Monday, September 20, 2010

Can this creature block that creature?

Combat is essential to Magic (and most card games) and blocking is part of combat.

Forge uses the method CombatUtil.canBlock(Card attacker, Card blocker) to determine if a creature can block. The canBlock() method returns true if the blocker can block and false if it can’t. (All classes ending in “Util” are composed of global, public, static methods and “Util” stands for “utility”.)

In the beginning canBlock() only checked for flying and fear but now the method has grown to 250 lines (including whitespace). You can view the canBlock() method here. Landwalk was one of the first code snippets that was submitted. (Probably by Rob Cashwalker or DennisBergkamp.) I was impressed that landwalk could be implemented and that canBlock() was able to be modified by an outside coder.

While canBlock() is long it isn’t too hard to understand because each code segment does its test and returns false if the blocker cannot block. Each of the “if” code segments are separate and do not interact.

Here are some of the conditions that canBlock() tests for:

Flying
Reach
Horsemanship
Fear
Intimidate

Plainswalk
Islandwalk
Swampwalk
Mountainwalk
Forestwalk
Legendary landwalk
Nonbasic landwalk

CARD can block only creatures with flying
CARD can't be blocked by creatures with flying
CARD can't be blocked except by creatures with flying

CARD can't be blocked by white creatures
CARD can't be blocked by Walls

Shadow
CARD can block creatures with shadow as though they didn't have shadow

CARD can't block creatures with power X or greater
CARD can't block creatures with power X or less

Each of the above conditions is a string (characters that you can see) and each card holds any number of strings (which internally are called keywords). The great thing is that Forge uses the text file cards.txt to create basic creatures that have one or more of the above keywords. Forge can even create instants and activated abilities by using special “scripting” keywords. I plan to talk more about scripting in a week or two. (For more info you can view cards.txt here.)

Here are two examples that don't require any extra Java coding.

Shock
R
Instant
no text
spDamageTgtCP:2
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/shock.jpg

Avian Changeling
2 W
Creature Shapeshifter
no text
2/2
Flying
Changeling
SVar:Rarity:Common
SVar:Picture:http://resources.wizards.com/magic/cards/lrw/en/card145813.jpg


Live long and prosper,
mtgrares

p.s.
I wasn't aware of the proliferate keyword. The card picture above is from the set "Duel Decks: Elspeth vs. Tezzeret".

Proliferate means "You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there."

9 comments:

Luis MArtins said...

Nice blog you have here.
Love to read the new updates on Forge.

Just one question.
I do not understand the Java programming. Can you tell me if this methos of "canBlock()" is implemmented in Forge 8-20?

Thanks in advance.
Regards and good job,
Luis Martins

Chris H. said...

Recently, the cards.txt file was converted into a folder named "cardsfolder". This folder contains over 4000 text files and each file now contains the info for just one card.

Forge said...

"Nice blog you have here. Love to read the new updates on Forge."

I only write once a week in order to keep myself sane and thankfully Forge has many people that do the programming. (I haven't coded anything to Forge in awhile.)

"I do not understand the Java programming. Can you tell me if this methos of "canBlock()" is implemented in Forge 8-20?"

Yes, all versions of Forge have the method canBlock().

Forge said...

"This folder contains over 4000 text files and each file now contains the info for just one card."

4,000 files is alot but hopefully it is an improvement.

When programming I've encounted this question a few times, "Should the program use one big file or hundreds (or thousands) of small files?" Obviously there are pros and cons on both sides depeneding on the specifics of the program.

Srećko Milosavljević said...

I missed your last post (request for ideas) and i'm writing here just to make sure you read this :)
My programming days are far behind in the high school, but I'm willing to help anyhow. I believe that there are heaps of boring jobs that we (non programming crowd) could do and it would be nice to read an introductory post how we could help.
Thank you and the team for a great game.

DennisBergkamp said...

"I do not understand the Java programming. Can you tell me if this methos of "canBlock()" is implemmented in Forge 8-20?"

This method can be found in CombatUtil:

CombatUtil.canBlock(Card attacker, Card blocker)

Luis Martins said...

"I do not understand the Java programming. Can you tell me if this methos of "canBlock()" is implemmented in Forge 8-20?"

When I referred this I was asking if the Forge 8-20 already have this new 250 coded lines.

Sorry if I expressed it badly.

And thanks for the quick response.

Forge said...

Srećko,

The forums is a good place to find things that need to be done.

Fidget said...

Sorry I'm a little late to the topic, but I was just tooling through the blog and saw this and had some thoughts.

Have you ever considered using SQLite, opposed to flat files? It would be a pretty handy way of abstracting away storage from the logic of the game. Another option is XML, of course.

Also, I'm thinking through this code and I don't think this is the best way to go about it. Utility functions are a little kludgy in Java. I think the most extensible way of going about this would be to have a Card class that has a method:
Public Card.canBlock(Card attacker)
And then through I know there are some ways to generate classes from XML/databases, so you could have each card have it's own class, and then instantiate it for each time it's in the deck/card/play/graveyard. I'm not 100% sure how this might work, but some sort of scripting language might work. You'd almost definitely have to roll your own. I just can't see all of these individual exceptions and conditions working out in the long run.