Programming a card
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
Re: Programming a card
by cyclope » 05 Oct 2009, 16:07
Thanks Zerker2000 for your help...
But is there an easiest way...
There are already cards like this in MTg : King Goblin , Champion Elf and i don't see that sort of code ...
Can anybody explain it to me ?
But is there an easiest way...
There are already cards like this in MTg : King Goblin , Champion Elf and i don't see that sort of code ...
Can anybody explain it to me ?
- cyclope
- Posts: 69
- Joined: 28 Sep 2009, 18:08
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by DennisBergkamp » 05 Oct 2009, 16:51
Ahh, these cards are trickier, because they are state based effects.cyclope wrote:Thanks Zerker2000 for your help...
But is there an easiest way...
There are already cards like this in MTg : King Goblin , Champion Elf and i don't see that sort of code ...
Can anybody explain it to me ?
They can be found in GameActionUtil.java (and stateBasedEffects.java). The way these cards are written is currently pretty ugly, but they seem to work.
GameActionUtil.java also includes cards that have upkeep effects (Howling Mine, Bitterblossom, ... ).
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by zerker2000 » 05 Oct 2009, 23:29
No offence intended, but:cyclope wrote:Thanks Zerker2000 for your help...
But is there an easiest way...
There are already cards like this in MTg : King Goblin , Champion Elf and i don't see that sort of code ...
Can anybody explain it to me ?
Easier way?! I just handed the code to you in a generic form on a silver platter!
O forest, hold thy wand'ring son
Though fears assail the door.
O foliage, cloak thy ravaged one
In vestments cut for war.
--Eladamri, the Seed of Freyalise
Though fears assail the door.
O foliage, cloak thy ravaged one
In vestments cut for war.
--Eladamri, the Seed of Freyalise
- zerker2000
- Programmer
- Posts: 569
- Joined: 09 May 2009, 21:40
- Location: South Pasadena, CA
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by cyclope » 06 Oct 2009, 17:17
I see no offence Zerker2000 but as i can't find the code in cardfactory.java , i thought it had an easier way ...
I was wrong and thank you all for your help you give to a guy who isn't a programmer but just a "copy and paste" coder...
I was wrong and thank you all for your help you give to a guy who isn't a programmer but just a "copy and paste" coder...
- cyclope
- Posts: 69
- Joined: 28 Sep 2009, 18:08
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by Chris H. » 06 Oct 2009, 17:41
`cyclope wrote:I see no offence Zerker2000 but as i can't find the code in cardfactory.java , i thought it had an easier way ...
I was wrong and thank you all for your help you give to a guy who isn't a programmer but just a "copy and paste" coder...
I am in a similar position. I downloaded Eclipse and learned how to build the the source code. The Eclipse site has a nice tutorial that will teach you how to use the application.
The Sun site has a nice Java tutorial ... reading the tutorial is helping me to learn Java. "Copy and paste" coding and making minor modifications to the existing code helps with the learning process.

-
Chris H. - Forge Moderator
- Posts: 6320
- Joined: 04 Nov 2008, 12:11
- Location: Mac OS X Yosemite
- Has thanked: 644 times
- Been thanked: 643 times
Re: Programming a card
by zerker2000 » 07 Oct 2009, 03:05
Helps start the learning process more than anythingChris H. wrote:"Copy and paste" coding and making minor modifications to the existing code helps with the learning process.

O forest, hold thy wand'ring son
Though fears assail the door.
O foliage, cloak thy ravaged one
In vestments cut for war.
--Eladamri, the Seed of Freyalise
Though fears assail the door.
O foliage, cloak thy ravaged one
In vestments cut for war.
--Eladamri, the Seed of Freyalise
- zerker2000
- Programmer
- Posts: 569
- Joined: 09 May 2009, 21:40
- Location: South Pasadena, CA
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by cyclope » 07 Oct 2009, 16:24
In the GameAtionUtil.java , i see some code relative to the "echo" capacity...
- Code: Select all
if (c.getIntrinsicKeyword().contains("Echo") && .....
- cyclope
- Posts: 69
- Joined: 28 Sep 2009, 18:08
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by DennisBergkamp » 07 Oct 2009, 16:26
Ah no, it's something I was experimenting with, it wouldn't do anything.
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by Chris H. » 07 Oct 2009, 17:37
`zerker2000 wrote:Seriously, all the basics have been done already: targeting at cards and players, Activated/static/triggered abilities, any effect in magic you can think of ... it usually Is a matter of finding a card that has an effect in the right situation, copying in the code of a card(or cards) that do the right thing, and then tweaking values to squash bugs and ensure proper amounts of effect.
I think that Rares did a wonderful job getting the project as far along as he did with little help from other people initially. And Rob's and Dennis' additions to the project have moved us forward.
cyclope has added several cards and I am awed by what he has been able to accomplish.
I hope that he will try Eclipse and I am sure that we can answer any more questions he may have about the Eclipse application.

Last edited by Chris H. on 07 Oct 2009, 18:41, edited 1 time in total.
-
Chris H. - Forge Moderator
- Posts: 6320
- Joined: 04 Nov 2008, 12:11
- Location: Mac OS X Yosemite
- Has thanked: 644 times
- Been thanked: 643 times
Re: Programming a card
by cyclope » 07 Oct 2009, 18:08
Thanks Dennis but I don't know if I'm very helpfull...
I will code simple cards that aren't in cards.tx and that are similar to other existing...
here there is an another enchant: Zephid's Embrace...
I hope my code is correct:
Can anybody explain me how I can generate this serialVersion UID for a card ?
I will code simple cards that aren't in cards.tx and that are similar to other existing...
here there is an another enchant: Zephid's Embrace...
I hope my code is correct:
- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Zephid's Embrace"))
{
final SpellAbility spell = new Spell(card)
{
public boolean canPlayAI()
{
CardList list = new CardList(AllZone.Computer_Play.getCards());
list = list.getType("Creature");
if(list.isEmpty())
return false;
//else
CardListUtil.sortAttack(list);
CardListUtil.sortFlying(list);
for (int i=0;i<list.size();i++) {
if (CardFactoryUtil.canTarget(card, list.get(i)))
{
setTargetCard(list.get(i));
return true;
}
}
return false;
}//canPlayAI()
public void resolve()
{
PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
play.add(card);
Card c = getTargetCard();
if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card, c) )
{
card.enchantCard(c);
System.out.println("Enchanted: " +getTargetCard());
}
}//resolve()
};//SpellAbility
card.clearSpellAbility();
card.addSpellAbility(spell);
Command onEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.addSemiPermanentAttackBoost(2);
crd.addSemiPermanentDefenseBoost(2);
crd.addExtrinsicKeyword("Shroud");
crd.addExtrinsicKeyword("Flying");
}
}//execute()
};//Command
Command onUnEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.addSemiPermanentAttackBoost(-2);
crd.addSemiPermanentDefenseBoost(-2);
crd.removeExtrinsicKeyword("Shroud");
crd.removeExtrinsicKeyword("Flying");
}
}//execute()
};//Command
Command onLeavesPlay = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
card.unEnchantCard(crd);
}
}
};
card.setEnchant(onEnchant);
card.setUnEnchant(onUnEnchant);
card.setLeavesPlay(onLeavesPlay);
spell.setBeforePayMana(CardFactoryUtil.input_targetCreature(spell));
}//*************** END ************ END **************************
- Code: Select all
private static final long serialVersionUID = 447190529377334168L;
Can anybody explain me how I can generate this serialVersion UID for a card ?
- cyclope
- Posts: 69
- Joined: 28 Sep 2009, 18:08
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by cyclope » 07 Oct 2009, 18:44
I try to code Silent Attendant :
- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Silent Attendant"))
{
final Ability_Tap ability = new Ability_Tap(card)
{
public void resolve()
{
AllZone.GameAction.getPlayerLife(card.getController()).addLife(1);
}
public boolean canPlayAI()
{
//computer should play ability if this creature doesn't attack
Combat c = ComputerUtil.getAttackers();
CardList list = new CardList(c.getAttackers());
//could this creature attack?, if attacks, do not use ability
return (! list.contains(card));
}
};//SpellAbility
card.addSpellAbility(ability);
ability.setDescription("tap: You gain 1 life.");
ability.setStackDescription(card.getName() + " - you gain 1 life.");
ability.setBeforePayMana(new Input_NoCost_TapAbility(ability));
}//*************** END ************ END **************************
- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Hero's Resolve"))
{
final SpellAbility spell = new Spell(card)
{
public boolean canPlayAI()
{
CardList list = new CardList(AllZone.Computer_Play.getCards());
list = list.getType("Creature");
if(list.isEmpty())
return false;
//else
CardListUtil.sortAttack(list);
CardListUtil.sortFlying(list);
for (int i=0;i<list.size();i++) {
if (CardFactoryUtil.canTarget(card, list.get(i)))
{
setTargetCard(list.get(i));
return true;
}
}
return false;
}//canPlayAI()
public void resolve()
{
PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
play.add(card);
Card c = getTargetCard();
if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card, c) )
{
card.enchantCard(c);
System.out.println("Enchanted: " +getTargetCard());
}
}//resolve()
};//SpellAbility
card.clearSpellAbility();
card.addSpellAbility(spell);
Command onEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.addSemiPermanentAttackBoost(1);
crd.addSemiPermanentDefenseBoost(5);
}
}//execute()
};//Command
Command onUnEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.addSemiPermanentAttackBoost(-1);
crd.addSemiPermanentDefenseBoost(-5);
}
}//execute()
};//Command
Command onLeavesPlay = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
card.unEnchantCard(crd);
}
}
};
card.setEnchant(onEnchant);
card.setUnEnchant(onUnEnchant);
card.setLeavesPlay(onLeavesPlay);
spell.setBeforePayMana(CardFactoryUtil.input_targetCreature(spell));
}//*************** END ************ END **************************
Last edited by cyclope on 07 Oct 2009, 19:10, edited 2 times in total.
- cyclope
- Posts: 69
- Joined: 28 Sep 2009, 18:08
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by Chris H. » 07 Oct 2009, 18:49
`cyclope wrote:I see many lines likein cardfactory.java and in other files...
- Code: Select all
private static final long serialVersionUID = 447190529377334168L;
Can anybody explain me how I can generate this serialVersion UID for a card ?
The serialVersion UID for a card are created in Eclipse. Dennis can have his copy of Eclipse create the serialVersion UID for a card when he adds your code submissions.
If and when you become familiar with the Eclipse package we can teach you how to create them from within Eclipse.

-
Chris H. - Forge Moderator
- Posts: 6320
- Joined: 04 Nov 2008, 12:11
- Location: Mac OS X Yosemite
- Has thanked: 644 times
- Been thanked: 643 times
Re: Programming a card
by cyclope » 07 Oct 2009, 19:07
Thanks Chris...
I wonder if this code for Whispersilk Cloak is good:
I wonder if this code for Whispersilk Cloak is good:
- Code: Select all
//*************** START *********** START **************************
if (cardName.equals("Whispersilk Cloak"))
{
final Ability equip = new Ability(card, "2")
{
public void resolve()
{
if (AllZone.GameAction.isCardInPlay(getTargetCard()) && CardFactoryUtil.canTarget(card, getTargetCard()) )
{
if (card.isEquipping())
{
Card crd = card.getEquipping().get(0);
if (crd.equals(getTargetCard()) )
return;
card.unEquipCard(crd);
}
card.equipCard(getTargetCard());
}
}
public boolean canPlay()
{
return AllZone.getZone(card).is(Constant.Zone.Play) &&
AllZone.Phase.getActivePlayer().equals(card.getController()) &&
(AllZone.Phase.getPhase().equals("Main1") || AllZone.Phase.getPhase().equals("Main2") );
}
public boolean canPlayAI()
{
return getCreature().size() != 0 && !card.isEquipping();
}
public void chooseTargetAI()
{
Card target = CardFactoryUtil.AI_getBestCreature(getCreature());
setTargetCard(target);
}
CardList getCreature()
{
CardList list = new CardList(AllZone.Computer_Play.getCards());
list = list.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
return c.isCreature() && (!CardFactoryUtil.AI_doesCreatureAttack(c)) && CardFactoryUtil.canTarget(card, c) &&
(! c.getKeyword().contains("Defender"));
}
});
// list.remove(card); // if mana-only cost, allow self-target
return list;
}//getCreature()
};//equip ability
Command onEquip = new Command()
{
public void execute()
{
if (card.isEquipping())
{
Card crd = card.getEquipping().get(0);
crd.addExtrinsicKeyword("Unblockable");
crd.addExtrinsicKeyword("Shroud");
}
}//execute()
};//Command
Command onUnEquip = new Command()
{
public void execute()
{
if (card.isEquipping())
{
Card crd = card.getEquipping().get(0);
crd.removeExtrinsicKeyword("Unblockable");
crd.removeExtrinsicKeyword("Shroud");
}
}//execute()
};//Command
Input runtime = new Input()
{
public void showMessage()
{
//get all creatures you control
CardList list = new CardList();
list.addAll(AllZone.Human_Play.getCards());
list = list.getType("Creature");
stopSetNext(CardFactoryUtil.input_targetSpecific(equip, list, "Select target creature to equip", true));
}
};//Input
equip.setBeforePayMana(runtime);
equip.setDescription("Equip: 2");
card.addSpellAbility(equip);
card.setEquip(onEquip);
card.setUnEquip(onUnEquip);
} //*************** END ************ END **************************
- cyclope
- Posts: 69
- Joined: 28 Sep 2009, 18:08
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by DennisBergkamp » 07 Oct 2009, 19:07
You're definitely being helpful! Every card (however simple) is a welcome addition.Thanks Dennis but I don't know if I'm very helpfull...
I will code simple cards that aren't in cards.tx and that are similar to other existing...
here there is an another enchant: Zephid's Embrace...
I hope my code is correct:
Especially the Auras you've been posting, we don't have that many of them in the game (yet), because it's something that was added fairly recently.
And yes exactly, those serialVersionIDs get generated by Eclipse.
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by cyclope » 09 Oct 2009, 15:50
Thanks Dennis...
Here is a Zendikar aura Nimbus Wings:
Here is a Zendikar aura Nimbus Wings:
- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Nimbus Wings"))
{
final SpellAbility spell = new Spell(card)
{
public boolean canPlayAI()
{
CardList list = new CardList(AllZone.Computer_Play.getCards());
list = list.getType("Creature");
if(list.isEmpty())
return false;
//else
CardListUtil.sortAttack(list);
CardListUtil.sortFlying(list);
for (int i=0;i<list.size();i++) {
if (CardFactoryUtil.canTarget(card, list.get(i)))
{
setTargetCard(list.get(i));
return true;
}
}
return false;
}//canPlayAI()
public void resolve()
{
PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
play.add(card);
Card c = getTargetCard();
if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card, c) )
{
card.enchantCard(c);
System.out.println("Enchanted: " +getTargetCard());
}
}//resolve()
};//SpellAbility
card.clearSpellAbility();
card.addSpellAbility(spell);
Command onEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.addSemiPermanentAttackBoost(1);
crd.addSemiPermanentDefenseBoost(2);
crd.addExtrinsicKeyword("Flying");
}
}//execute()
};//Command
Command onUnEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.addSemiPermanentAttackBoost(-1);
crd.addSemiPermanentDefenseBoost(-2);
crd.removeExtrinsicKeyword("Flying");
}
}//execute()
};//Command
Command onLeavesPlay = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
card.unEnchantCard(crd);
}
}
};
card.setEnchant(onEnchant);
card.setUnEnchant(onUnEnchant);
card.setLeavesPlay(onLeavesPlay);
spell.setBeforePayMana(CardFactoryUtil.input_targetCreature(spell));
}//*************** END ************ END **************************
- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Paralysing Grasp"))
{
final SpellAbility spell = new Spell(card)
{
public boolean canPlayAI()
{
CardList list = new CardList(AllZone.Computer_Play.getCards());
list = list.getType("Creature");
if(list.isEmpty())
return false;
//else
CardListUtil.sortAttack(list);
CardListUtil.sortFlying(list);
for (int i=0;i<list.size();i++) {
if (CardFactoryUtil.canTarget(card, list.get(i)))
{
setTargetCard(list.get(i));
return true;
}
}
return false;
}//canPlayAI()
public void resolve()
{
PlayerZone play = AllZone.getZone(Constant.Zone.Play, card.getController());
play.add(card);
Card c = getTargetCard();
if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card, c) )
{
card.enchantCard(c);
System.out.println("Enchanted: " +getTargetCard());
}
}//resolve()
};//SpellAbility
card.clearSpellAbility();
card.addSpellAbility(spell);
Command onEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.addExtrinsicKeyword("This card does not untap during your untap phase");
}
}//execute()
};//Command
Command onUnEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.removeExtrinsicKeyword("This card does not untap during your untap phase");
}
}//execute()
};//Command
Command onLeavesPlay = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
card.unEnchantCard(crd);
}
}
};
card.setEnchant(onEnchant);
card.setUnEnchant(onUnEnchant);
card.setLeavesPlay(onLeavesPlay);
spell.setBeforePayMana(CardFactoryUtil.input_targetCreature(spell));
}//*************** END ************ END **************************
- cyclope
- Posts: 69
- Joined: 28 Sep 2009, 18:08
- Has thanked: 0 time
- Been thanked: 0 time
Who is online
Users browsing this forum: No registered users and 39 guests