Monday, September 8, 2008

Programming Cards using Plaintext

If you read my previous post I asked the question, “How do you condense a Magic card into reusable parts that can be written as text?” There are many answers to this question but I will show you how I plan to do it for MTG Forge version 2. I plan to encode cards using only text.

2 B

Text: Destroy target tapped creature.
Target: creature
Resolve: destroy target creature

Royal Assassin
1 B B
Creature Human Assassin

Activated Ability
Text: tap: Destroy target tapped creature.
Cost: tap
Target: tapped creature
Resolve: destroy target creature

This is how cards will be encoded in version 2. Gone are the days of having to know Java. There is a lot of similarity between these two cards. Assassinate and Royal Assassin’s ability both have the same targets and resolve. My goal is to reuse the same Java code for both of these cards. My current way of cutting-and-pasting code is hacky to say the least.

The format above is similar to the current format in cards.txt. I love plaintext because it is so easy to read and understand. I am thrilled with the possibility of being able to encode spells like Assassinate using only plaintext. I realize that the format above won’t work for all cards, like Fire//Ice, but it will work for 90% of them.

This plaintext encoding is also very easy to parse. (Parsing is when the program interprets the plaintext and actually constructs the code for the card.) My goal is to reduce a card into a set of reusable parts. I want multiple cards to use the same targeting and resolve code.

Personally I am very excited about this “discovery.” The plaintext is very readable by both humans and machines. Practically I could add this to MTG Forge version 1 but I’m going to put it into version 2, because version 1 has many bugs.

I already have the experience of programming many Magic cards and I know what needs to be improved. Multiple cards need to use the same code. All cards that say “gain life” should use the exact same code and in version 2 they will.

Like I’ve said before, there are many ways to encode cards as text. My way may not be the best way for someone else, but it is the best way for me. I understand these plaintext cards and I “see” the code in my head. The targeting and resolve code can be separated and I also understand how to connect the targeting code to the resolve code.

It seems like I could remove the “text:” line but it greatly simplifies everything by keeping it. My goal is to make parsing as easy as possible and hopefully idiot proof, lol. (Parsing tends to be very complicated and hard to test. And yes regular expressions make parsing easier, but I want it to be very easy. And like all things in MTG Forge, it can be changed later. For all your programmers out there, I call that “very late binding” LOL.)

This plaintext encoding can also work for triggered and static abilities.

Venerable Monk
2 W
Creature Monk

Triggered Ability
Text: When Venerable Monk comes into play, you gain 2 life.
Trigger: comes into play
Resolve: gains X life – controller, 2

Glorious Anthem
1 W W

Static Ability
Text: Creatures you control get +1/+1.
Effect: creatures you control get X/X, 1, 1


Text: Shock deals 2 damage to target creature or player.
Target: creature or player
Resolve: damage target creature or player, 2

Ballista Squad
3 W
Creature Human Rebel

Activated Ability
Text: XW, tap: Ballista Squad deals X damage to target attacking or blocking creature.
Cost: X W
Cost: tap
Target: attacking or blocking creature
Resolve: damage target creature – X paid

2 W

Static Ability
Effect: your creatures (subtype X) have keyword X, soldier, vigilance

Activated Ability
Cost: 2 W
Resolve: create token, 1, 1, soldier, W


Anonymous said...

You should be careful because for example for Royal Assassin his ability also checks on the resolve if the creature is still tapped.
It is not only the targeting restriction.

MioCid said...

The good thing of this is that all of us could help you and get all the cards coded (at least the easier ones)

Seems difficult to me, though

Silly Freak said...

i hope the examples were not exactly as you imagine them. in whole, it's a good idea, but you should be careful with using the targeting restrictions in the resolve part. for example, ballista squad says "attacking or blocking creature" in the target but only "target creature" in the resolve. parsing that is maybe not that simple

also, for finding cards by properties (creatures you control, cards in your graveyard...), i think you should use a more generic ability.
the "creatures you control get X/X" ability is very specific. it doesn't even allow night of souls betrayal. I imagine cards(controler=you,type=creature) or something like this.

the same could easily be done for targeting. it would mean to target one card matching the criterion, which would be also checked on resolution.

Rob Cashwalker said...

Making these generic abilities is easy as long as they're uniform in targeting. It's providing for these cases where there are many different restriction combinations....

Creatures you control is easy. All Creatures is easy. All Black Creatures is moderate. Black Elf Creatures You Control is getting more difficult. And those are just dealing with color, type and controller, the most very basic restrictions. Throw tapped into the mix, and wait for hell to freeze.... Reading this information is no problem. It's using this information later to form the spell abilities in code where it gets sticky. When I tried to implement a fraction of what Forge is talking about, I ended up with so many nested if-then-else blocks that I lost track of what I was trying to do in the first place 100 lines ago.

Forge said...

"You should be careful because for example for Royal Assassin his ability also checks on the resolve if the creature is still tapped.
It is not only the targeting restriction."

True, I sometimes forget the the legality of a target is also checked before the card is resolved.

"i hope the examples were not exactly as you imagine them."

Sorry to burst your bubble, but yeah. I'm not saying that I will only use this kind of formatting but to begin with I plan to program cards this way.

I'm just trying to reduce a large number of cards and spells into text, I'm not planning on reducing every card into a text format. I the future I'll probably use XML also.

Silly Freak said...

i didn't mean that your notation is bad. i like the splitting of cost, target and effect, which reflects the actions really taken. i just meant that you should be careful with the targets in your effects section.
if the target is "attacking or blocking creature" you also have to destroy "target attacking or blocking creature". if you skip "attacking or blocking" you could also just say "destroy target"

Forge said...

Well maybe Royal Assassin's resolve should say.

Resolve: destory target tapped creature

All this is a little bit hypothetical and I haven't worked out all the details and problems that can and will occur.