Monday, June 30, 2008

MTG Forge – Sliver Edition

This is new release of MTG Forge with 14 news cards. Most of the new cards are slivers. Sliver Legion now works and I’ve added Joiner Adept (Lands you control have "tap: Add one mana of any color to your mana pool.") which will help out any 5 color green decks. The sliver code isn’t perfect and your slivers won’t affect the computer’s slivers. The sliver code was taken from Glorious Anthem.

There are also a few other small bug fixes. Sprout Swarm is now an Instant. The Deck Editor now sorts different, so all “Creature – Sliver” cards will be grouped together. The Deck Editor sorts by the card type line, so basic lands will be under “B” since their type line reads “Basic Land – Mountain”. Fixed Man-o'-War, it incorrectly bounced a creature to its controller’s hand instead of its owner’s hand.

Fixed Liliana Vess, she sets the card’s controller correctly but there still might be a few bugs with creatures with “come into play” abilities. Limited changelings functionality, Changelings are slivers but they aren’t goblins or any other creatures types. When clicking on planeswalkers and other cards, you can now cancel.

I try to improve MTG Forge and most of these changes were suggested by you, the reader. And although I can’t implement every suggestion, I do what I can.

Windows Installer
Java jar for Mac, Linux, etc…

(To save your decks, copy the file “all-decks2”)
(Java source code is included)

p.s. I keep typing “silver” instead of “sliver”, arg!!!

Wednesday, June 25, 2008

Static and Triggered Abilities

And here is more bad news, triggered abilities are just as hard to program as static ones. Triggered abilities begin with the words “when”, “whenever” or “at”. Hypnotic Specter says, “Whenever Hypnotic Specter deals damage to an opponent, that player discards a card at random.”

The bad news is the card sets like Shadowmoor have a ton of static and triggered abilities, which makes them fun to play with but hard to program. Remember: activated abilities easy, static and triggered hard.

Since MTG Forge doesn’t support events, triggered abilities are implemented as static abilities. MTG Forge only has a few cards with triggered abilities: Baru, Fist of Krosa, Reach of Branches, Soul Warden, and its color swapped twin Essence Warden.

For those intrepid readers who want to see the Java code for static abilities, just check out the class GameActionUtil and the method executeCardStateEffects(). This is a helper method that GameAction checkStateEffects() calls. checkStateEffects() is called every time the game’s state should be checked, which is a lot. But a word of warning GameActionUtil looks very weird. I combined highly advanced Java with insomnia at 2am and this is what I came up with.

Basically each card has its own class and all of the classes are executed by a single method, executeCardStateEffects(). The good news is that all of the code for each card is together, even though the overall code is messy.

Honestly I would have a very hard time writing this code again from scratch, but it works so I don’t mess with it. Essentially all of the cards are just variations on my original Glorious Anthem code which I ingloriously cut-and-pasted multiple times.
I love throwing code at you, even though I know that everybody isn’t a programmer. The code for Serra Avatar is the shortest and easiest to understand. Serra Avatar says that its power and toughness are equal to your life total.
private static Command Serra_Avatar = new Command()
{

public void execute()
{
CardList list = new CardList();
list.addAll(AllZone.Human_Play.getCards());

list.addAll(AllZone.Computer_Play.getCards());

list = list.getName("Serra Avatar");

for(int i = 0; i < list.size(); i++)
{
Card card = list.get(i);
int n = AllZone.GameAction.getPlayerLife(card.getController()).getLife();

card.setAttack(n);
card.setDefense(n);
}//for

}//execute

};//Serra Avatar

Monday, June 23, 2008

Coding Shadowmoor

I rare look from inside Wizards. One man's tale of coding Shadowmoor for Magic Online.

Coding Shadowmoor

Static Abilities

A friend asked me to program some slivers, so I took a deep breath and tried to figure out which slivers were the easiest to add. (If you have never gotten the change to crush a foe with slivers, you haven’t played Magic long enough.) This got me thinking about static abilities.

Magic’s static abilities are the hardest effects to program. Card with static abilities include Glorious Anthem (your creatures get +1/+1) and Nightmare (power and toughness are equal to the number of swamps you control.)

There are relatively few cards in MTG Forge that have static abilities, because they are hard to code. Activated abilities are almost trivial when compared to static. Examples of activated abilities include Elvish Piper (tap: put a creature from your hand into play) and Rootwalla (1G: Rootwalla gets +2/+2 until end of turn), all activated abilities have a colon “:”.

Let me try to explain why static abilities are so complicated. Glorious Anthem gives +1/+1 to all your creatures. So this means Anthem gives +1/+1 to all your current creatures and well as any future creatures you play. The “future” part of that sentence is what makes Anthem problematic. Otherwise Anthem would just be similar to Warrior's Honor, “Creatures you control get +1/+1 until end of turn.” Warrior’s Honor effect is done after it resolves, while Glorious Anthem’s effect stays around.

MTG Forge was written without any static abilities and after brainstorming I figured out a way to program Glorious Anthem (I really wanted to use that card) and Nightmare. But creatures like Nightmare have a problem, they can’t be pumped up by effects like Giant Growth.

The difficulty is that Magic applies effects in layers, while MTG Forge does not. MTG Forge uses a number (int) to represent a creature’s power. Thankfully the layering problem doesn’t crop up very often, but when it does it will surprise you. The only solution is to implement a complicated layering system, so until that happens just don’t target Nightmare with Giant Growth :+)

Wednesday, June 18, 2008

Confessions of Blogger

I wanted to talk a little about the history of this blog. I started this blog about 14 months ago and I remember being disappointed when I was only getting 5 hits a day. Nowadays I’m up to 100+ hits a day which is phenomenal. I remember wondering should I stop blogging, since no one was reading it.
I’m probably the worst blogger ever. I don’t read any blogs and I write about the boring subject of computer programming, although I try to spice it up by talking about Magic, lol. Most blogs talk about too many subjects or at worst, just random thoughts. I try to make this blog very focused, just programming and Magic. A few “miracle” articles combine both topics, but sometimes I’ll write about just programming or Magic. Hopefully my programming articles are still interesting to my non-coding readers. I think programming is fun, so I try to make it sound fun.

This blog is also an extension of my program MTG Forge. It is a “behind the scenes” about programming Magic cards and artificial intelligence. MTG Forge has gotten people working on their own projects, which was one of my goals. Part of me feels like a “crazy scientist” that writes this program in his kitchen (I don’t have a basement) and then unleashes it on the world.

I like giving away the source code even though I know it isn’t really usable to anyone else. Trying to modify some else’s code is like trying to add a chapter into a book that is already written, you can do it, but it is very hard.

Hopefully small pieces of my code, like the Card and SpellAbility classes, make sense. So you don’t have to understand the whole project, you can just look at some of the pieces and use them in your own project if you want to. And if you are very brave you can look at CardFactory. CardFactory is so horrible, weird, and messy that it is almost beautiful.

In a way CardFactory is my masterpiece. A normal piece of code, called a “method”, is 5 to 30 lines long. CardFactory has a method that is more than 10,000 lines long. CardFactory actually creates all the cards, so a lot of “voodoo” happens there. Each planeswalker is about 200 lines of code. That is why MTG Forge currently only has 3 out of 5 planeswalkers, they are a ton of work.

So in closing, I wanted to thank you (the readers) for making this blog successful. At last count MTG Forge has been downloaded more than 10,000 times, but this number is 6 months old. (I don’t have a way to track the number of times my program is downloaded.) And hopefully one day I’ll build an AI (artificial intelligence) that is unbeatable ;)

Monday, June 16, 2008

Video Game Programming

Recently I’ve talked a great deal about programming and I hope it’s not too boring for all you non-programmers. The reason I have coding on my mind is because I’m working on AI Mage (MTG Forge version 2). The main difference between the current version 1 and 2 is the user interface.

Version 2 will have a fully graphic, video game type interface. Cards will be drawn on the screen showing their attack and damage. You will also be able to rearrange cards like in Shandalar. This is an example of how it looks and although you can’t do play any cards yet, it still looks pretty good.
The bottom area is your hand, the middle your play area, and the top is the computer’s play area cards. The colors were pretty random and can be changed later. On the left you have all your important information, all your mana symbols, the number of cards in your library, graveyard, and removed from play. I even included a poison counter for the future. All the icon pictures were shameless stolen from a private version of Magic, Incantus.

The good news is that the user interface is pretty much finished. Everything you see works. If you move the mouse, the large “card detail” picture is updated. All the icons on the left are connected to the rules engine.

I have all the dialogs working. Dialogs are those boxes that popup and ask, “Do you want to erase that file?” click yes or no. You can even stop at ANY phase. Do you want to stop at end of combat, go for it. Next on my to do list is to cycle through all of the phases, because Magic is essentially about changing phases and moving cards.

Wednesday, June 11, 2008

Programming Hybrid Mana 2

I could have gone the easy route and not programmed hybrid mana at all. I could have just let the user select which cost they would play. Like if the card cost (G/W) the user would select G or W and then tap the appriopriate land.

My previous pseudocode looks correct but there were a still a few errors I had to fix. First, you have to internally reverse the mana cost because otherwise the colorless part will “eat” the colored mana the rest of the cost needs.

For example, 2WW needs to be reversed to WW2. So when you add mana, the white mana part is checked first. In other words, when you pay W toward the cost 2WW the result should be 2W not 1WW. And when you display the cost to the user, the output has to be reversed again.

Below I will example how to use my Python code that handles mana costs. Some examples of valid mana costs are
2
1 W
X U
GW
RB RB
2/G 2/G 2/G

Each part is separated with a space, which just makes it easier to split up. GW means you can pay G or W and 2/G means that you can pay either 2 or G. The class ManaCost is the class that you will be using. ManaCost is low level and a graphical component is supposed to use ManaCost and allow the user to select the appropriate land or mana. The graphical component would also tap the land if the mana was needed. An example of how to use ManaCost is given below.

c = ManaCost()
c.setManaCost(“2 W W”)
c.isNeeded(“W”) #true
c.addMana(“W”)
print c.toString() #2 W
c.addMana(“W”)
c.addMana(“U”)
c.addMana(“U”)
print c.isPaid() #true

Feel free to use this in your own projects. This has been tested thoroughly comes with a wide variety of test cases: TestManaCost and TestManaPart.

Download Python Code

Monday, June 9, 2008

Super Rares

Just in case you missed it, starting with the card set Shards of Alara there will be "mythic rares". One mythic rare for every 8 booster packs. The card picture is a preview card of a mythic rare planeswalker in Shards of Alara.

The Year of Living Changerously - by Mark Rosewater

And checkout some of the card art from Eventide.

Programming Hybrid Mana

I have talked about programming normal mana costs (2WW), but Shadowmoor features new, unusual costs like (2/B), you may pay 2 of any mana or B. Shadowmoor also brings back hybrid costs like (G/B), you may pay G or B. The reason I mention all of this, is because these new costs mean more programming (which isn’t necessarily a bad thing).

I have done some additional programming and the good news is that I can process all mana costs that Wizards has ever printed, except for the weird snow mana that Coldsnap introduced. I wanted to talk about the logic that my code uses.

Everything came together when I started thinking about dividing the mana cost into smaller parts. So “2WW” would have the parts: 2, W, W. Each individual part would know what kind of mana it needed. So the object ManaPart would have a only a few methods as shown below. The method needsMana() returns true if that mana is needed. The object ManaPart greatly simplifies the task of programming X and hybrid costs.

ManaPart
addMana(String mana)
needsMana(String) : boolean
isPaid() : boolean
toString() : String

But wait!! I haven’t shown you the magic yet. Each ManaPart object also has a method named correctManaPart(String part) that returns either true or false. This method answers the question “Does this object handle this kind of mana?” So the ManaPart that handles X costs always handles the X regardless of the rest of the cost. So I could easily handle snow mana, because it would involve just adding a new ManaPart.

I’m going to try to describe the pseudocode below. TotalManaCost is given a cost like 2WW creates the correct ManaPart for each part. In this example, the parts are “2”, “W”, and “W” so three ManaPart objects are created.
TotalManaCost.setCost(String cost):

#first divide “2 W W”, into 2, W, W
split cost into parts
for p in parts:
for m in (all manaParts):
if m.correctCost(p)
totalCost.add(create ManaPart(p))


method addMana(String mana):
#loop through to see which ManaPart needs mana
#manaPart is a list (array)
for z in manaPart:
if z.isNeeded(mana):
z.addMana(mana)
return
I know that reading the pseudo-code helps understand the overall process but seeing the actual code really helps. The method for addMana() was pasted from the actual source code.

Download Python Code – I’ll explain it in more detail in my next post.

Friday, June 6, 2008

Shandalar Patch

This is the biggest patch that I could find for Shandalar and it adds 200+ cards and allows you to mulligan. I got this patch from http://www.manalink.de

ManaLink 2.0

Wednesday, June 4, 2008

Magic For Beginners

I added a few beginner decks for those people who are learning Magic for the first time. Basically the decks are named like "0-learn-red-level-1" which means this is red, level 1 deck. Level 1 is only creatures with no abilities and then level 2 adds spells and so on. Hopefully this will help a few people.

Windows Download

Adventures in Programming: Double Clicking

While working on the next version of MTG Forge, which will be called “AI Mage”, I encountered a little snafu. The graphic library (PyGame) which also handles all events doesn’t seem to have a “double click” event. While double-clicking is common when using Windows, I guess it is rare when it comes to videogames. So I was left with a problem, how could I simulate double-clicking? I couldn’t just use single-clicking since I allow the user to rearrange the cards. So what was I going to do?

I don’t know if this solution is optimal or not, but I substituted right-clicking instead. So you use the left mouse button to move a card and the right button to play the card. Hopefully this will eliminate the nuisance of accidentally playing a card, which is very common with Magic Online.

I could have tried to devise a way to measure the time between clicks, so that I could turn a single click into a double click but I wanted a simple solution. On a side note, I was hoping that AI Mage could run on a Macintosh, but I don’t know if they use a two button mouse. I know the old Macs used only a one button mouse.

The joys of programming, oh how I love (and sometimes hate) thee. If my brain can concentrate well enough, I actually spend my time programming instead of playing videogames.

Monday, June 2, 2008

More Shandalar

MTG Forge was written because I enjoyed Shandalar so much. Shandalar being the 1998 MicroProse version of Magic: The Gathering called “Duels of the Planeswalkers” which also had an expansion called “Spells of the Ancients.” It is amazing that even 10 years ago the word “planeswalker” was around but it was not made into a card until recently. Anyways, Shandalar was great fun and featured constructed (all the cards), sealed, and a basic RPG.

After playing many days of constructed, I was beginning to get bored so I hesitantly tried the sealed deck option. As it turned out, it was even better than constructed. Although Shandalar’s sealed card pool was pretty abysmal, I always seemed to have more red cards, it was still new and exciting. MTG Forge stemmed from the simple idea that I wanted to add and remove cards from the sealed card pool.

I knew that trying to program Magic was a big task and that I probably wouldn’t ever be able to program a whole block, so MTG Forge was designed primarily for sealed games. Since sealed games usually have lots of creatures, I figured that programming the AI to use creatures would be easier than spells, since many spells depend on the board situation like Wrath of God.

In many ways Shandalar is still the gold standard. The game board and card presentation is clear and easy to understand. Selecting your phase stops is very simple. And the AI does occasionally surprise me. Shandalar’s AI seems to be able to do simple combos although it randomly shoots itself in the foot by playing Weakness (enchant creature -2/-1) on its own creature. Overall Shandalar’s AI is probably better than MTG Forge’s, but Forge does better at creature combat. I don’t necessarily take this as a putdown since Shandalar had more manpower.

There have been a few unofficial updates to Shandalar but they tend to be pretty random. I found a few patches at http://www.manalink.de but nothing is really organized. You can download Shandalar from here, but you will have to use BitTorrent. Enjoy.