Thursday, March 27, 2008

Over Engineering

Starting a new software project is hard. First, you hope that your project gets to a finished state. Second, you have to decide on the technology. Java or Python? OpenGL or SDL? (Don’t worry if you don’t know what those acronyms mean, I don’t. All I know is that they are graphic libraries.) And finally, you have to make a ton of hard software design choices about the architecture that will haunt you throughout the development cycle.

The last choice is where I am struggling right now. I can’t see the whole project in my head. I’m trying to be agile and only program what I immediately need. MTG Forge 1.0 did help me see many aspects of the overall design that I did well and those that need improvement. MTG Forge was written before planeswalkers but it was flexible enough to incorporate them. (Although the program presumes your opponent will only have one planeswalker in play.) The file “cards.txt” was extremely useful for adding creatures with keywords like flying and haste. The “Generate Deck” option was a great success and I hardly ever use the deck editor any more. If I want to exercise my deck building skills I use the sealed deck option.

It is dangerous to talk about one’s weaknesses, since they usually outnumber the positive, but I’ll give it a shot anyways. People’s number one complaint about MTG Forge was the user interface and I understand where people are coming from. Personally MTG Forge’s biggest weakness was my cut-and-paste mentality when it came to programming cards. The amount of redundant card code is enormous. I plan to use the Factory pattern in order to centralize code like “choosing a target player” and “dealing damage to a creature.” In the back of my mind are hard cards like Searing Meditation (when you gain life you can pay 2 and deal 2 damage to a creature or player). Cards like that can only be programmed if all of the gain life code is in one place. (A better solution might be to observe a change in your life points instead of adding Searing Mediation to the life gain code.)

So what does all of this have to do with over engineering? Well you try to make really, really good design decisions in the beginning, so you don’t regret it later. I may never actually program Searing Meditation, but I want that level of flexibility. The best way to keep things flexible is to make each component only dependent on itself. The main parts of MTG Forge 2.0 will be Card (all card code will be handled here and could be used in other Magic projects), GUI (the user interface will be totally separate), Input (it handles all of the mouse actions like choosing targets), and the Engine (does things like lets a user draw a card, determines the winner or loser, and checks for creature damage).

I’m going to tell on myself, but my worst offense is probably global variables. They keep track of all player zones and life totals. (Everything that begins with AllZone is a global variable.) They are also cause MTG Forge to get slow after a few games since the stack of all the method calls keeps getting longer and longer. The Engine part of MTG Forge will replace the need for any global variables.

Hopefully I haven’t been too long. –Forge

Monday, March 24, 2008

MTG Forge - Java Version

I wasn't sure how many people were interested in the Java version, but here it is. This a zipped jar file that runs on Windows, Mac, Linux, or anything else that runs Java. Currently you can't draft in this version or the regular version of MTG Forge, I must have made a mistake somewhere. Just unzip everything a directory and execute the file "java -jar run-forge.jar"

MTG Forge Java Version - Download

Wizards is Trying to Kill Me

Yes, the tagline is totally outrageous and false, like all good taglines. :) Checkout Beseech the Queen, a new Shadamoor card. That is some funky mana. I assume it means “You can pay BBB or 2BB or 4B or 6”. This has to be correct or very close since Mark Rosewater (head Wizard card designer) mentioned that the converted mana cost is 6. What this means to me, is more programming and more headaches, aka Wizards is trying to kill me. (By the way that sounds like a bad Dungeons and Dragons dream.)

A few weeks ago, while waiting for a job interview I sketched out an idea to program hybrid mana costs, introduced in Ravnica. And while I didn’t get the job, I did come up with a pretty nifty solution. Thankfully with a little bit of tweaking, it worked. I’m not sure exactly how to implement this new mana cost, but maybe something will come to me. If not, I’ll just code, test, debug, and repeat until finished. Hopefully it will only take me 1 hour, but maybe I’m just blowing my own horn.

Currently the mana cost is just a string. A string is a sequence of letters like “I am a string”. All text that you see on the screen is a string. This new mana, along with split cards, make any operations like finding the converted mana cost more difficult. The solution is to replace the string mana cost with a class that represents the mana cost.

A class is a collection of operations, called methods, that act on the same data. A number class would have methods add and subtract. The mana cost class should have methods like getConvertedCost and getCardColor. The card’s color is important and is usually determined by the mana cost, some exceptions are Pact of Negation and Ancestral Vision. The mana class could also have the methods addToCost and reduceCost for cards like Thorn of Amethyst (Noncreature spells cost 1 more to play) and Cloud Key (Spells you play of the chosen type [Creature, Instant, etc...] cost 1 less to play).

Monday, March 17, 2008

StarCityGames

My program got mentioned on StarCityGames. The articles says

The other problem is the woeful AI. Frankly, in all of the games I have played with Forge, I have only lost one, once, to mana screw. I have never lost to the AI.
But he also ends the article saying,
Of all of these programs, I have the highest hopes for Forge, but it will still take some work. Like I said, it is updated regularly. I am writing this on Wednesday, February 27, and the last update was yesterday. He is supposedly working on MTG Forge 2.0, with a new engine, so we will see how things go.
I guess I have to take the good with the bad, lol. At least he didn't mention the gui. :)

New Version

I’ve fixed a few errors and added 6 new cards. The total number of cards in now a whopping 461!!! You can now resize the window, a caring reader donated this code. I fixed a random EOT error and Immaculate Magistrate used to occasionally target lands. The AI for Kiki-Jiki can now copy one of your creatures, before the computer would just copy one of the creatures that he already owned. I also fixed the combat code when you are attacking into a bigger creature with trample, you will not receive trample damage. Trample only works when attacking, who knew?

The 6 cards I added where pretty random. I am still very limited in the kinds of cards that I can program and most Lorwyn and Morningtide cards are very complicated. Kamahl, Pit Fighter is a big guy with a nice ability that the computer can effectively use. Empty the Warrens is my first storm card that is interesting in a variety of situations. Serra Avatar is an unusual creature, since she can be a 20/20. She is also quite valuable and still runs at least $15 in real life. The man-lands Faerie Conclave, Forbidding Watchtower, and Treetop Village where pretty easy to program so I added them.

People have asked me what decks the computer can use effectively, so I’ve added 5 constructed decks that should be challenging to play against. The black deck is called “black-good-AI” and has Pestilence and lots of Terror effects. The blue one has 8 ways to steal creatures, 4 Control Magic and 4 Sower of Temptation, and 7 bounce effects with Repulse and Man-o-War. The green deck has a good mana curve along with game winning cards like Epic Proportions and Garruk Wildspeaker.

The white deck has 4 Wrath of Gods, 4 Oblivion Rings, 4 Sunlances, and 4 Serra Avengers to beat you down with. (Maybe the Wrath of Gods should be Swords to Plowshares?) The land counts are low because the computer has his land automatically smoothed so he only draws land when he needs to. This smoothing helps the computer be more competitive by increasing his chances of top-decking something good.

Download Windows Installer – MTG Forge 03-2008
(To save the decks that you created, keep a copy of the file “all-decks2”.)

ps.
I had Empty the Warrens working correctly, then I fixed Serra Avenger and that broke Empty the Warrens. It will probably produce too many tokens.

Tuesday, March 11, 2008

Shadowmoor

Don't ask me where MTG Salvation got this picture, but behold a new Shadowmoor card. And check out this really weird spoiler on Wizards website, card pictures but no text, here.

Chewy Gui

In case you don’t know how to pronounce Gui (goo-ey) it rhymes with chewy. (Gui stands for graphic user interface. Windows and all Windows programs are Gui. DOS and command prompts are not Gui.)

Gui’s are hard to write for many reasons. One, despite the power of modern computers, displaying a simple image on the screen and allowing the user to interact with it is very difficult. How many free video games do you play for more than 5 minutes? (Well not counting MTG Forge of course, ha.) Two, writing a gui that people can understand and use is magnitudes harder than point number one. I can pick up and play Mario 3 which is about 15 years old because the gui is so easy to understand. Writing an intuitive interface like Mario can make you famously wealthy for life, but I doubt Mario 3 was written by less than 50 dedicated people. For a really bad gui just look at Word 2007, they played hide-and-seek with the toolbar and I find it unusable.

So what does all this gui talk have to do with MTG Forge, well MTG Forge has a gui doesn’t it? Admittedly it is a basic gui that was built with regular components like buttons, panels, and text areas. I have been experimenting with a more sophisticated gui for MTG Forge 2.0 but I am getting frustrated. I have a working knowledge of Python, although there are many deeper topics that I don’t quite understand yet. For all you programmers, my fingers have finally gotten used to _not_ adding a semicolon at the end of every line. You don’t really know a programming language until you can program blindfolded, it has to be in your fingers.

But the frustrating part is also learning about the graphical library that will let me draw pictures on the screen. Learning Python was manageable since I previously mastered Java and I am familiar with the basic fundamentals of programming: variables, loops, if statements. Learning a graphical library is like trying to learn another language, but I’m not familiar with the basic language.

I am getting sidetracked by trying to write a better gui but I really want to focus on adding Lorwyn and Morningtide cards, so I am thinking about using my previous Java gui for MTG Forge 2.0. But you may ask, “I thought you were using Python and not Java?” Well thanks to Jython, I can compile Python into Java. Unlike the current version of MTG Forge, I plan to program the gui completely separate from the rest of the code in case some enterprising programmer wants to write a better one. (In the current version of MTG Forge, I accidentally let some non-gui code slip into the gui which would make writing a different gui much harder.) In version 2.0, I want to be able to change the gui with just one line of code.

By the way, I try to re-read my posts to catch any grammatical mistakes, but I’m sure I miss a few. Every time I start a sentence with “but”, I always think back to my high school English class (no “buts” allowed). --Forge

Friday, March 7, 2008

Delaying Glorious Anthem

Glorious Anthem (GA) is a tough card to program and when I first started MTG Forge I had no idea if I could ever code it. Think for a second and tell me what is the difference between cards like Shock and GA? Hopefully most of you realize that GA’s effect stays around, while Shock is just a one-shot.

Thankfully I was able to implement GA with minimal fuss. GameAction already had a method called checkStateEffects() which sent creatures to the graveyard if they had enough damage and checked for legendary permanents, so I just added GA to the code. GA is actually implemented in GameActionUtil which also does upkeep effects like Juzam Djinn. There are only 17 cards that do state effects, cards like Soul Warden and Nightmare. I recently programmed Serra Avatar (power and toughness are each equal to your life total) which was a relatively simple.

And finally, design a flexible system but put off what you don’t know how to do. I didn’t know how to program GA but I didn’t sweat it. There were a hundred other things that I wanted to program first, like Shock and creature combat, and I couldn’t let myself be bogged down in details.

I thought about showing you the code for GA, but Serra Avatar is much easier to understand (and it won’t make your eyes glaze over). AllZone is a global variable that keeps track of all player zones and life totals.


//taken from GameActionUtil
//get all creatures
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

Wednesday, March 5, 2008

Working Python Code

The previous Python code just had the source code but none of the GUI components that were needed (pictures, fonts). So now this is the working, but still very alpha, source code. Run “GuiMain” in the gui directory. All you can do is move 3 card images around. You cannot move the card outside of its current zone. The three colored region on the screen represent your hand, your play area and the computer’s play area.

When you move the card it “bleeds” (look at the picture to see what I mean). This behavior is on purpose although it may seem like a bug. First a little background. For one, I don’t know anything about graphics programming other than the basic xy coordinate plane. (I actually did teach a few months of geometry, go math!!) Two, I thought I could just draw the whole screen 15 times a second but my computer isn’t that fast. So my compromise is that I only redraw the card that is moving and I don’t redraw everything.

In order to correct the bleeding effect, I should redraw the background where the card was previously at. That is easier said than done because I don’t know anything about graphics programming. Basically I feel like I am building my first dog house. I know the tools, hammer, nails, wood but I’m not sure how to best use them. I know the end result that I want, but I don’t know the exact steps.

This code requires Python and Pyglet
Download Source Code

Monday, March 3, 2008

Python

Everyone seems interested in my new Python version so here it is. No one every seemed too interested in my Java source code. Maybe Python is more fun?

The GUI requires Pyglet but all you can do is to move a card. And you have to make sure there is a file called "card.jpg" in the gui directory. The only thing that really works is ManaCost, everything else is in its very early stages. The Card class holds one or more SpellAbility classes. Each SpellAbility has a resolve() method that is called when it is popped off the stack and resolves.

Python Source Code:www.mediafire.com/?rjnzzdvnmy1
Pyglet Graphics Library:pyglet.org