Re: Programming a card

Posted:
18 Oct 2009, 21:12
by silly freak
actually, the point of the forge.properties file is that you don't have to copy your res folder. you can change the forge.properties file to point wherever you want. my folder structure looks like
- Code: Select all
forge
forge/versions
forge/versions/20091007
forge/versions/20091015
forge/versions/20091017
forge/res
the forge.properties files inside forge/versions/yyyymmdd, i change to
- Code: Select all
main--transparent-properties=../../res/main.properties
this way, I can keep my quest progress with new versions and don't have to move/copy/redownload the card pictures
(okay, that's not exactly what it looks for me; i just share the pics folder, just to be save from incompatible res files. but that's only my paranoia...)
Re: Programming a card

Posted:
19 Oct 2009, 19:08
by cyclope
Thanks for your help with using Eclipse...
But as Zerker said , can i use the abdamage keyword or no for
Nightscape Master ?
Re: Programming a card

Posted:
19 Oct 2009, 20:12
by DennisBergkamp
There's currently an abDamageCP keyword, but it also targets players, so I'm not sure if that would work for
Nightscape Master.
A possibility would be to create an abDamageP keyword

Re: Programming a card

Posted:
19 Oct 2009, 20:26
by Chris H.
`
Permanents which use the abDamageCP keyword will ask you to "Select target Creature, Player, or Planeswalker" as part of it's activation and targeting system. You can look at the abDamageCP keyword code. You may be able to copy and modify a portion of the code to use with the
Nightscape Master code.
Unfortunately, the keyword by itself will not give you quite the ability that you are looking for ... it is close.
Re: Programming a card

Posted:
20 Oct 2009, 18:49
by Rob Cashwalker
abDamageC, abDamageP and spDamageP represented too few cards that I knew how to do back then, many of them rely on variable information, which I didn't figure out how to program until spDraw and spDamageTgt.
spDamageTgt represents a way to code a single effect that may target either Creatures only, Players only or Creatures or Players (I know it asks the human for planeswalker targets, but I forgot about the AI). Previous keywords were separate because they had different AI due to the difference in targets or other details.
Basically, look for the sequence "CP" in the keyword string (k[0]) ELSE (important) look for "C" ELSE look for "P".
Set a final boolean to represent each specific case, and set up the AI to choose accordingly.
Players should be higher priority than creatures if their life would drop below a threshold of like 10 or so after the damage.
Walkers probably need to drop below 2 or 3, or half their printed loyalty, or (something else?).
Notice that the AI is broken up into smaller decision functions, each of which is used depending on the variant of damage spell.
Having overcome the slight AI differences, I'd like to go back over the keywords to make them work in a uniform fashion, which could eliminate a few thousand lines of code in just the keyword handling section, not to mention any explicit code for similar cards that needed it. Adding support for the variables and drawbacks also opens up all the cards that were ignored previously because of their difficulty in implementation.
I don't think we should go as far as unifying abilities and spells, because spells have their SpellAbilities cleared and permanents don't, but that might not be difficult to revise later as well.
Just consolidating the various forms of Pump into "abPump[Tgt] {cost}:{Boosts}" would be huge. ([Tgt] is optional if present, it's targeted, if not, it's a self-pump. If there is only one element in the Boosts parameter, then it's a keyword-only pump, if there are two elements, it's a PT-only pump, if there are three elements it's a PTK pump. Simple enough? This is how the spPumpTgt works, but without the support for variables)
Re: Programming a card

Posted:
20 Oct 2009, 18:59
by silly freak
I like eliminating redundant code - no, slightly wrong - I like redundant code getting deleted ^^
no, really, this is a good Idea. having a more uniform syntax for the different keywords makes it easier to add cards. currently, you can compare it with if every class was written in a different language. I hope you succeed
as for the planeswalkers, I'd say that a major targeting criterion is to drop the walker below his ultimate's cost
Re: Programming a card

Posted:
22 Oct 2009, 18:26
by cyclope
OK... if i really understand, i keep the code for the second ability of
Nightscape Master...
Could anybody tell me if the code for this second ability is correct...
Re: Programming a card

Posted:
23 Oct 2009, 19:16
by cyclope
I 've coded some more enchantments:
Reflexes- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Reflexes"))
{
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("First Strike");
}
}//execute()
};//Command
Command onUnEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.removeExtrinsicKeyword("First Strike");
}
}//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 **************************
in card.txt:
Reflexes
R
Enchantment Aura
Enchanted creature has first strike.
Enchant creature
Shield of Duty and Reason- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Shield of Duty and Reason"))
{
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("Protection from green");
crd.addExtrinsicKeyword("Protection from blue");
}
}//execute()
};//Command
Command onUnEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.removeExtrinsicKeyword("Protection from green");
crd.removeExtrinsicKeyword("Protection from blue");
}
}//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 **************************
in card.txt:
Shield of Duty and Reason
W
Enchantment Aura
Enchanted creature has first protection from green and from blue.
Enchant creature
Scavenged Weaponry- Code: Select all
Scavenged Weaponry
//*************** START *********** START **************************
if(cardName.equals("Scavenged Weaponry"))
{
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(1);
}
}//execute()
};//Command
Command onUnEnchant = new Command()
{
public void execute()
{
if (card.isEnchanting())
{
Card crd = card.getEnchanting().get(0);
crd.addSemiPermanentAttackBoost(-1);
crd.addSemiPermanentDefenseBoost(-1);
}
}//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 **************************
in card.txt:
Scavenged Weaponry
2 B
Enchantment Aura
Enchanted creature gets +1/+1.
Enchant creature
Cantrip
Maniacal Rage- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Maniacal Rage"))
{
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("This creature cannot block");
}
}//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("This creature cannot block");
}
}//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 **************************
in card.txt:
Maniacal Rage
1 R
Enchantment Aura
Enchanted creature gets +2/+2 and this creature cannot block.
Enchant creature
Magefire Wings- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Magefire 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(2);
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.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 **************************
in card.txt:
Magefire Wings
U R
Enchantment Aura
Enchanted creature gets +2/+0 and has flying.
Enchant creature
and I've coded the sorcery
Sacred Nectar:
- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Sacred Nectar")
{
SpellAbility spell = new Spell(card)
{
public boolean canPlay()
{
setStackDescription(card.getName() +" - " +card.getController() +" gains 4 life.");
return super.canPlay();
}
public void resolve()
{
PlayerLife life = AllZone.GameAction.getPlayerLife(card.getController());
life.addLife(4);
}
};
spell.setDescription("You gain 4 life.");
card.clearSpellAbility();
card.addSpellAbility(spell);
}//*************** END ************ END **************************
in cards.txt:
Sacred Nectar
1 W
Sorcery
You gain 4 life.
I hope i haven't made too much errors and i hope you'll enjoy these...
Re: Programming a card

Posted:
23 Oct 2009, 19:48
by Chris H.
Thank you, Cyclope. It is nice to have some more spells added to Forge.
Re: Programming a card

Posted:
25 Oct 2009, 13:49
by cyclope
I read the file GameActionUtil.java and i think we could add these cards:
Levitation:
- Code: Select all
In GameActionUtil.java:
- in public static void executeCardStateEffects() add : Levitation.execute();
- after }// executeCardStateEffects() add:
public static Command Levitation = new Command()
{
private static final long serialVersionUID = ;
CardList gloriousAnthemList = new CardList();
public void execute()
{
String keyword = "Flying";
CardList list = gloriousAnthemList;
Card c;
// reset all cards in list - aka "old" cards
for (int i = 0; i < list.size(); i++)
{
c = list.get(i);
c.removeExtrinsicKeyword(keyword);
}
list.clear();
PlayerZone[] zone = getZone("Levitation");
for (int outer = 0; outer < zone.length; outer++)
{
CardList creature = new CardList(zone[outer].getCards());
creature = creature.getType("Creature");
for (int i = 0; i < creature.size(); i++)
{
c = creature.get(i);
if (!c.getKeyword().contains(keyword))
{
c.addExtrinsicKeyword(keyword);
gloriousAnthemList.add(c);
}
}// for inner
}// for outer
}// execute()
};
and in" public static HashMap<String, Command> commands = new HashMap<String, Command>();
static {" add: commands.put("Levitation", Levitation);
and finally in StateBasedEffects.java, after "public void initStateBasedEffectsList()":
cardToEffectsList.put("Levitation", new String[] {"Levitation"});
and in cards.txt:
Levitation
2 U U
Enchantment
All creatures you control gain flying.
Knighthood:
- Code: Select all
In GameActionUtil.java:
- in public static void executeCardStateEffects() add : Knighthood.execute();
- after }// executeCardStateEffects() add:
public static Command Levitation = new Command()
{
private static final long serialVersionUID = ;
CardList gloriousAnthemList = new CardList();
public void execute()
{
String keyword = "First Strike";
CardList list = gloriousAnthemList;
Card c;
// reset all cards in list - aka "old" cards
for (int i = 0; i < list.size(); i++)
{
c = list.get(i);
c.removeExtrinsicKeyword(keyword);
}
list.clear();
PlayerZone[] zone = getZone("Knighthood");
for (int outer = 0; outer < zone.length; outer++)
{
CardList creature = new CardList(zone[outer].getCards());
creature = creature.getType("Creature");
for (int i = 0; i < creature.size(); i++)
{
c = creature.get(i);
if (!c.getKeyword().contains(keyword))
{
c.addExtrinsicKeyword(keyword);
gloriousAnthemList.add(c);
}
}// for inner
}// for outer
}// execute()
};
and in" public static HashMap<String, Command> commands = new HashMap<String, Command>();
static {" add: commands.put("Knighthood", Knighthood);
and finally in StateBasedEffects.java, after "public void initStateBasedEffectsList()":
cardToEffectsList.put("Knighthood", new String[] {"Knighthood"});
and in cards.txt:
Knighthood
2 W
Enchantment
All creatures you control gain first strike.
Boartusk Liege- Code: Select all
In GameActionUtil.java:
- in public static void executeCardStateEffects() add : Boartusk_Liege.execute();
- after }// executeCardStateEffects() add:
public static Command Boartusk_Liege = new Command()
{
private static final long serialVersionUID = ;
CardList gloriousAnthemList = new CardList();
public void execute()
{
CardList list = gloriousAnthemList;
Card c;
// reset all cards in list - aka "old" cards
for (int i = 0; i < list.size(); i++)
{
c = list.get(i);
if (CardUtil.getColors(c).contains(Constant.Color.Green)
&& !c.getName().equals("Boartusk Liege"))
{
c.addSemiPermanentAttackBoost(-1);
c.addSemiPermanentDefenseBoost(-1);
}
if (CardUtil.getColors(c).contains(Constant.Color.Red)
&& !c.getName().equals("Boartusk Liege"))
{
c.addSemiPermanentAttackBoost(-1);
c.addSemiPermanentDefenseBoost(-1);
}
}
// add +1/+1 to cards
list.clear();
PlayerZone[] zone = getZone("Boartusk Liege");
// for each zone found add +1/+1 to each card
for (int outer = 0; outer < zone.length; outer++)
{
CardList creature = new CardList(zone[outer].getCards());
creature = creature.getType("Creature");
for (int i = 0; i < creature.size(); i++)
{
c = creature.get(i);
if (CardUtil.getColors(c).contains(Constant.Color.Green)
&& !c.getName().equals("Boartusk Liege"))
{
c.addSemiPermanentAttackBoost(1);
c.addSemiPermanentDefenseBoost(1);
}
if (CardUtil.getColors(c).contains(Constant.Color.Red)
&& !c.getName().equals("Boartusk Liege"))
{
c.addSemiPermanentAttackBoost(1);
c.addSemiPermanentDefenseBoost(1);
}
gloriousAnthemList.add(c);
}// for inner
}// for outer
}// execute()
};// Boartusk_Liege
and in" public static HashMap<String, Command> commands = new HashMap<String, Command>();
static {" add: commands.put("Boartusk_Liege", Boartusk_Liege);
and finally in StateBasedEffects.java, after "public void initStateBasedEffectsList()":
cardToEffectsList.put("Boartusk Liege", new String[] {"Boartusk Liege"});
and in cards.txt:
Boartusk Liege
1 RG RG RG
Creature Goblin Knight
Other green creatures you control get +1/+1. Other red creatures you control get +1/+1.
3/4
Trample
Glen Elendra Liege- Code: Select all
In GameActionUtil.java:
- in public static void executeCardStateEffects() add : Glen_Elendra.execute();
- after }// executeCardStateEffects() add:
public static Command Glen_Elendra = new Command()
{
private static final long serialVersionUID = ;
CardList gloriousAnthemList = new CardList();
public void execute()
{
CardList list = gloriousAnthemList;
Card c;
// reset all cards in list - aka "old" cards
for (int i = 0; i < list.size(); i++)
{
c = list.get(i);
if (CardUtil.getColors(c).contains(Constant.Color.Blue)
&& !c.getName().equals("Glen Elendra Liege"))
{
c.addSemiPermanentAttackBoost(-1);
c.addSemiPermanentDefenseBoost(-1);
}
if (CardUtil.getColors(c).contains(Constant.Color.Black)
&& !c.getName().equals("Glen Elendra Liege"))
{
c.addSemiPermanentAttackBoost(-1);
c.addSemiPermanentDefenseBoost(-1);
}
}
// add +1/+1 to cards
list.clear();
PlayerZone[] zone = getZone("Glen Elendra Liege");
// for each zone found add +1/+1 to each card
for (int outer = 0; outer < zone.length; outer++)
{
CardList creature = new CardList(zone[outer].getCards());
creature = creature.getType("Creature");
for (int i = 0; i < creature.size(); i++)
{
c = creature.get(i);
if (CardUtil.getColors(c).contains(Constant.Color.Blue)
&& !c.getName().equals("Glen Elendra Liege"))
{
c.addSemiPermanentAttackBoost(1);
c.addSemiPermanentDefenseBoost(1);
}
if (CardUtil.getColors(c).contains(Constant.Color.Black)
&& !c.getName().equals("Glen Elendra Liege"))
{
c.addSemiPermanentAttackBoost(1);
c.addSemiPermanentDefenseBoost(1);
}
gloriousAnthemList.add(c);
}// for inner
}// for outer
}// execute()
};// Glen_Elendra
and in" public static HashMap<String, Command> commands = new HashMap<String, Command>();
static {" add: commands.put("Glen_Elendra", Glen_Elendra);
and finally in StateBasedEffects.java, after "public void initStateBasedEffectsList()":
cardToEffectsList.put("Glen Elendra Liege", new String[] {"Glen Elendra Liege"});
and in cards.txt:
Glen Elendra Liege
1 UB UB UB
Creature Goblin Knight
Other blue creatures you control get +1/+1. Other black creatures you control get +1/+1.
2/3
Flying
Thistledown Liege- Code: Select all
In GameActionUtil.java:
- in public static void executeCardStateEffects() add : Thistledown_Liege.execute();
- after }// executeCardStateEffects() add:
public static Command Thistledown_Liege= new Command()
{
private static final long serialVersionUID = ;
CardList gloriousAnthemList = new CardList();
public void execute()
{
CardList list = gloriousAnthemList;
Card c;
// reset all cards in list - aka "old" cards
for (int i = 0; i < list.size(); i++)
{
c = list.get(i);
if (CardUtil.getColors(c).contains(Constant.Color.Blue)
&& !c.getName().equals("Thistledown Liege"))
{
c.addSemiPermanentAttackBoost(-1);
c.addSemiPermanentDefenseBoost(-1);
}
if (CardUtil.getColors(c).contains(Constant.Color.White)
&& !c.getName().equals("Thistledown Liege"))
{
c.addSemiPermanentAttackBoost(-1);
c.addSemiPermanentDefenseBoost(-1);
}
}
// add +1/+1 to cards
list.clear();
PlayerZone[] zone = getZone("Thistledown Liege");
// for each zone found add +1/+1 to each card
for (int outer = 0; outer < zone.length; outer++)
{
CardList creature = new CardList(zone[outer].getCards());
creature = creature.getType("Creature");
for (int i = 0; i < creature.size(); i++)
{
c = creature.get(i);
if (CardUtil.getColors(c).contains(Constant.Color.Blue)
&& !c.getName().equals("Thistledown Liege"))
{
c.addSemiPermanentAttackBoost(1);
c.addSemiPermanentDefenseBoost(1);
}
if (CardUtil.getColors(c).contains(Constant.Color.White)
&& !c.getName().equals("Thistledown Liege"))
{
c.addSemiPermanentAttackBoost(1);
c.addSemiPermanentDefenseBoost(1);
}
gloriousAnthemList.add(c);
}// for inner
}// for outer
}// execute()
};// Thistledown_Liege
and in" public static HashMap<String, Command> commands = new HashMap<String, Command>();
static {" add: commands.put("Thistledown_Liege", Thistledown_Liege);
and finally in StateBasedEffects.java, after "public void initStateBasedEffectsList()":
cardToEffectsList.put("Thistledown Liege", new String[] {"Thistledown Liege"});
and in cards.txt:
Thistledown Liege
1 UB UB UB
Creature Goblin Knight
Other blue creatures you control get +1/+1. Other white creatures you control get +1/+1.
1/3
Flash
Could anybody tells me if it's right or wrong or if i have forgotten something...
Thanks for your help.
Re: Programming a card

Posted:
25 Oct 2009, 16:45
by Marek14
How about
Creakwood Liege? It could be cobbled from your code and
Bringer of the Green Dawn.
Mindwrack Liege might also be possible, by modifying
Elvish Piper.
Ashenmoor Liege,
Wilt-Leaf Liege and
Murkfiend Liege have more complex rules.
As for
Balefire Liege and
Deathbringer Liege, they should be possible (since there's
Fable of Wolf and Owl,
Quirion Dryad, and
Merrow Levitator). With those two, the whole cycle of Hatchlings might be easy to do as well:
Belligerent HatchlingNoxious HatchlingShrewd Hatchling (maybe not this one)
Sturdy HatchlingVoracious HatchlingGoing through cards.txt, I see that there is large amount of cards implemented that trigger on you playing a certain type of spell. Further possibilities are:
Eidolon cycle:
Aurora Eidolon (damage prevention, so probably not doable right now),
Enigma Eidolon,
Entropic Eidolon,
Sandstorm Eidolon,
Verdant EidolonSpiritcraft cards:
Baku Altar,
Blademane Baku,
Bounteous Kirin,
Briarknit Kami, Budoka Pupil (flip), Callow Jushi (flip),
Celestial Kirin,
Cloudhoof Kirin,
Cunning Bandit (flip),
Dreamcatcher,
Earthshaker,
Elder Pine of Jukai (soulshift), Faithful
Squire (flip),
Fiddlehead Kami,
Guardian of Solitude,
Haru-Onna,
Hikari, Twilight Guardian (blink), Hired Muscle (flip),
Horizon Seed,
Infernal Kirin,
Innocence Kami,
Jade Idol,
Kami of Fire's Roar,
Kami of Tattered Shoji,
Kami of the Hunt,
Kami of the Painted Road,
Kami of the Waning Moon,
Kemuri-Onna,
Kiri-Onna,
Kodama of the South Tree,
Kyoki, Sanity's Eclipse,
Loam Dweller,
Nikko-Onna,
Orbweaver Kumo,
Ore Gorger,
Oyobi, Who Split the Heavens,
Petalmane Baku,
Quillmane Baku,
Scaled Hulk,
Sire of the Storm,
Skullmane Baku,
Skyfire Kirin,
Soilshaper,
Soul of Magma,
Tallowisp,
Teller of Tales,
Thief of Hope (soulshift),
Waxmane Baku,
Yuki-OnnaOther cards from
Merrow Levitator cycle:
Ballynock Trapper,
Cinder Pyromancer,
Merrow Bonegnawer,
Nettle SentinelMimic cycle:
Battlegate Mimic,
Nightsky Mimic,
Riverfall Mimic,
Shorecrasher Mimic.
Woodlurker MimicDuo cycle:
Emberstrike Duo,
Gravelgill Duo,
Safehold Duo,
Tattermunge Duo.
Thistledown DuoBattlewand OakBlood FunnelCelestial AncientCircu, Dimir LobotomistCloven Casting (spell copying)
ContemplationCustoms DepotDoor of DestiniesDreamspoiler WitchesDwarven PatrolEndrek Sahr, Master Breeder (state trigger)
EquilibriumEyes of the Watcher (scry)
Faerie TauntingsFurious AssaultGelectrodeGlen Elendra PrankstersGlimpse of Nature (probably hard)
Gloryscale ViashinoHalcyon GlazeInspired SpriteKurgadonLeering EmblemLeonin BattlemageLeyline of Lightning (leyline ability)
Loyal GyrfalconLys Alana BowmasterLys Alana HuntmasterManaplasmMasked AdmirersMerrow ReejereyMindmoilMirari (spell copying)
Mishra, Artificer ProdigyMomir Vig, Simic VisionaryMountain Titan (hard)
OnslaughtPristine AngelPyromancer Ascension (spell copying)
Quest for the Holy RelicSpellweaver Volute (spell copying)
Thorntooth WitchTibor and LumiaTidespout TyrantVeilstone Amulet (beware, it doesn't give untargetability, it sets up a rule)
Voidmage Husher (ability countering)
Wee DragonautsWitch-Maw Nephilim
Re: Programming a card

Posted:
25 Oct 2009, 16:50
by DennisBergkamp
Cyclope,
Hmm,
Knighthood and
Levitation should work fine... however, the Lieges are much trickier than that, since they pump "Other" creatures of the same colors.
Your code might've worked if it was for a Legendary creature, but since there could be multiple Lieges in play, it's trickier.
Re: Programming a card

Posted:
25 Oct 2009, 19:38
by cyclope
Ok Dennis , i haven't thought about that it could have in play more than one of these Liege...
Have you got any idea to implement these cards ?
I also try to code
Stormscape Apprentice:
- Code: Select all
//*************** START *********** START **************************
if (cardName.equals("Stormscape Apprentice")
{
final SpellAbility ability = new Ability_Tap(card, "W")
{
private static final long serialVersionUID = ;
public void resolve()
{
Card c = getTargetCard();
c.tap();
}
public boolean canPlayAI() {return false;}
};//SpellAbility
final SpellAbility ability2 = new Ability_Tap(card, "B")
{
private static final long serialVersionUID = ;
public void resolve()
{
String opponent = AllZone.GameAction.getOpponent(card.getController());
AllZone.GameAction.getPlayerLife(opponent).subtractLife(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("W, tap: Tap target creature.");
ability.setBeforePayMana(CardFactoryUtil.input_targetCreature(ability));
card.addSpellAbility(ability2);
ability2.setDescription("B, tap: Target player loses 1 life.");
ability2.setStackDescription(card.getName() + " - Opponent loses 1 life.");
}//*************** END ************ END **************************
and
Stormscape Master:
- Code: Select all
//*************** START *********** START **************************
if (cardName.equals("Stormscape Master")
{
final SpellAbility ability = new Ability_Tap(card, "B B")
{
private static final long serialVersionUID = ;
public void resolve()
{
String opponent = AllZone.GameAction.getOpponent(card.getController());
AllZone.GameAction.getPlayerLife(opponent).subtractLife(2);
AllZone.GameAction.getPlayerLife(card.getController()).addLife(2);
}
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("B B, tap: Target player loses 2 life and you gain 2 life");
ability2.setStackDescription(card.getName() + " - Opponent loses 2 life."+card.getName()+card.getController()+" gains 2 life");
}//*************** END ************ END **************************
and in cards.txt:
Stormscape Master
2 U U
Creature Human Wizard
WW, tap : target creature gains protection from color of your choice until end of turn. BB, tap: target player loses 2 life and you gain 2 life.
2/2
TgtKpump W W T:Protection from white
TgtKpump W W T:Protection from red
TgtKpump W W T:Protection from black
TgtKpump W W T:Protection from green
TgtKpump W W T:Protection from blue
Did I succeeded or not ? (I'm not sure of the last lines...)
Re: Programming a card

Posted:
25 Oct 2009, 20:18
by DennisBergkamp
Yeah I think I know how to implement them, hopefully without bugs.
Stormscape Apprentice looks good

Re: Programming a card

Posted:
25 Oct 2009, 20:43
by DennisBergkamp
Oh, and actually I don't really "execute" these effects anymore with "
Levitation.execute()", instead add it to the big list at the bottom of GameActionUtil:
- Code: Select all
commands.put("Levitation", Levitation);
and then in StateBasedEffects.java:
- Code: Select all
cardToEffectsList.put("Levitation",new String[] {"Levitation"});