All of these Magic programs, including my own (Forge), encode cards differently. Today I’m going to show how Forge and Wagic encode two familiar cards: Shock and Royal Assassin. Forge takes the direct route and shoehorns cards into Java while Wagic uses its own scripting language which is very short and concise.
Of the five programs mentioned I believe that Forge’s cards are the longest and Wagic’s are the shortest. Having short cards is a big advantage since it means less code is required for each card and hopefully less debugging. In Forge if you wanted to change the damage code, you would have to update each card that dealt damage, while Wagic would only have to tweak the damage code that is used for all the cards, which is a big improvement.
(This is a contrived example but it is generally true. Cards in Forge always a global static method to deal damage, so the damage code could be updated easily but other aspects of cards such as targeting do not always use a global static method.)
On a side note, usually Forge’s cards are very long but I forgot about the scripting code that people like Rob Cashwalker has been writing. (Since Forge is an open source project, letting other people do some of the “hard stuff” is truly wonderful.) Forge’s Shock is only 5 lines, which is great, and probably wins the title of “shortest Shock code”. So in reality some of Forge’s cards are very long like Royal Assassin and some of the cards are very short like Shock.
Wagic – Royal Assassin
[card]
text={T}: Destroy target tapped creature.
id=129708
auto={T}:destroy target(creature[tapped])
name=Royal Assassin
rarity=R
type=Creature
mana={1}{B}{B}
power=1
subtype=Human Assassin
toughness=1
[/card]
Wagic – Shock
[card]Forge - Shock
text=Shock deals 2 damage to target creature or player.
target=creature,player
auto=Damage:2
id=129732
name=Shock
rarity=C
type=Instant
mana={R}
[/card]
Shock
R
Instant
no text
spDamageCP:2
Forge – Royal Assassin
if(cardName.equals("Royal Assassin"))
{
final Ability_Tap ability = new Ability_Tap(card)
{
public boolean canPlayAI()
{
CardList human =
CardFactoryUtil.AI_getHumanCreature(card, true);
human = human.filter(new CardListFilter()
{
public boolean addCard(Card c)
{return c.isTapped();}
});
CardListUtil.sortAttack(human);
CardListUtil.sortFlying(human);
if(0 < human.size())
setTargetCard(human.get(0));
return 0 < human.size();
}
public void resolve()
{
Card c = getTargetCard();
if(AllZone.GameAction.isCardInPlay(c) &&
c.isTapped() && CardFactoryUtil.canTarget(card, c) )
{
AllZone.GameAction.destroy(c);
}
}//resolve()
};//SpellAbility
Input target = new Input()
{
public void showMessage()
{
AllZone.Display.showMessage("Select
target tapped creature to destroy");
ButtonUtil.enableOnlyCancel();
}
public void selectButtonCancel() {stop();}
public void selectCard(Card c, PlayerZone zone)
{
if(!CardFactoryUtil.canTarget(card, c)){
AllZone.Display.showMessage(
"Cannot target this card (Shroud? Protection?).");
}
else if(c.isCreature() &&
zone.is(Constant.Zone.Play) && c.isTapped())
{
//tap ability
card.tap();
ability.setTargetCard(c);
AllZone.Stack.add(ability);
stop();
}
}//selectCard()
};//Input
card.addSpellAbility(ability);
ability.setDescription("tap: Destroy target
tapped creature.");
ability.setBeforePayMana(target);
}