Monday, May 30, 2011

The Magic Stack


I've read countless times that the most confusing part of Magic for beginners to understand is the stack.  When I personally think of a "stack", I picture the little stack of plates at buffet restaurants.  The top is the only place that you can add or remove plates.  Stacks are a common computer programming concept.

When programming Forge I had to decide what type of object would go on the stack?  What information should the stack item store?  I had already created a class called SpellAbility, which represents each spell or ability using the command pattern, which is an abstract execute() method. 

In Forge I put the SpellAbility object on the stack and getSourceCard() which would return the card object that created the spell or ability.  Generally this works very well with Shocks and Giant Growths stacking correctly.  (If I had to do Forge again, I would cheat a little and put Card objects on the stack.  Card.getStackObject() would return a SpellAbility object.  Moving only Card objects around makes some of the programming much easier.)

Obviously as cards become more complicated the stack must become more complicated.  Currently the developer team is redesigning the stack and wrapping SpellAbility with an object called StackItem.  This makes sense because SpellAbility was designed to be added to Card objects and wasn't designed to go on the stack.  By changing Forge's design it will allow more cards to be added.  And hey, everybody loves the smell of fresh cardboard in the morning.

Thanks for reading,
mtgrares

p.s. 
The stack gets very complicated very quickly when you include obscure cases which generate multiple effects which individually go on the stack.  First the active player chooses the order of effects for his cards then the non-active player chooses. 

405.3. If an effect puts two or more objects on the stack at the same time, those controlled by the active player are put on lowest, followed by each other player’s objects in APNAP order (see rule 101.4). If a player controls more than one of these objects, that player chooses their relative order on the stack.

APNAP stands for Active Player, Nonactive Player Order - which means that the active player goes first, then the non-active player.  The active player is "the player whose turn it is" or simply, the player who untapped and drew a card.

Monday, May 23, 2011

Forge Commits

Committing is posting your code from your individual computer to the server where the code is stored.  The Forge project has 50 or more commits a day, which is very impressive.

Every commit is just one small change.  Let's take a look at a few.

The AI will use ZoneAffecting more often at the end of human turn.

This means that the AI will try to use more effects at end of turn.  ZoneAffecting is a scripting keyword which is used to create cards.

Another small step towards Mana Drain script-only.

Harding coding cards is a really big pain, so the more scripting the better.

Fixed Akki Coalflinger. Improved AI of Pyrohemia and Swans of Bryn Argoll.

This commit changed 3 things.  Apparently Akki Coalflinger wasn't working (an update probably broke him) and the AI has a hard time using complex cards like Pyrohemia (which deals damage to all creatures) and Swans of Bryn Argoll, which ignores damage but turns that damage into card drawing (1 damage = 1 card drawn by your opponent).

Doomgape is not correct. It can not be scripted at this time.

I think the comment says it all. 

Converted March of Souls to script. 

March of Souls can be scripted and the java code for the card can be removed.  (I coded March of Souls back in the day because it was so unusual.  It destroys everything like Wrath of God but also creates 1/1 tokens for every creature on the board.  Usually March of Souls was worse than Wrath but in a jam it might help.)

Converted Lorthos the Tidemaker to script.

Always a good thing. 


Added Magus of the Moon and Blood Moon.

Both cards turn non-basic lands into mountains.

Make sure state-based effects are checked when a land is played by either player, not just the computer.

State effects can get very complicated and it is hard to make sure that they are called at the right time.  Basically state effect needs to be called/checked after anything happens in Magic, which is generally when somebody plays a land or an ability/spell is put on the stack or resolved off of the stack.

Forge is composed of literally millions of these small programming changes.  Thanks to the development team for their hard work.

Monday, May 16, 2011

Picking the Right Programming Language


I actually worried a little bit when I started coding Forge in Java.  I thought, “Was Java really the best language for this project?”  “What if people didn’t have Java installed on their computers?”  Thankfully I have never had an email telling me that they had to install Java.  I presume some people did have to install Java but hopefully it installed without any problems.  After a little analysis-paralysis I chose Java and starting coding furiously.

In the end I chose Java because it was the language I knew the best.  Java isn’t perfect but no language is.  Java ended up to be a good choice because Forge also runs on Mac and Linux.  The remarkable thing is that I didn’t intend for Forge to run on any other operating system other than Windows.  Being able to be run on Mac and Linux was a happy accident.

Choosing the right programming language also depends on your goal.  If you want to make a browser based game you can use Flash or Java.  (Forge could be made into a browser game but it would take a lot of work.)  If you are trying to squeeze every CPU cycle, you will probably want to use C++.   Java is pretty fast but C++ is probably the fastest language (other than assembly of course).

Various Magic projects use various languages.  Incantus is written in Python.  Wagic uses C++ in order to effectively run on the PSP (Playstation Portable).  MagArena uses Java and although it uses min-max (a CPU intensive algorithm) it employs various speed-ups and it runs well on my 750 MHz machine.

In the end it really doesn’t matter which programming language you use. 

p.s.
If your language has any type of certification, I would say go for it.  Even if you just study and never take the test, it would really help you.  Studying helped me learn a bunch of esoteric stuff that is generally unimportant but sometimes very important.  By knowing a language through and through, you will be a better, faster programmer.

Monday, May 9, 2011

Forge Scripting


The current developers have done a great job working on Forge.  (Which does not include me.)  The reason that Forge supports as many Magic cards as it does is through scripting or dsl (domain specific language).  When I stopped working on Forge only simple creature cards could be scripted.  Now instants, sorceries, and activated abilities can be scripted.

Before I jump in and show you some examples of scripting, let me briefly define it.  “Scripting is using a special, ‘small language’ inside of a bigger program.”  In the case of Forge, basically scripting is using a special syntax or language other than Java.  Scripting is shorthand.  Creating cards with Java is long and verbose.  Creating cards with scripting is short and sweet.

To see Forge’s scripting, look in your /forge/res/cardsfolder/ directory and to begin things Shock is always a good place to start.


Name:Shock
ManaCost:R
Types:Instant
Text:no text
A:SP$DealDamage | Cost$ R | Tgt$ TgtCP | NumDmg$ 2 | SpellDescription$ Shock deals 2 damage to target creature or player.
SVar:Rarity:Common

Above is most of the text in the file “shock.txt”.  And while I don’t understand all of the scripting language, you see it deals damage, has a mana cost, has some kind of target, and does 2 damage.


Name:Elvish Piper
ManaCost:3 G
Types:Creature Elf Shaman
Text:no text
A:AB$ChangeZone | Cost$ G T | Origin$ Hand | Destination$ Battlefield | ChangeType$ Creature | ChangeNum$ 1 | SpellDescription$ You may put a creature card from your hand onto the battlefield.
PT:1/1
SVar:Rarity:Rare

Elvish Piper is another well-known card.  This time the scripting adds an activated ability and a complicated one at that.  The scripting specifies that the ability will changes zones, has a tap cost, and the card that you choose in your hand has to be a creature and that it will be put onto the battlefield.  Since the ability is a complex one, I thought that this card may not be scripted but it is nice that the scripting language is powerful enough to not use Java. 

(Elvish Piper was one of the first cards that I ever coded for Forge.  I thought I understood the rules very clearly but I still made a small mistake.  I didn’t understand the difference between “target” and “choose” so I made the player choose a creature card in their hand BEFORE the ability when on the stack.  This is very incorrect as the choice should be made AFTER the ability resolves.)


Name:Eon Hub
ManaCost:5
Types:Artifact
Text:Players skip their upkeep steps.

The text above is for Eon Hub but it does not have any scripting because it is specified in the Java code.  Scripting tries to deal with common actions not unique effects.


Name:Entomb
ManaCost:B
Types:Instant
Text:no text
A:SP$ChangeZone | Cost$ B | Origin$ Library | Destination$ Graveyard | ChangeType$ Card | ChangeNum$ 1 | SpellDescription$ Search your library for a card and put that card into your graveyard. Then shuffle your library.
SVar:Rarity:Rare

Entomb is another good example.


Name:Zombify
ManaCost:3 B
Types:Sorcery
Text:no text
A:SP$ChangeZone | Cost$ 3 B | Origin$ Graveyard | Destination$ Battlefield | TgtPrompt$ Choose target creature card in your graveyard | ValidTgts$ Creature.YouCtrl | SpellDescription$ Return target creature card from your graveyard to the battlefield.
SVar:Rarity:Uncommon

Zombify is similar to Entomb but the syntax is a little different because Zombify restricts you to only choosing creature cards.


Name:Wrath of God
ManaCost:2 W W
Types:Sorcery
Text:no text
A:SP$DestroyAll | Cost$ 2 W W | ValidCards$ Creature | NoRegen$ True | SpellDescription$ Destroy all creatures. They can't be regenerated.
SVar:Rarity:Rare

Wrath of God is a personal favorite of mine.


Name:Glorious Anthem
ManaCost:1 W W
Types:Enchantment
Text:no text
K:stPumpAll:Creature.YouCtrl:1/1:No Condition:Creatures you control get +1/+1.

Pumping up your creatures is another common effect.  This time the scripting creates a continuous static effect versus just a spell or ability.


Name:Wrath of Marit Lage
ManaCost:3 U U
Types:Enchantment
Text:Red creatures don't untap during their controllers' untap steps.
K:Permanents don't untap during their controllers' untap steps:Creature.Red
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigTapAll | TriggerDescription$ When CARDNAME enters the battlefield, tap all red creatures.
SVar:TrigTapAll:AB$TapAll | Cost$ 0 | ValidCards$ Creature.Red

And to wrap things up with, Wrath of Marit Lage.  This effect is very complicated and I’m surprised to see it scripted.

Forge’s scripting is the reason that last month 1,000 new cards were added.  Creating a scripting language is hard because you want it to be flexible but also easy to read.  “Easy to read” both as a programmer and “easy to read” as in “easy for the code to parsed”. 

(Parsing is transforming the shorthand into longhand and parsing can be very, very complicated and thorny.  There is no end to the parsing rabbit hole, which is why you try to make your scripting language easy to parse.)

I don't know if it is really scripting or not but Forge also puts the card rarity with the other card information.

Thanks for reading,
mtgrares

Sunday, May 1, 2011

New Version

Another great months equals another great version of Forge.  Forge now clocks in with 7,746 cards.  This month there are only 84 new cards but you have to remember that last month there were more than 1,000 new cards.

4-22 was the date that this version of Forge was first posted on the forums.  Many thanks to the faithful developers :*)

Link - Forge 04-22 (Windows, Linux) 13 MB

Link - Forge 04-22 (Mac) 8 MB - Use Keka to uncompress 7z files

Link - Quest Opponent Icons - 1MB - The Mac version needs these pictures, put them in /forge/res/icons/ directory

Download - Card Pictures (160 MB)
These are most of the low-quality (LQ) card pictures.  You can download the rest of the LQ card pictures or the high-quality (HQ) card pictures using the menu on the New Game screen.

Java - in case you need to update or download Java

If you have any questions/comments, please post them to the forum.
---------------------------------------------------------------------
Instead of blah, blah talking about the new cards I'm just going to show the card picture itself.  And of course you can admire the wonderful artwork.  (And yes this is way easier than typing a bunch of text myself.)


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

Sloth
Dennis Bergkamp
Friar Sol
Hellfish
Slapshot5
Jeff Wadsworth
Corwin72
Jaedayr
LazyLockie
Zirbert
Replika
Eidolon
Jhhh
Chris H

Here are some of the changes.  You can read all of the updates in "changes.txt"
- Fixed Mox Opal.
- Cards with "CARDNAME can't be the target of spells." can no longer be targeted by aura spells.
- "CARDNAME can't be the target of Aura spells." will no longer protect from abilities of auras (like Chime of Night.)
- Fixed Dense Foliage.
- Converted Leafdrake Roost to generic aura + AF.
- Added Zirberts Zombie Pack 4.
- Fixed Treva's Ruins.
- Fixed Mage Slayer.
- Minor edit to the notes recently added to CF_Auras.
- Added a brG Landfall theme.
- Updated some themes.
- Fixed several misspellings, changed occured to occurred.
- Cleanup in CardFactory.
- Added two new parameters to AF ChangeZone: Mandatory and Chooser (see wiki).
- Converted Chittering Rats as an example.
- Made a few edits to finish the Squirrel Nest conversion. Most of the work was already done at some point in the past.
- Converted Chimney Imp to use "Mandatory".
- Converted Mind Swords to use "Mandatory".