Monday, December 27, 2010

Other Offline TCGs

I hope everyone had a great Christmas.  Instead of talking about Forge's great features and its great gameplay and its great AI and its great new cards, I figured I would mention a few other trading card games (TCG) that you can play offline against the AI.  Please keep in mind that none of these games are as good as Forge but they try :-)

Blue Moon is a traditional card game where you choose from one of several decks and then play against the AI.  There are 8 decks that you can use and play against.  The AI is very sophisticated and uses neural networks. (Download links are at the bottom of the page.)


Another traditional card game (from the same programmer) is Race for the Galaxy.  Instead of having individual decks, both player draw from the same deck.  (Download links are at the bottom of the page.)

Both of these games have a nice user interface and a challenging AI opponent.  The rules for the two card games are very complicated and while I have mastered the rules of Magic, I have yet to master the rules for Blue Moon or Race for the Galaxy.  It's not that the rules are bad but they have many details like Magic.

While this next program isn't a card game, it has many related elements.  Carcassonne is a board game where you draw a game piece and build town and roads.  The rules are very simple while mastering those rules is challenging.

After you draw a random board piece you have to add it to the current map while keeping all roads and cities connected, which restricts you from adding a piece anywhere that you want to.  After you place your map piece, you may put a settler on that piece.  The program has a good AI and lets you play against one or more AI opponents.  The programmer also lets you play against other people on the Internet and writing network code is never easy.

I have yet to win a game against the AI even though I enjoyed the fun aspects of creating a new map.  I find myself wanting to be able to play a shorter game against the AI so I can evaluate my progress quicker.  Playing a game that uses all 60 pieces can be long, especially if you are losing.

All three of these games are quite good and will consume many hours.  Please tell me if you happen to beat the AI in any of these three games.

Blue Moon
Windows Executable
GTK Library (required) 
Rules
Programmer Homepage

Race for the Galaxy
Windows Executable
Rules
Programmer Homepage - Also has a Mac OS X version that you can download.

Carcassonne
JCloisterZone - requires Java
Programmer Homepage

Keep on forging (my new catch phrase),
mtgrares

Monday, December 20, 2010

Odds and Ends

I wanted to name this column “Todds and Tends” but I wasn’t sure that anybody would get it.  When I post something I try to have a specific topic in mind but today I’m going to wonder a little bit and talk about various magically related subjects.

Forge continues to be developed by about 5 serious programmers who tend to spend many hours a week programming new features.  One of the areas of improvement is the attacking and blocking code.  They have been working on improving this important piece of code.  Considering all of the combat modifers in Magic like first strike, deathtouch, regeneration and planewalkers the AI combat code has to take into account a lot of information.  Improving this area of the AI is very tough because the AI cannot “see” activated abilities and treats insanely, powerful creatures like Royal Assassin as generic 1/1 creatures.

I’ve been playing Magarena all week and it has been great.  Magarena has a great AI and it will make some very good tactical decisions.  The other good thing is that the AI is very fast and I only have to wait a few seconds, even though my computer is ancient.  Magarena has 450 cards but all of the cards are game winners, no stupid 2/2 for 3 mana.  The AI can be very aggressive, one time it killed my 8/8 with 2 spells and another time he totally devastated me with a trampling 24/24.

I’m thinking about adding a quest mode to Magarena because I think it would be really fun.  I’ve really enjoyed using randomly generated decks but the quest mode provides some real depth and is very engaging (you don’t want to quit).  Magarena happens to be written in Java, so at least I have a chance of modifying the source code.  I’ve written about Magarena previously here.

I’m not sure how many of you know about stackoverflow.com, which is a question and answer website that only deals with computer programming.  There is a new-ish website called draw3cards.com that deals with Magic questions.  Draw3cards isn’t a very “serious” website but it does let people ask and answer a variety of questions like: What is the least printed magic card? and Are there any colored lands? (only Dryad Arbor which is green.)  I even asked my own question, “Is there a downside to being able to play any card as a land?” I didn't know about the Dakkon Blackblade Magic Online avatar that lets you play any card as a land.  Vanguard seems to have some great avatars like Momir Vig which have spawned whole new formats.

The card art is from  Jace vs. Chandra which are Japanese duel decks with new manga art for the planeswalkers.  You can read the official announcement here.

Keep on tapping,
mtgrares

p.s.
This is a little bit random but just sit back and enjoy something: look outside, tell a joke, or just say ‘hi’ to the people sitting next to you.  I love computers, the internet, and always being connected but it can be very stressful.  And truthfully you don’t need to read the latest gossip or read about the latest technology or read somebodies twitter feed (I’ve never used twitter myself).  Try to relax for a whole 2 minutes. :+)


Thursday, December 16, 2010

Duels of the Planeswalkers - Adding Cards and Modding

The new PC game can be modded so extra cards can be added.  I don’t know anything about it myself but the SlightlyMagic.net forum has tons of info.  The forum seems to have quite a following with 105 topics and 1,413 posts.

Monday, December 13, 2010

Understand Changes.txt

Every version of Forge comes with the file “changes.txt” which describes some of the changes.  Unfortunately changes.txt is extremely brief and full of jargon.  Today I thought I would decode changes.txt and describe some of the changes in common English. 

First a little background info.  In Forge cards can be encoded in one of two ways: Java or scripted.  A Java card is in regular Java and you can see everything that is going on.  A scripted card uses only text.  Scripting is one of the reasons that Forge has so many cards, scripting saves a ton of time versus coding in Java.  The “script” for Shock looks like this A:SP$DealDamage | Cost$ R | Tgt$ TgtCP | NumDmg$ 2 | SpellDescription$ Shock deals 2 damage to target creature or player.

From changes.txt, “Rob added code that can display different images for cards that are included in multiple sets.”  Going back to Shock, which is in /res/cardsfolder/shock.txt, I can see 8 different card pictures that are downloaded for Shock.  Unfortunately, as of right now, you can’t specify which Shock card picture you would like.  (On a side note, I didn’t deal with “set of cards” in Forge because I had a hard enough time getting stuff working.  As Forge has gotten bigger, the issue of “what set is this card in?” becomes more important.)

“Sol added code that gives us and the computer access to the other phases that were missing in earlier versions.”  This change is pretty easy to understand, now you have access to all of the phases in Magic, woot!

“We are currently in the process of creating a new AbilityFactory system which is designed to replace many of the scripted keywords.”  The scripting code has become messy so they are refactoring (moving) the code around in order to make it cleaner.  Cleaner code is much easier to deal with, so you don’t feel like pulling your hair out.

“Moved majority of discard code to Player classes.”  Initially Forge didn’t have a Player class.  A player was specified using only a string, “Human” or “Computer”.  This is why Forge sometimes says “Human draws a card” instead of “You draw a card”.  Since Forge has grown, creating a class to represent a player has become more important.  Instead of the discard code being separate, now it is part of the player class.  I presume you, the human player, and the computer have different player subclasses but I’m not sure.

“Fixed null-pointer error for non-Targeted Fetch cards played by the AI.”  As a Magic player you know that your brain automatically looks for the word “target”.  Many cards aren’t targeted and they have to be handled a little differently.  Apparently the AI caused an error when it used certain types of cards.  (Null errors are the bane of programming.  Every programmer has encountered them zillions of times.)

“Convert Library of Alexandria, SearchMerc/Rebel to use abCost and Target.”  Many of the changes involve removing the Java code for a card and replacing it with scripting, which is a good thing because this actually reduces the number of lines of code.  This is the script for Library of Alexandria

A:AB$Draw | Cost$ T | NumCards$ 1 | ActivatingCardsInHand$ 7 | SpellDescription$ Draw a card. Activate this ability only if you have exactly seven cards in hand.


“Mishra's Factory now uses AF_Pump.”  Java code replaced by scripting again.  Mishra's Factory lets you pump up another Mishra's Factory that has become a 2/2, so that ability is now scripted.

A:AB$Pump | Cost$ T | ValidTgts$ Creature.Assembly-Worker | NumAtt$ +1 | NumDef$ +1 | SpellDescription$ Target Assembly-Worker creature gets +1/+1 until end of turn. | TgtPrompt$ Select target Assembly-Worker creature.

“Goldmeadow Lookout, Oran-Rief, Magosi updated to use Ability_Activated.”  Before Goldmeadow Lookout didn’t use the Java object Ability_Activated and now it does.  Many times I would cut and paste code instead of making objects and central points of control.

“Fix for cards still using Input_NoCost_TapAbility.java. This same fix may be needed for other Inputs.”  Activated abilities have a ton of different costs and some activated abilities costs only tap a card.  Input is how Forge processes all mouse input.  Input uses the State Pattern.

“Modular Targeting now should happen as the Modular creature goes to the grave instead of on Resolution. This fixes the Input issue that was occurring due to the Phase changes.”  Some of the fixes in Forge are regular rules issues.  You may think you understand the rules but you have to be a regular rules lawyer or a DCI Judge in order to never make a mistake.

My biggest rules mistake was thinking that there were two battlefield zones (one of your and one for your opponent) and that Elvish Piper was targeted.  Obviously Elvish Piper isn’t targeted but I was used to the player always making a decision before the ability went on the stack, instead of when the ability resolved.

If you have any other questions about changes.txt, just ask on the forum.

Keep on tapping,
mtgrares

Monday, December 6, 2010

New Version

The only time that I use Windows awful calculator (calc.exe) is to figure out how many cards have been added to Forge.  The good news is MANY cards have been added, specifically 1,339 new cards and no that isn't a typo.  Forge now supports an outrageous 5,441 cards which is enough cards to keep (most) people happy for the rest of their life.

The reason for the huge number of new cards is twofold.  One, it has been about a month and a half since I posted a new version of Forge.  And two, Forge went through a major change in the codebase (source code) which is good because Forge can support more cards.  Thanks to everybody that helped with this difficult conversion.  The additional good news is that a large number of bugs have also been stamped out of existence.  (Forge still has a number of bugs but the number is far smaller.)

Chris H (from the forum) mentioned quite a few changes and here are a few of them.  (I'm quoting from Chris so I'm not stealing, its borrowing.  Hey, if he ever starts up a blog, he can "borrow" from me, ha.)  For a complete list of changes, see "changes.txt"

Rob Cashwalker added code that can display different images for cards that are included in multiple sets. There's a Image Base folder, by default {ForgeFolder}/res/pics, but you can change that in the forge.properties file. Under that, the three-letter set code as a folder, then the card_name.jpg. I'm giving some thought to also try the alternate mostly 2-letter code that the HQ archives use, if the other doesn't exist. Now supports pictures using MWS filenames and folders.  (mtgrares - For more details, post a question in the forums.)

Right now, there's no support for promo sets or duel decks. The primary impetus is to enhance the booster pack generation, (for draft and quest) with pictures being a somewhat secondary benefit.

Friar Sol added code that gives you and the computer access to the other phases that were missing in earlier versions. There is a pull down menu named "Phase Stop" that lets you turn off and on the various phase steps. The phase stop menu is available when using the new and the old GUI battlegrounds.  (mtgrares - Sounds good, many people have requested this feature.)

(Alright, back to mtgrares.)
OK, the good stuff, here are some of some of the unusual new cards that you can use.  Silent Arbiter (cost: 4, artifact creature, 1/5) which has "No more than one creature can attack each combat.  No more than one creature can block each combat." Scourglass (cost: 3WW, artifact) "tap, sacrifice Scourglass: Destroy all permanents except for artifacts and lands".  Platinum Emperion (cost: 8, artifact creature, 8/8) "You life total can't change.  You can't gain or lose life.  You can't pay any amount of life except 0".

And lastly, a card that will improve almost any deck, Pithing Needle. You probably own me 5 or 10 dollars since you don't have to buy a set of these yourself but I'll let it slide this time. :-)

On a side note, the decks that are named AI-something, means that the AI should be able to use the deck pretty well, since the AI has trouble using certain types of decks and cards.

Keep on tapping,
mtgrares

Link (11 MB) - Download Forge 11/30 version - The date 11/30 is when it was first released on the forum.

Card Pictures (150 MB) - Unzip these in your /res/pics/ directory.  These are the low quality (LQ) pictures. (This link has been fixed, sorry about the inconvenience.)

p.s. Magiccards.info is the bets place to view high-quality scans of Magic cards.  The card scans are much better than Gatherer.

--Many people helped with this version. A special thank you goes out to them:

Dennis Bergkamp
Rob Cashwalker
Friar Sol
Slapshot5
Sloth
Snacko
Hellfish
Zerker2000
Jeff Wadsworth
Silly Freak
PhoenixAvenger
Bladescape
Chris H

Thursday, December 2, 2010

Magarena - A Smart Magic AI

I just had to tell everybody about a new Magic program that I found.  It is called Magarena.  It has 900 cards and a very good AI.  The computer can (and will) play instants and abilities during combat and at end of turn.  I "researched" the program very thoroughly and I had a good time playing against such a smart opponent.  Some of the games lasted 20 or 25 turns because the game AI was so good.  In those close games I had no idea if I would win or lose.

Magarena has a very nice user interface and looks likes a real videogame.  The user interface is much more graphical than Forge and has an elegant wood background.  Magarena also has "undo" which lets you fix a mistake or try to sneak something else past the intelligent AI.  Undo is a great feature because it is universally used and understood.

Magarena uses min-max for the AI and is written in Java.  Feel free to post your comments about Magarena to the forum thread here.

Download - Magarena's Google Project page, runs on Windows, Mac, Linux

Requires Java

Monday, November 29, 2010

AI - Continuing saga

(Here is an article written by lazylockie, which is his username on the forums.  You may think this is a cop-out and that I'm extremely lazy and you would be correct on both accounts.  So without further ado...)

In this article I’ll talk about Forge – yeah, obviously – but more specifically about some aspects of Forge’s AI.

Why is the AI weak?
I think the main reason sometimes the AI is so weak is because it doesn’t interact the human on any other phase other Main. This limits a lot the card pool they can effectively use. We know the developers are working on this, but it’s a nice advantage that we players have against them.

For example stuff like Giant Growth, Basking Rootwalla and Sorceress Queen are usually the Achilles Tendon of AI. AI happily attacks with a White Knight onto your Basking Rootwalla and suddenly you’ve gained advantage on a situation that in real life wouldn’t have happened. Stalemates are more easily broken and often lead into human victory.


AI needs to be generic
How is your general behavior when playing with Jace, the Mind Sculptor? I assume it would be something like: If you’re not playing against burn or there’s no threat on opponent’s field, Brainstorm. This could be, in pseudo code – albeit probably codeable on Forge:

Jace, the Mind Sculptor behavior
if (there’s a “dangerous” creature on opponent’s field)
  -1 ability targeting that creature

if (loyalty == 1) OR (opponent has a basic land AND loyalty <= 3)
   +2 ability targeting opponent
else
   +0 ability //Brainstorm for card advantage

 The pseudocode above isn’t perfect, but practically covers all common sense functionality of Jace. However, as mtgrares (the author of this bog) already mentioned on past articles, designing an AI behavior for each card created is hard/confusing and even then it might not work as expected, since Magic involves interactions between many cards at same time.

Another example that is often seen is Baneslayer Angel. The little lady is almost auto-win on the hands of a human player if it connects, because common sense says that that gal must attack every turn, even when on board disadvantage, because it has evasion and lifelink. However, AI doesn’t comprehend that Baneslayer has a 10 point life swing, so in dire situations he’ll often leave it for blocking, when he could have attacked and won the battle.

Why the AI prefers simple decks
If there’s one thing that AI is good at is brute force. Anything that is big and cheap is often a good deal for AI. That’s why Affinity decks are so hard on the hands of AI, especially at early levels of Quest mode: big stuff like Myr Enforcer is free and the deck is pretty straightforward. The fewer decisions the deck needs to make, the better AI will handle that deck. Tarmogoyf, considered one of the best creatures on Legacy, fits this function of brute force quite well: easily splashable, low mana investment, grows quickly as game progresses. It amuses me why Tarmogoyf isn’t widely used on AI decks.

(This is mtgrares talking now)
Let me briefly critique the pseudocode.   The AI has a hard time determining if you (the opponent) has a dangerous creature on the field.  How dangerous is dangerous?  Is a flying 2/2 dangerous or does it have to be a flying 4/4?  Royal Assassin is very dangerous bit the AI won't recognize it has dangerous, since it is only a 1/1 and the AI cannot "see" activated abilities.

I would suggest using Jace to look at his opponents library.  If the opponent has less than 6 lands the AI would put basic lands on the bottom of your library and if the opponent has more than 6 lands, do the opposite, put any spell on the bottom of your library.  Then use Jace's ultimate ability to win the game.

And to finish the article on a funny note, "I am the mustard seed of your doom" which is taken from the videogame Mario and Luigi: Bowser's Inside Story. 

--mtgrares

Monday, November 22, 2010

Generate Deck - Play by Play


I love Forge's generate deck option.  It was something that occurred to me randomly and has grown to be one of my favorite ways to play Magic.  Today, I'm going to play through one game against the AI and describe all of the wonderful, exciting stuff that happens.

I lost the coin toss and I'm going second.  My opening hand has 4 lands, 3 cost creature, 6 cost creature, and an creature enchantment (aura).  I should win if I can play Plasma Elemental (cost: 5U, 4/1) since it is unblockable, if the AI doesn't weenie rush me.
The AI plays a land.

I draw the nearly worthless Demolish (cost: 3R, sorcery) which says "Destroy target artifact or land."  I play an Island.

The AI plays a different land, so he has access to both of his colors.

I draw another Island and play a Mountain.

AI plays another Plains.  (Those Zendikar full-frame lands do look great.  I was hoping that Wizards would print all new lands like that.)

I play a 2nd Island and cast my Vodalian Knights (cost: 1UU, 2/2) which has first strike and gains flying for U.  I caught a big break since Vodalian Knights can't attack unless the AI has an Island, which it does.

The AI plays a 4th Island and plays Cessation (cost: 2W, enchant creature, enchanted creature can't block) on my Knights.  At least Vodalian Knights can still block.

I draw the insane Phantasmal Forces (cost: 3U, 4/1, flying) "At the beginning of your upkeep, sacrifice Phantasmal Forces unless you pay U" and cast it.

The AI plays another land (now he has 5) and Psionic Blast's my Phantasmal Forces.

I draw and play another land so now I have 5.  I don't have any creatures that I can play yet so I destroy one of the AI's land with Demolish and I play Brainstorm (cost: U, instant, Draw three cards, then put two cards from your hand on top of your library in any order.) Brainstorm doesn't show me any creatures.

The computer plays Keeneye Aven (cost: 3U, creature, 2/3, flying).

I cautiously play my game winning Plasma Elemental (4/1, unblockable) and hope the AI doesn't notice.

The AI plays Diplomatic Immunity (cost: 1U, enchant creature) which gives his Keeneye Aven shroud and swings for 2. 
AI - 18 life, Me - 18 life

I enchant Plasma Elemental with Volcanic Strength which increases Plasma's stats by +2/+2 and swing for 6.
AI - 12 life, Me - 18 life

The AI destroys Volcanic Strength with Frantic Purification (cost: 2W, instant, Destroy target enchantment) and attacks with Keeneye Aven for 2.  AI - 12 life, Me - 16 life

I draw the obscure card Onslaught (cost: R, enchantment, Whenever you cast a creature spell, tap target creature) which doesn't help me at all but I play it anyways.  I attack with Plasma Elemental for 4.
AI - 8 life, Me - 16 life

The AI coolly attacks for 2 and then plays the game changing Meloku the Clouded Mirror which has the ability to turn all of your lands into 1/1 flyers.  Lets hope the AI is dumb and doesn't use Meloku's ability.
AI - 8 life, Me - 14 life

I draw another odd Magic card, Bringer of the Blue Dawn which costs an insane 7UU.  I only have 7 lands so Bringer is unplayable.  I swing for 4 with Plasma Elemental.
AI - 4 life, Me - 14 life

The AI swings for 2 with Keeneye Aven and only creates one flying token.  The AI seems smart and plays Shu Soldier-Farmers (cost: 4W, 2/4) which has a triggered ability, so the AI gains 4 life.  That extra 4 life means that the AI can live an extra turn.
AI - 8 life, Me - 12 life

I draw and play another land.  I swing again for 4 with Plasma Elemental.
AI - 4 life, Me - 12 life

The AI creates one more token with Meloku and attacks with almost everything, for a total attack of 6.  I sacrificially use Vodalian Knights to reduce the attack to 4.
AI - 4 life, Me - 8 life

Finally victory is within my grasp.  I attack with Plasma Elemental and win the game.  All in all it was a good game.  The AI whittled my life down to 8 and threw me a few curveballs.  Plasma Elemental was an all-star and I would have certainly lost the game with any other creature.  In this format the creatures win the game.  Generated decks feel similar to sealed decks because they are a little random and not very focused.

Playing a quick game like this is very satisfying.  Magic is a fun game with lots of variety.  I love not knowing which cards are in my deck.  I love that feeling of surprise and of course winning occasionally doesn't hurt. :)  I'm glad that the AI put up a good fight and didn't seem to do anything stupid.

Keep tapping,
mtgrares

p.s.
--The generate deck code that I wrote still has some major flaws in it: it doesn't generate a mana curve and it could exclude some awful cards which are only useful if you build a whole deck around them.  I prefer generated decks without creatures with a low power (0 or 1) and without artifacts.  The menu options are in the New Game screen, under Options.

--Writing is hard work.  It took me an hour to write the 900 or so words above.  I have no idea how the guys at Star City Games churn out so many pages each week.

Friday, November 19, 2010

Jesus Follow-up

I figured my Jesus post would generate a number of comments.  Most personal blogs are so random that they are unreadable so I have intentionally focused on making all of my posts about Magic or programming.  So rather than diluting this blog, maybe I’ll start another blog where I talk only about Jesus (but I’ll probably sneak in some Magic stuff).

I realize that religion is a volatile topic and everyone has a strong opinion.  One of my favorite shows is House and he despises religion.  I also know that Karl Marx said that “Religion is the opiate of the masses”.  But neither House nor Karl Marx have changed my stance on Jesus.

The truth about blogging is that I have no idea what I’m doing even though I’ve written more than 100,000 words.  I’m just a guy who writes stuff for an unseen audience.  Yes I can look at the hit count and say that the average number of views in a day is 500 to 800 but those are just numbers and people are different than numbers.  To me blogging is just a big experiment and the only reason that I blog is to “advertise” Forge.

Thanks for your patience,
mtgrares

p.s.
The new opiate of the masses is the Internet and before that was the TV.

Thursday, November 18, 2010

Do you know Jesus?

I wanted to briefly talk about something more important than Magic.  I believe that heaven and hell are real, literal places and that the only way to get into heaven is to ask Jesus into your heart.  The common belief is that a person has to be “good” or do a few “good works” to get into heaven but the Bible says our good works are as “filthy rags”.  Nothing you can do (without Jesus) will get you into heaven. 

The only way to get into heaven is to ask Jesus into your heart and to ask him to forgive your sins.  If you have never read the Bible, start with Matthew which describes the life of Jesus.

p.s.
I have been reluctant to talk about Jesus on my blog but since Jesus is the most important part of my life, I should talk about him more. 

Monday, November 15, 2010

How to NOT Write a Magic Clone


Let's say that you wanted to write your own implementation of Magic (for some unknown reason). Naturally you would create a Card class which mimics a real, cardboard card. And for some crazy reason you wanted to add your favorite card from Planeshift Singe (R, Instant, "Deals 1 damage to target creature"). Obviously you are not a "power gamer" but that is ok, because you like who you are....maybe.

The simplest way to implement effects like Singe is to allow a Card object to deal damage to another Card object. The code for Singe would look something like this:
Singe.resolve()
{
  getTargetCard().addDamage(1)
}
So far so good, one card down, a bazillion to go. Now you want to code a card that says, "Whenever you deal damage, you draw 1 card". Suddenly your world comes crashing down because your simple implementation doesn't work. Card objects should not deal damage to each other, so you use a layer of indirection. Singe could be written as:
Singe.resolve()
{
  RulesEngine.addDamage(getTargetCard(), 1)
}
Now you want to add another card, Awe Strike (W, Instant, "The next time target creature would deal damage this turn, prevent that damage. You gain life equal to the damage prevented this way").

The question is this, "Can we add Awe Strike using the method above?" Truthfully the answer is maybe. If every card uses the rule engine hopefully you should be able to code Awe Strike. Unfortunately the devil is always in the details.

The goal when programming a Magic clone is to give as much information as possible to the rules engine so it can do the insane things that Magic cards do like Painter's Servant

If the rules engine isn't given enough information eventually your Magic clone will hit the wall and not be able to implement a card or keyword.

Keep on tapping,
mtgrares

p.s.
The craziest card I know of is Warp World (5RRR, sorcery) which dumps all of your permanents into your graveyard and then you draw that many cards and put those permanents onto the battlefield. The Magic 2010 set faq lists 6 separate sub-steps.


--“All problems in computer science can be solved by another level of indirection.”

--You can read more about my idea of making the rules engine object huge because it has to handle everything in the whole game.  (Most of the RulesEngine object would just act as a "wrapper" for other objects/methods.)  Big objects are usually to be avoided because they have too much complexity but I don't see another way to handle a game like Magic.  You can read a previous post about this subject here.

Wednesday, November 10, 2010

Forge Download - With Decks

I forgot to include decks in the most recent verison of Forge.  That is fixed now.

You can download more decks from Forge's deck forum here.

Monday, November 8, 2010

Forge’s Strengths

Some people have accused me of talking more about Forge’s weaknesses than strengths, so I decided to remedy (fix) the situation. Forge has a number of strong points such as: good architecture, quest mode, and a number of great volunteers.

Talking about Forge’s software architecture is a little abstract so let me provide a comparison. A program’s architecture is the foundation that the rest of the program is built on. The foundation can be marginally improved but basically the foundation restricts what the program can and cannot do.

Forge’s architecture isn’t perfect but I would give it a good B. I assumed most costs would be mana costs which is true 90% of the time but this decision makes adding cards with additional costs (like sacrificing a permanent) more complicated. Looking back it would have been better to make cost an abstract class (or interface in Java terms) so that the cost could be anything. On the positive side Forge’s architecture lets you basically do (almost) anything, so you can hack it do death in order to support weird/unusual cards. Most of Forge’s architecture was built by me but other people have improved my code. I remember trying to code Time Walk and Forge just wouldn’t support it, but now Forge has Time Walk, so I am very impressed.

Forge’s greatest feature is the fantasy quest mode. I like to think of it as a poor man’s Shandalar since it is only menu based. In the beginning you start out with a random cardpool and you buy or win more cards. Quests can be as short as 10 wins or as long as you want it to be. You have 200 different decks that you may face.

The fantasy quest mode also allows you to buy more life, since you start at with 15. You can also purchase a free mulligan (you draw 7 cards) or a creature to begin the game with (either a plant wall or a wolf). You can also buy a boost that adds 10% to all of your match winnings as well as improving your selling percentage to the card shop by 1% (which is a lot since the card shop usually only buys at 10%). After 20 wins you may also get to face specialized AI opponents that have an unfair advantage. To add some tention, some of these special opponents can only be played once, so you better make sure to win. (A big thanks to Dennis for the fantasy quest mode.)

And lastly Forge is great because it has a good number of volunteers. Without these volunteers Forge would have probably been stuck with only 1,000 cards. These guys have improved the user interface, added the fantasy quest mode, and added/fixed numerous cards and bugs in Forge. While Forge didn’t have any documentation (which is my fault) the code seems to be very readable and I’m glad that these guys can figure out my (insane) code. Nowadays they know more about Forge than I do.

I never dreamed Forge would have over 5,000 cards or be downloaded 1,500 times a month. Forge has been the biggest project I have worked on and I’m just glad that Forge’s architecture didn’t implode because of all of the hacks. (Earlier versions of Forge did sort of collapse under their own weight because the foundation was not good enough.)

“Never debug standing up”

--mtgrares

p.s.
I hate to explain this quote because then it isn’t funny but I don’t want to leave anyone out. “Never debug standing up” is like saying, “No matter how long you think a job will take, it will always take more time” similar to Murphy’s Law.

p.p.s.
A clone of Shandalar is being worked on. You will walk around and do similar quests.

Monday, November 1, 2010

New Version

This new version of Forge has almost 800 new cards and a world-bashing total of 4,890 cards. (P.S. Don’t ask me what “world-bashing” means, I just made it up.)

I’m just going to list some of the new cards without any rhyme or reason. Bubble Matrix (4, artifact) says “Prevent all damage dealt to creatures” so you will probably need an alternate win condition or try burning your opponent off the face of the planet. Claws of Gix (0, artifact) “1, sacrifice a permanent: You gain 1 life” will interest some deck builders like moths to a nuclear bomb.

Fortune Thief (4R, creature, 0/1) will always keep your life at 1 like Ali from Cairo. Fortune Thief does have morph and can be flipped for RR. Some people may remember Arcbound Ravager (2, artifact creature, 1/1) combine him with Disciple of the Vault to damage your opponent when artifacts go to the graveyard. Umbra Stalker (4BBB, creature, */*) its power and toughness are equal to the number of black mana symbols on the cards in your graveyard. At least it gives you one reason to mill yourself.

Download Forge (10 MB) – Runs on Windows, Mac, Linux and requires Java 1.5 or higher.  This is the 10/19 version because that is when it was released on the forums.

Download (109 MB) - LQ (low quality) Card Pictures - delete your /res/pic/ directory because this file creates a new directory named "pic"

I’m sure there are other mind-blowing cards but you will have to find them for yourself. Download and enjoy.  --mtgrares

(For some reason Word 2010 wants to change "artifact" to "artefact", go figure.  Computers are .... weird sometimes.)

p.s.
Many people helped with this version. Programming can be very hard and frustrating. A big THANK YOU goes out to them:

Dennis Bergkamp
Rob Cashwalker
Friar Sol
Slapshot5
Sloth
Zerker2000
Gofishus
Hellfish
Nerzahd
PhoenixAvenger
Chris H

Monday, October 25, 2010

Forge's Architecture or "How to program your own Magic engine" - Part 2

In Forge each player's life and zones (hand, library, battlefield, exile, stack) are all global variables. Much of the user interface and card code needs to access this information, so instead of passing the data everywhere, I just made it global.

GameAction is a loose collection of methods:

newGame()
drawCard(String player),
moveToGraveyard(Card c)
discard(Card c)
discardRandom(String player)
checkStateEffects()
sacrifice(Card c)
destroy(Card c)
destroyNoRegeneration(Card c)
shuffle(String player)
getOpponent(String p) : String
isCardInPlay(Card c) : boolean

Most of the code in GameAction could be done by the individual card code but putting all of the code in one place promotes code reuse and DRY (don't repeat yourself). GameAction at first only had newGame() and drawCard(String player). The other methods were added as needed.

GameAction.checkStateEffects() checks for state effects like "should a creature go to the graveyard" and the "legendary rule". At first I had no idea how to implement ongoing state effects like Glorious Anthem but then I hacked this method, voila! At first I thought I was bending the rules but this is completely correct after all.

(Forge has GameActionUtil which helps GameAction and is made up of static methods. GameActionUtil continues Forge's tradition of huge classes is 1/2 MB of code. And no that isn't Forge's largest class, CardFactory is a cool 1 MB all by itself. 1 MB of code is absolutely huge and is as long as a novel.)

Playing a spell or ability seems easy but there are many checks that you need to do. When choosing targets for a spell or ability, first you have to check if the chosen card has protection from that spell. Then each time a targeted spell/ability resolves, it has to check "is this card still on the battlefield" by GameAction.isCardInPlay(Card c). (I wrote this back when the battlefield was called "in play".)


Input

The Input class implements the State Pattern and handles all of the mouse clicks. Input is used to implement phases and choosing targets. Initially the Input class can be confusing but if you look at the code, you should be able to understand my design.

Input is just an interface (abstract class). The getMessage() method would return something like "Main1" or "Choose target creature to receive 2 damage".
interface Input
{
  String  getMessage();
  void    clickCard(Card c, Zone z);
}
The class InputControl is attached to the user interface and is just a "wrapper" for Input.
class InputControl
{
  private Input i;

  void setInput(Input input)
  {
      i = input;
      String s = i.getMessage();
      //display s on the user interface (gui)
  }

  void clickCard(Card c, Zone z)
  {
      i.clickCard(c, z);
  }
}
Hopefully you can see how InputControl changes. InputMain.getMessage() would return "Main Phase" and InputMain.clickCard() would allow the player to play a card in his hand or an activated ability on a creature on the battlefield. Input is also used to pay mana costs, to mulligan at the beginning of the game and to declare attackers and blockers.

Since InputControl.setInput() always calls Input.getMessage() first, you can put hacky stuff in getMessage(). Planeswalkers were introduced to Magic after I had much of Forge written and I was wondering if I could add them somehow. I put a bunch of hacky code in Input.getMessage() to restrict the player to only using one ability per turn. Also at that time Forge didn't even have the concept of loyalty counters, so I just used an int. Finally I just created another Combat object to simulate planeswalker combat. (For a long time if the AI had two planeswalkers, you could only attack the first one.)


A more complete Input class would also have clickPlayer(String player) and clickManaPool(). Technically the Input class does not process all of the mouse clicks since dialog boxes are used to get additional information from the player. The Input class could be modified to include dialog boxes which would be more "unifying" versus allowing the card code create dialog boxes at will.

The Input class may not seem very important but it was one of the first, big problems that I faced. I have no idea how Shandalar or other Magic programs process the mouse. Without stumbling onto the state pattern, I have no idea how badly I would have coded an inferior Input class.

Well that covers the main classes in Forge: Card, SpellAbility, Input, and GameAction. Forge has numerous other classes like CardList but these are the most important ones. If you understand these 5 classes, you can write your own Magic rules engine.

--mtgrares

p.s. Feel free to post any further technical questions about Forge's architecture.

Monday, October 18, 2010

Forge's Architecture or "How to program your own Magic engine" - Part 1

The old Rocky and Bullwinkle cartoon would always announce the next episode with two separate but related titles like "Bombs Away" or "My Ears are Ringing". Today I wanted to talk about Forge's architecture which should point you in the right direction for programming your own Magic rules engine. (You should also download a copy of Magic's comprehensive rules and read through as much as you can. I remember thinking that trample worked even when a creature was blocking.)

For interested non-programmers, the word "class" or "object" means "lines of Java code". Card.getName() means that getName() is code that exists inside the Card object.


Card

The most important classes in Forge are Card, SpellAbility, Input, and GameAction. The Card class represents a physical Magic card. Card objects are used everywhere that a real Magic card is used: player's library, graveyard, hand, battlefield, and exiled. Each Card object has a unique id so the player can know which card the AI is targeting. Shandalar had an option that allowed you to see each card's unique id.

(I was tempted to use only the card's name (String) in the library, hand and graveyard. I'm glad that I didn't because flashback was a late addition but it works beautifully because a card is a Card object and not a lousy String.)

The Card class has become more and more complicated and has grown from 200 lines to 17,000 (including whitespace and blank lines). Important Card methods are getName() : String, getSpellAbility() : SpellAbility[], getUniqueID() : int.


SpellAbility

The SpellAbility class represents every spell or ability. A Card object holds one or more SpellAbility objects. A Card object representing Elvish Piper would hold two SpellAbility objects. One representing the 1/1 creature and one representing the activated ability. The SpellAbility for the 1/1 creature can only be played if the Card object is in the player's hand, so SpellAbility.canPlay() checks to see which zone the card is in. Likewise the SpellAbility representing the activated ability, so canPlay() only returns true if the card is on the battlefield.

SpellAbility.canPlayAI() returns true if the AI should play the card. This means that each card is responsible for evaluating the game state. SpellAbility.canPlayAI() for Giant Growth checks to see if any of the AI's creatures are attacking and then targets one creature. This type of AI is very basic but it allows the AI to use a wide variety of cards. Since each card is evaluated separately the AI won't kill a 4/4 flyer with 2 Shocks. SpellAbility.resolve() is self-explanatory and does the "action" of the card like destroying all creatures.

In Forge only SpellAbility objects can go on the stack. This has caused some complications because after you pay for a card, you can't simply move the Card object from your hand to the stack. In Forge 2, I have been thinking about technically allowing a Card object to go on the stack and then get the SpellAbility using a method like, Card.getStackSpellAbility().

The methods setTargetCard() and setTargetPlayer() are used when the card targets only one card or player. The AI also uses these methods which allows the resolve() to be the same for both the human player and the AI. (Having different resolve() methods for you and the computer is a dangerous, dangerous road that I almost went down. Duplicating resolve() for different players seems wrong because of the code duplication.)

SpellAbility.setDescription(String s)
SpellAbility.getDescription() : String

SpellAbility.setStackDescription(String s)
SpellAbility.getStackDescription() : String


These are typical get/set methods. getDescription() is used when the card is in your hand or in play, while getStackDescription() is used when the card (SpellAbility) is on the stack and should say something like "Shock - targeting Elvish Piper (23)". While these 4 methods are minor, they convey much needed information to the player.

Important SpellAbility methods include getManaCost() : String, canPlay() : boolean, canPlayAI() : boolean, resolve(), setTargetCard(Card), setTargetPlayer(String player).

(SpellAbility should use an abstract Cost class instead of getManaCost() because Cost could include tap and sacrifice costs. Forge has to hack tap and sacrifice costs in order to make them work.)

Since this was just an overview of Forge and some of you may want more details. Please leave comments about the technical details you are interested in. I have breezed over many of the small details like "how exactly do you pay for mana" and "what should the user interface look like". These are important decisions that you, the lead programmer, need to decide. Programming is the result of thousands of tiny decisions that need to miraculously work together.

Next week I'll talk about Input and GameAction.

~~mtgrares

p.s.
Forge just uses Strings to represent mana and the reason that all mana strings have extra spaces "2 G G" was because it made the parsing code extra easy. This was a design decision that I had to make early on. It really doesn't matter if there are spaces or not but a decision has to be made.