Programming a card
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
Re: Programming a card
by Triadasoul » 29 Nov 2009, 10:30
Looking at Treetop village i decided to rewrite it's code for other living lands that aren't implemented yet.
1. Should i add "c.setManaCost("R")" string to give a colour to creatures ?
2. Should i change serialVersionUID?
If the code is right, i'll write it for other living lands.
Ghitu Encampment
1. Should i add "c.setManaCost("R")" string to give a colour to creatures ?
2. Should i change serialVersionUID?
If the code is right, i'll write it for other living lands.
Ghitu Encampment
- Code: Select all
Cardfactory_Lands.java
else if(cardName.equals("Ghitu Encampment"))
{
card.addComesIntoPlayCommand(new Command()
{
private static final long serialVersionUID = -2246560994818997231L;
public void execute()
{
card.tap();
}
});
final Command eot1 = new Command()
{
private static final long serialVersionUID = -8535770979347971863L;
public void execute()
{
Card c = card;
c.setBaseAttack(0);
c.setBaseDefense(0);
c.removeType("Creature");
c.removeType("Warrior");
c.removeIntrinsicKeyword("First Strike");
}
};
final SpellAbility a1 = new Ability(card, "1 R")
{
public boolean canPlayAI()
{
return ! card.getType().contains("Creature");
}
public void resolve()
{
Card c = card;
c.setBaseAttack(2);
c.setBaseDefense(1);
//to prevent like duplication like "Creature Creature"
if(! c.getIntrinsicKeyword().contains("First Strike"))
{
c.addType("Creature");
c.addType("Warrior");
c.addIntrinsicKeyword("First Strike");
}
AllZone.EndOfTurn.addUntil(eot1);
}
};//SpellAbility
card.clearSpellKeepManaAbility();
card.addSpellAbility(a1);
a1.setStackDescription(card +" becomes a 2/1 creature with first strike until EOT");
Command paid1 = new Command() {
private static final long serialVersionUID = -6800983290478844750L;
public void execute() {AllZone.Stack.add(a1);}
};
a1.setBeforePayMana(new Input_PayManaCost_Ability(a1.getManaCost(), paid1));
================================================================================================
cards.txt:
Ghitu Encampment
R
Land
Ghitu Encampment comes into play tapped. 1R: Ghitu Encampment becomes a 2/1 red Warrior creature with first strike until end of turn. It's still a land.
tap: add R
=================================================================================================
cards_pictures.txt:
ghitu_encampment.jpg http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=106564
- Triadasoul
- Posts: 223
- Joined: 21 Jun 2008, 20:17
- Has thanked: 0 time
- Been thanked: 4 times
Re: Programming a card
by zerker2000 » 30 Nov 2009, 03:46
1. No, you should add a "Ghitu Encampment is red." keyword.
2. Probably, just change a random digit or something.
Notes about code:
a) Comes into play tapped is a keyword, so there is no need to code it in CardFactory.
b) The duplication code should check for each of Creature, Warrior, and fStrike separately, as first strike can be lost as an effect of an ability. Also, I think addType checks for duplicity anyways, and if not that should probable be fixed in addType instead of in each card using it.
c)The whole paid1 mess is redundant, since if it is left out, you will still pay the mana and play the ability as usual.
Also, aren't gatherer pictures to be avoided due to quality concerns?
2. Probably, just change a random digit or something.
Notes about code:
a) Comes into play tapped is a keyword, so there is no need to code it in CardFactory.
b) The duplication code should check for each of Creature, Warrior, and fStrike separately, as first strike can be lost as an effect of an ability. Also, I think addType checks for duplicity anyways, and if not that should probable be fixed in addType instead of in each card using it.
c)The whole paid1 mess is redundant, since if it is left out, you will still pay the mana and play the ability as usual.
Also, aren't gatherer pictures to be avoided due to quality concerns?
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 Triadasoul » 30 Nov 2009, 06:19
But it becomes red after activating the ability so i don't know how to use it as a keyword for now %)zerker2000 wrote:1. No, you should add a "Ghitu Encampment is red." keyword.
So should i use this code for that :zerker2000 wrote:Notes about code:
b) The duplication code should check for each of Creature, Warrior, and fStrike separately, as first strike can be lost as an effect of an ability. Also, I think addType checks for duplicity anyways, and if not that should probable be fixed in addType instead of in each card using it.
if(! c.getIntrinsicKeyword().contains("First Strike")) || ! c.gettype().contains("Warrior") || ! с.gettype().contains("Creature")) ?
I didn't understand about paid1, should i remove it at all ?zerker2000 wrote:c)The whole paid1 mess is redundant, since if it is left out, you will still pay the mana and play the ability as usual.
Also, aren't gatherer pictures to be avoided due to quality concerns?
What picture database should i use then?
Thank you for your feedback. And what about previously posted Captain of the Watch?
- Triadasoul
- Posts: 223
- Joined: 21 Jun 2008, 20:17
- Has thanked: 0 time
- Been thanked: 4 times
Re: Programming a card
by DennisBergkamp » 30 Nov 2009, 07:04
Actually, I think the first strike is fine, since it does addInstrinsicKeyword...
Captain of the Watch looks good, it *should* work, I'll add it into the code and test it...
2. Eclipse can generate these serialVersionUIDs automatically.
3. In the case of Captain of the Watch, these would be the only files that need changing.
EDIT: And hmm, unless I'm missing something here, using c.setManaCost("R"); should work alright too (then c.setManaCost(""); again), or Zerker's suggestion: c.addIntrinsicKeyword("Ghitu Encampment is red."); then c.removeIntrinsicKeyword("Ghitu Encampment is red."); when reset to a non-creature land again.
Captain of the Watch looks good, it *should* work, I'll add it into the code and test it...
1. You'll have to install something like Eclipse, import the source, make the code changes and compile + run the whole thing (to get started using eclipse, check out this thread: viewtopic.php?f=52&t=1093 ).Hi, i wanted to contribute, but i am a complete beginner in java, so i took some parts of the code and try to edit-compile them to suit Captain of the Watch needs. I have several noob questions about this process:
1. How can i give this code a try in game?
2. What does serialVersionUID variable mean ?
3. In witch else files should i add code except Gameactionutil, StateBasedeffects.java, Cardfactory_creatures.java, Cards.txt, card-picture.txt in this case?
2. Eclipse can generate these serialVersionUIDs automatically.
3. In the case of Captain of the Watch, these would be the only files that need changing.
EDIT: And hmm, unless I'm missing something here, using c.setManaCost("R"); should work alright too (then c.setManaCost(""); again), or Zerker's suggestion: c.addIntrinsicKeyword("Ghitu Encampment is red."); then c.removeIntrinsicKeyword("Ghitu Encampment is red."); when reset to a non-creature land again.
-
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 » 30 Nov 2009, 07:28
What I meant isTriadasoul wrote:So should i use this code for that :
if(! c.getIntrinsicKeyword().contains("First Strike")) || ! c.gettype().contains("Warrior") || ! с.gettype().contains("Creature")) ?
- Code: Select all
if(!c.getIntrinsicKeyword().contains("First Strike"))
c.addIntrinsicKeyword("First Strike");
if(!с.getTypes().contains("Creature"))
c.addType("Creature");
if(!c.getTypes().contains("Warrior"))
c.addType("Warrior");
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 Triadasoul » 30 Nov 2009, 10:35
So i re-edited ghitu encampment. Added: colour, duplication code, "comes tapped" keyword. I didn't remove paid1 because i didn't know with what to replace it in Input_PayManaCost_Ability. I've tested it for a while, it works pretty fine except the dialog box for choosing manasource/ability is narrow for 2 of them.

PS: how can i generate random serialVersionUID with eclipse? (didn't find it also)

PS: how can i generate random serialVersionUID with eclipse? (didn't find it also)
- Code: Select all
cards.txt
//*************** START *********** START **************************
else if(cardName.equals("Ghitu Encampment"))
{
final Command eot1 = new Command()
{
private static final long serialVersionUID = -8535770979347971863L;
public void execute()
{
Card c = card;
c.setBaseAttack(0);
c.setBaseDefense(0);
c.removeType("Creature");
c.removeType("Warrior");
c.removeIntrinsicKeyword("First Strike");
c.setManaCost("");
}
};
final SpellAbility a1 = new Ability(card, "1 R")
{
public boolean canPlayAI()
{
return ! card.getType().contains("Creature");
}
public void resolve()
{
Card c = card;
c.setBaseAttack(2);
c.setBaseDefense(1);
c.setManaCost("R");
//to prevent like duplication like "Creature Creature"
if(!c.getIntrinsicKeyword().contains("First Strike"))
c.addIntrinsicKeyword("First Strike");
if(!c.getType().contains("Creature"))
c.addType("Creature");
if(!c.getType().contains("Warrior"))
c.addType("Warrior");
AllZone.EndOfTurn.addUntil(eot1);
}
};//SpellAbility
card.clearSpellKeepManaAbility();
card.addSpellAbility(a1);
a1.setStackDescription(card +" becomes a 2/1 creature with first strike until EOT");
a1.setDescription("1 R: Ghitu Encampment becomes a 2/1 red Warrior creature with first strike until end of turn. It's still a land.");
Command paid1 = new Command() {
private static final long serialVersionUID = -6800983290478844750L;
public void execute() {AllZone.Stack.add(a1);}
};
a1.setBeforePayMana(new Input_PayManaCost_Ability(a1.getManaCost(), paid1));
}//*************** END ************ END **************************
================================================================================================
cards.txt:
Ghitu Encampment
no cost
Land
no text
Comes into play tapped.
tap: add R
====================================================================================================
card-pictures.txt:
http://www.wizards.com/global/images/magic/general/ghitu_encampment.jpg
Last edited by Triadasoul on 30 Nov 2009, 20:05, edited 2 times in total.
- Triadasoul
- Posts: 223
- Joined: 21 Jun 2008, 20:17
- Has thanked: 0 time
- Been thanked: 4 times
Re: Programming a card
by Triadasoul » 30 Nov 2009, 12:27
Stalking Stones:
- Code: Select all
cardfactory_lands.java:
//*************** START *********** START **************************
else if(cardName.equals("Stalking Stones"))
{
final SpellAbility a1 = new Ability(card, "6")
{
public boolean canPlayAI()
{
return ! card.getType().contains("Creature");
}
public void resolve()
{
Card c = card;
c.setBaseAttack(3);
c.setBaseDefense(3);
c.setManaCost("");
//to prevent like duplication like "Creature Creature"
if(!c.getType().contains("Elemental"))
c.addType("Elemental");
if(!c.getType().contains("Artifact"))
c.addType("Artifact");
if(!c.getType().contains("Creature"))
c.addType("Creature");
}
};//SpellAbility
card.clearSpellKeepManaAbility();
card.addSpellAbility(a1);
a1.setStackDescription(card +" becomes a 3/3 Elemental artifact creature that's still a land.");
a1.setDescription("6: Stalking Stones becomes a 3/3 Elemental artifact creature that's still a land. (This effect lasts indefinitely.)");
Command paid1 = new Command() {
private static final long serialVersionUID = -6800983290478844750L;
public void execute() {AllZone.Stack.add(a1);}
};
a1.setBeforePayMana(new Input_PayManaCost_Ability(a1.getManaCost(), paid1));
}//*************** END ************ END **************************
===============================================================================================================
cards.txt:
Stalking Stones
no cost
Land
no text
tap: add 1
==================================================================================================================
cards-pictures.txt
stalking_stones.jpg http://www.wizards.com/global/images/magic/general/stalking_stones.jpg
- Code: Select all
cardfactory_lands.java:
//*************** START *********** START **************************
else if(cardName.equals("Spawning Pool"))
{
final Command eot1 = new Command()
{
private static final long serialVersionUID = -8535770979347971863L;
public void execute()
{
Card c = card;
c.setBaseAttack(0);
c.setBaseDefense(0);
c.removeType("Creature");
c.removeType("Skeleton");
c.removeIntrinsicKeyword("RegenerateMe:B");
c.setManaCost("");
}
};
final SpellAbility a1 = new Ability(card, "1 B")
{
public boolean canPlayAI()
{
return ! card.getType().contains("Creature");
}
public void resolve()
{
Card c = card;
c.setBaseAttack(1);
c.setBaseDefense(1);
c.setManaCost("B");
//to prevent like duplication like "Creature Creature"
if(!c.getIntrinsicKeyword().contains("RegenerateMe:B"))
c.addIntrinsicKeyword("RegenerateMe:B");
if(!c.getType().contains("Creature"))
c.addType("Creature");
if(!c.getType().contains("Skeleton"))
c.addType("Skeleton");
AllZone.EndOfTurn.addUntil(eot1);
}
};//SpellAbility
card.clearSpellKeepManaAbility();
card.addSpellAbility(a1);
a1.setStackDescription(card +" becomes a 1/1 skeleton creature with B: regenerate this creature until EOT");
Command paid1 = new Command() {
private static final long serialVersionUID = -6800983290478844750L;
public void execute() {AllZone.Stack.add(a1);}
};
a1.setBeforePayMana(new Input_PayManaCost_Ability(a1.getManaCost(), paid1));
}//*************** END ************ END **************************
===============================================================================================================
cards.txt:
Spawning Pool
no cost
Land
no text
Comes into play tapped.
tap: add B
===============================================================================================================
Cards-pictures.txt
spawning_pool.jpg http://www.wizards.com/global/images/magic/general/spawning_pool.jpg
Last edited by Triadasoul on 30 Nov 2009, 20:04, edited 1 time in total.
- Triadasoul
- Posts: 223
- Joined: 21 Jun 2008, 20:17
- Has thanked: 0 time
- Been thanked: 4 times
Re: Programming a card
by DennisBergkamp » 30 Nov 2009, 17:58
What's happening here is that the ability gets added to the card, but the text of the ability is blank. So, taking the example of Stalking Stones:
- Code: Select all
//your current code:
card.clearSpellKeepManaAbility();
card.addSpellAbility(a1);
a1.setStackDescription(card +" becomes a 3/3 Elemental Artifact Creature that's still a land.");
//Add this line:
a1.setDescription("6: Stalking Stones becomes a 3/3 Elemental artifact creature that's still a land.");
- Code: Select all
a1.setDescription("1 R: Ghitu Encampment becomes a 2/1 red Warrior creature with first strike until end of turn. It's still a land.");
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by Triadasoul » 30 Nov 2009, 20:17
I've edited abovementioned code of Ghitu Encampment and Stalking Stones + card.txt description. But i've some complexities with Spawning Pool cause adding/removing its regeneration via addIntrinsicKeyword("RegenerateMe:B") doesn't seem to work. There is no such a choice in a dialog box. I tried to add it via addSpellAbility, but i don't know how to remove it cause Clearspellability doesn't understand argument. Is there another way to add/remove this regeneration?
- Triadasoul
- Posts: 223
- Joined: 21 Jun 2008, 20:17
- Has thanked: 0 time
- Been thanked: 4 times
Re: Programming a card
by DennisBergkamp » 30 Nov 2009, 21:15
Ah yes, the RegenerateMe keyword can't be added dynamically... But I think there's a removeSpellAbility(SpellAbility sa), zerker added this to support one of his cards, I can't remember which. But look at the code for Squirrel Nest (CardFactory_Auras), I'm pretty sure I used it there.
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by Triadasoul » 01 Dec 2009, 11:26
I've found it. What code should i take for duplicate prevenetion in this case ? Should i use getspellability for this and how? (for example regeneration is ability "a2")
And another existing card modification: Urza's Factory (copied from Vitu-Ghazi, the City-Tree)
And another existing card modification: Urza's Factory (copied from Vitu-Ghazi, the City-Tree)
- Code: Select all
cardfactory_lands.java:
//*************** START *********** START **************************
else if(cardName.equals("Urza's Factory"))
{
final Ability_Tap ability = new Ability_Tap(card, "7")
{
private static final long serialVersionUID = 1781653158406511188L;
public boolean canPlay()
{
if (AllZone.GameAction.isCardInPlay(card))
return true;
else
return false;
}
public void resolve()
{
String player = card.getController();
PlayerZone play = AllZone.getZone(Constant.Zone.Play, player);
//make token
Card c = new Card();
c.setOwner(card.getController());
c.setController(card.getController());
c.setName("Assembly-Worker");
c.setImageName("c 2 2 Assembly-Worker");
c.setManaCost("");
c.setToken(true);
c.addType("Artifact");
c.addType("Creature");
c.addType("Assembly-Worker");
c.setBaseAttack(2);
c.setBaseDefense(2);
play.add(c);
}
};
ability.setDescription("7, tap: Put a 2/2 colorless Assembly-Worker artifact creature token onto the battlefield.");
ability.setStackDescription(card.getName() + " - Put a 2/2 colorless Assembly-Worker artifact creature token onto the battlefield.");
card.addSpellAbility(ability);
//not sure what's going on here, maybe because it's a land it doesn't add the ability to the text?
//anyway, this does the trick:
//card.removeIntrinsicKeyword("tap: add 1");
card.setText(card.getSpellText() + "\r\n Put a 2/2 colorless Assembly-Worker artifact creature token onto the battlefield.");
//card.addIntrinsicKeyword("tap: add 1");
}//*************** END ************ END **************************
======================================================
cards.txt:
Urza's Factory
no cost
Land Urza's
no text
tap: add 1
======================================================
card-pictures.txt:
urzas_factory.jpg http://www.wizards.com/global/images/magic/general/urzas_factory.jpg
- Code: Select all
//*************** START *********** START **************************
else if(cardName.equals("Mishra's Factory"))
{
final Command eot1 = new Command()
{
private static final long serialVersionUID = -956566640027406078L;
public void execute()
{
Card c = card;
c.setBaseAttack(0);
c.setBaseDefense(0);
c.removeType("Artifact");
c.removeType("Creature");
c.removeType("Assembly-Worker");
}
};
final SpellAbility a1 = new Ability(card, "1")
{
public boolean canPlayAI()
{
return ! card.getType().contains("Creature");
//& ! card.isTapped() ;
//it turns into a creature, but doesn't attack
// return (! card.getKeyword().contains("Flying") &&
// (CardFactoryUtil.AI_getHumanCreature("Flying").isEmpty()));
}
public void resolve()
{
Card c = card;
c.setBaseAttack(2);
c.setBaseDefense(2);
//to prevent like duplication like "Creature Creature"
if(! c.getKeyword().contains("Creature"))
{
c.addType("Artifact");
c.addType("Creature");
c.addType("Assembly-Worker");
}
AllZone.EndOfTurn.addUntil(eot1);
}
};//SpellAbility
card.addSpellAbility(a1);
a1.setDescription("1: Mishra's Factory becomes a 2/2 Assembly-Worker artifact creature until end of turn. It's still a land.");
a1.setStackDescription(card +" - becomes a 2/2 creature until EOT");
Command paid1 = new Command() {
private static final long serialVersionUID = -6767109002136516590L;
public void execute() {AllZone.Stack.add(a1);}
};
a1.setBeforePayMana(new Input_PayManaCost_Ability(a1.getManaCost(), paid1));
final SpellAbility[] a2 = new SpellAbility[1];
final Command eot2 = new Command()
{
private static final long serialVersionUID = 6180724472470740160L;
public void execute()
{
Card c = a2[0].getTargetCard();
if(AllZone.GameAction.isCardInPlay(c))
{
c.addTempAttackBoost(-1);
c.addTempDefenseBoost(-1);
}
}
};
a2[0] = new Ability_Tap(card)
{
private static final long serialVersionUID = 3561450520225198222L;
public boolean canPlayAI()
{
return getAttacker() != null;
}
public void chooseTargetAI()
{
setTargetCard(getAttacker());
}
public Card getAttacker()
{
//target creature that is going to attack
Combat c = ComputerUtil.getAttackers();
CardList att = new CardList(c.getAttackers());
att.remove(card);
att.shuffle();
if(att.size() != 0)
return att.get(0);
else
return null;
}//getAttacker()
public void resolve()
{
Card c = a2[0].getTargetCard();
if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card,c) )
{
c.addTempAttackBoost(1);
c.addTempDefenseBoost(1);
AllZone.EndOfTurn.addUntil(eot2);
}
}//resolve()
};//SpellAbility
card.addSpellAbility(a2[0]);
a2[0].setDescription("tap: Target Assembly-Worker gets +1/+1 until end of turn.");
@SuppressWarnings("unused") // target unused
final Input target = new Input()
{
private static final long serialVersionUID = 8913477363141356082L;
public void showMessage()
{
ButtonUtil.enableOnlyCancel();
AllZone.Display.showMessage("Select Assembly-Worker to get +1/+1");
}
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() && c.getType().contains("Assembly-Worker"))
{
card.tap();
AllZone.Human_Play.updateObservers();
a2[0].setTargetCard(c);//since setTargetCard() changes stack description
a2[0].setStackDescription(c +" gets +1/+1 until EOT");
AllZone.InputControl.resetInput();
AllZone.Stack.add(a2[0]);
}
}//selectCard()
public void selectButtonCancel()
{
card.untap();
stop();
}
};//Input target
a2[0].setBeforePayMana(CardFactoryUtil.input_targetType(a2[0], "Assembly-Worker"));
}//*************** END ************ END **************************
- Code: Select all
Cardfactory_lands:
//*************** START *********** START **************************
else if(cardName.equals("Goblin Burrows"))
{
final SpellAbility[] a2 = new SpellAbility[1];
final Command eot2 = new Command()
{
private static final long serialVersionUID = 6180724472470740160L;
public void execute()
{
Card c = a2[0].getTargetCard();
if(AllZone.GameAction.isCardInPlay(c))
{
c.addTempAttackBoost(-2);
}
}
};
a2[0] = new Ability_Tap(card, "1 R")
{
private static final long serialVersionUID = 3561450520225198222L;
public boolean canPlayAI()
{
return getAttacker() != null;
}
public void chooseTargetAI()
{
setTargetCard(getAttacker());
}
public Card getAttacker()
{
//target creature that is going to attack
Combat c = ComputerUtil.getAttackers();
CardList att = new CardList(c.getAttackers());
att.remove(card);
att.shuffle();
if(att.size() != 0)
return att.get(0);
else
return null;
}//getAttacker()
public void resolve()
{
Card c = a2[0].getTargetCard();
if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card,c) )
{
c.addTempAttackBoost(2);
AllZone.EndOfTurn.addUntil(eot2);
}
}//resolve()
};//SpellAbility
card.addSpellAbility(a2[0]);
a2[0].setDescription("1 R, tap: Target Goblin gets +2/+0 until end of turn.");
@SuppressWarnings("unused") // target unused
final Input target = new Input()
{
private static final long serialVersionUID = 8913477363141356082L;
public void showMessage()
{
ButtonUtil.enableOnlyCancel();
AllZone.Display.showMessage("Select Goblin to get +2/+0");
}
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() && c.getType().contains("Goblin"))
{
card.tap();
AllZone.Human_Play.updateObservers();
a2[0].setTargetCard(c);//since setTargetCard() changes stack description
a2[0].setStackDescription(c +" gets +2/+0 until EOT");
AllZone.InputControl.resetInput();
AllZone.Stack.add(a2[0]);
}
}//selectCard()
public void selectButtonCancel()
{
card.untap();
stop();
}
};//Input target
a2[0].setBeforePayMana(CardFactoryUtil.input_targetType(a2[0], "Goblin"));
}//*************** END ************ END **************************
====================================================
cards.txt:
Goblin Burrows
no cost
Land
no text
tap: add 1
====================================================
card-pictures.txt:
goblin_burrows.jpg http://www.wizards.com/global/images/magic/general/goblin_burrows.jpg
- Code: Select all
cardfactory_lands:
//*************** START *********** START **************************
else if(cardName.equals("Skarrg, the Rage Pits"))
{
final SpellAbility[] a2 = new SpellAbility[1];
final Command eot2 = new Command()
{
private static final long serialVersionUID = 6180724472470740160L;
public void execute()
{
Card c = a2[0].getTargetCard();
if(AllZone.GameAction.isCardInPlay(c))
{
c.addTempAttackBoost(-1);
c.addTempDefenseBoost(-1);
c.removeIntrinsicKeyword("Trample");
}
}
};
a2[0] = new Ability_Tap(card, "G R")
{
private static final long serialVersionUID = 3561450520225198222L;
public boolean canPlayAI()
{
return getAttacker() != null;
}
public void chooseTargetAI()
{
setTargetCard(getAttacker());
}
public Card getAttacker()
{
//target creature that is going to attack
Combat c = ComputerUtil.getAttackers();
CardList att = new CardList(c.getAttackers());
att.remove(card);
att.shuffle();
if(att.size() != 0)
return att.get(0);
else
return null;
}//getAttacker()
public void resolve()
{
Card c = a2[0].getTargetCard();
if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card,c) )
{
c.addTempAttackBoost(1);
c.addTempDefenseBoost(1);
c.addIntrinsicKeyword("Trample");
AllZone.EndOfTurn.addUntil(eot2);
}
}//resolve()
};//SpellAbility
card.addSpellAbility(a2[0]);
a2[0].setDescription("G R, tap: Target creature gets +1/+1 and gains trample until end of turn.");
@SuppressWarnings("unused") // target unused
final Input target = new Input()
{
private static final long serialVersionUID = 8913477363141356082L;
public void showMessage()
{
ButtonUtil.enableOnlyCancel();
AllZone.Display.showMessage("Select Creature to get +1/+1 and trample");
}
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())
{
card.tap();
AllZone.Human_Play.updateObservers();
a2[0].setTargetCard(c);//since setTargetCard() changes stack description
a2[0].setStackDescription(c +" gets +1/+1 and trample until EOT");
AllZone.InputControl.resetInput();
AllZone.Stack.add(a2[0]);
}
}//selectCard()
public void selectButtonCancel()
{
card.untap();
stop();
}
};//Input target
a2[0].setBeforePayMana(CardFactoryUtil.input_targetType(a2[0], "Creature"));
}//*************** END ************ END **************************
====================================================
cards.txt
Skarrg, the Rage Pits
no cost
Land
no text
tap: add 1
====================================================
card-pictures.txt:
skarrg_the_rage_pits.jpg http://www.wizards.com/global/images/magic/general/skarrg_the_rage_pits.jpg
- Code: Select all
carfactory_lands:
//*************** START *********** START **************************
else if(cardName.equals("Daru Encampment"))
{
final SpellAbility[] a2 = new SpellAbility[1];
final Command eot2 = new Command()
{
private static final long serialVersionUID = 6180724472470740160L;
public void execute()
{
Card c = a2[0].getTargetCard();
if(AllZone.GameAction.isCardInPlay(c))
{
c.addTempAttackBoost(-1);
c.addTempDefenseBoost(-1);
}
}
};
a2[0] = new Ability_Tap(card, "W")
{
private static final long serialVersionUID = 3561450520225198222L;
public boolean canPlayAI()
{
return getAttacker() != null;
}
public void chooseTargetAI()
{
setTargetCard(getAttacker());
}
public Card getAttacker()
{
//target creature that is going to attack
Combat c = ComputerUtil.getAttackers();
CardList att = new CardList(c.getAttackers());
att.remove(card);
att.shuffle();
if(att.size() != 0)
return att.get(0);
else
return null;
}//getAttacker()
public void resolve()
{
Card c = a2[0].getTargetCard();
if(AllZone.GameAction.isCardInPlay(c) && CardFactoryUtil.canTarget(card,c) )
{
c.addTempAttackBoost(1);
c.addTempDefenseBoost(1);
AllZone.EndOfTurn.addUntil(eot2);
}
}//resolve()
};//SpellAbility
card.addSpellAbility(a2[0]);
a2[0].setDescription("W, tap: Target Soldier gets +1/+1 until end of turn.");
@SuppressWarnings("unused") // target unused
final Input target = new Input()
{
private static final long serialVersionUID = 8913477363141356082L;
public void showMessage()
{
ButtonUtil.enableOnlyCancel();
AllZone.Display.showMessage("Select Soldier to get +1/+1");
}
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() && c.getType().contains("Soldier"))
{
card.tap();
AllZone.Human_Play.updateObservers();
a2[0].setTargetCard(c);//since setTargetCard() changes stack description
a2[0].setStackDescription(c +" gets +1/+1 until EOT");
AllZone.InputControl.resetInput();
AllZone.Stack.add(a2[0]);
}
}//selectCard()
public void selectButtonCancel()
{
card.untap();
stop();
}
};//Input target
a2[0].setBeforePayMana(CardFactoryUtil.input_targetType(a2[0], "Soldier"));
}//*************** END ************ END **************************
====================================================
cards.txt:
Daru Encampment
no cost
Land
no text
tap: add 1
====================================================
card-pictures.txt:
Daru_Encampment.jpg http://www.wizards.com/global/images/magic/general/Daru_Encampment.jpg
- Triadasoul
- Posts: 223
- Joined: 21 Jun 2008, 20:17
- Has thanked: 0 time
- Been thanked: 4 times
Re: Programming a card
by DennisBergkamp » 01 Dec 2009, 17:57
Cool! Thanks Triad, I'll add these 
Yes, apparently the AI doesn't attack with living lands (canPlayAI returns false)... not sure if there's a good reason for this. It's possible originally the AI would tap its living lands creatures for mana to pay for their own abilities
This might still be the problem...

Yes, apparently the AI doesn't attack with living lands (canPlayAI returns false)... not sure if there's a good reason for this. It's possible originally the AI would tap its living lands creatures for mana to pay for their own abilities

-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by DennisBergkamp » 01 Dec 2009, 18:07
As for the duplicate detection, you probably have to do some hack like this:
- Code: Select all
boolean hasRegen = false;
SpellAbility[] sas = card.getSpellAbility();
for (SpellAbility sa : sas)
{
if(sa.toString().equals("B: Regenerate this creature.")) //this is essentially ".getDescription()"
hasRegen = true;
}
if (!hasRegen){
//add regenAbility here, make sure you setDescription of the regenAbility to "B: Regenerate this creature."
}
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: Programming a card
by Rob Cashwalker » 01 Dec 2009, 18:09
How does the AI choose mana sources to pay for abilities? Somewhere there must be code that loops through a CardList of all possible mana sources. Sort the list such that man-lands are at the end. (assuming the AI keeps using list.get(0) for each needed mana)DennisBergkamp wrote:Cool! Thanks Triad, I'll add these
Yes, apparently the AI doesn't attack with living lands (canPlayAI returns false)... not sure if there's a good reason for this. It's possible originally the AI would tap its living lands creatures for mana to pay for their own abilitiesThis might still be the problem...
The other issue will be that the AI would need to know if the man-land would be useful to attack with.... which normally is calculated in CardFactoryUtil.AI_doesCreatureAttack(card). But the man land isn't animated yet, therefore it will always return false.
The Force will be with you, Always.
-
Rob Cashwalker - Programmer
- Posts: 2167
- Joined: 09 Sep 2008, 15:09
- Location: New York
- Has thanked: 5 times
- Been thanked: 40 times
Re: Programming a card
by DennisBergkamp » 01 Dec 2009, 18:24
Well, it should actually disregard the man-land (what if it only has 1 or 2 manasources available?).
And yes, another possibility as you said, is the doesCreatureAttack() returning false. What we could do is add some method that predicts this (wouldCreatureAttack()
? )
And yes, another possibility as you said, is the doesCreatureAttack() returning false. What we could do is add some method that predicts this (wouldCreatureAttack()

-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Who is online
Users browsing this forum: No registered users and 46 guests