Code from slapshot5
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
55 posts
• Page 2 of 4 • 1, 2, 3, 4
Re: Code from slapshot5
by slapshot5 » 09 Apr 2010, 05:22
This is Gaea's Avenger from Antiquities
GameActionUtil.java
GameActionUtil.java
- Code: Select all
public static Command Gaeas_Avenger = new Command() {
private static final long serialVersionUID = 1987511098173387864L;
public void execute() {
// get all creatures
CardList list = new CardList();
list.addAll(AllZone.Human_Play.getCards());
list.addAll(AllZone.Computer_Play.getCards());
list = list.getName("Gaea's Avenger");
for(int i = 0; i < list.size(); i++) {
Card c = list.get(i);
c.setBaseAttack(countOppArtifacts(c)+1);
c.setBaseDefense(c.getBaseAttack());
}
}// execute()
private int countOppArtifacts(Card c) {
PlayerZone play = AllZone.getZone(Constant.Zone.Play, AllZone.GameAction.getOpponent(c.getController()));
CardList artifacts = new CardList(play.getCards());
artifacts = artifacts.getType("Artifact");
return artifacts.size();
}
};
- Code: Select all
cardToEffectsList.put("Gaea's Avenger", new String[] {"Gaeas_Avenger"});
- Code: Select all
commands.put("Gaeas_Avenger", Gaeas_Avenger);
- Code: Select all
Gaea's Avenger
1 G G
Creature Treefolk
Gaea's Avenger's power and toughness are each equal to 1 plus the number of artifacts your opponents control.
1/1
- Code: Select all
http://www.wizards.com/global/images/magic/general/gaeas_avenger.jpg
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: Code from slapshot5
by slapshot5 » 10 Apr 2010, 05:11
First pass code for Diamond Valley from Arabian Nights:
CardFactory_Lands.java:
Thanks,
-slapshot5
CardFactory_Lands.java:
- Code: Select all
//*************** START *********** START **************************
else if(cardName.equals("Diamond Valley")) {
final Ability_Tap ability = new Ability_Tap(card, "0") {
private static final long serialVersionUID = -6589125674356046586L;
@Override
public boolean canPlayAI() {
CardList list = new CardList(AllZone.Computer_Play.getCards());
list = list.filter(new CardListFilter() {
public boolean addCard(Card c) {
return c.isCreature();
}
});
if(list.size() > 0 && AllZone.Computer_Life.getLife() < 5 ) setTargetCard(CardFactoryUtil.AI_getBestCreature(list, card));
return list.size() > 0;
}
@Override
public void resolve() {
Card c = getTargetCard();
if(c != null) {
if(CardFactoryUtil.canTarget(card, c) && c.isCreature() ) {
AllZone.GameAction.addLife(c.getController(),c.getNetDefense());
AllZone.GameAction.sacrifice(c);
}
}
}
};
Input runtime = new Input() {
private static final long serialVersionUID = -7649177692384343204L;
@Override
public void showMessage() {
CardList choice = new CardList();
final String player = AllZone.Phase.getActivePlayer();
PlayerZone play = AllZone.getZone(Constant.Zone.Play, player);
choice.addAll(play.getCards());
choice = choice.getType("Creature");
choice = choice.filter(new CardListFilter() {
public boolean addCard(Card c) {
return (c.isCreature());
}
});
stopSetNext(CardFactoryUtil.input_targetSpecific(ability, choice,
"Select target creature:", true, false));
}
};
card.addSpellAbility(ability);
ability.setBeforePayMana(runtime);
}//*************** END ************ END **************************
- Code: Select all
Diamond Valley
no cost
Land
tap: Sacrifice a creature: You gain life equal to the sacrificed creature's toughness.
- Code: Select all
http://www.wizards.com/global/images/magic/general/diamond_valley.jpg
Thanks,
-slapshot5
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: Code from slapshot5
by slapshot5 » 10 Apr 2010, 06:10
This is People of the Woods from The Dark:
GameActionUtil.java
GameActionUtil.java
- Code: Select all
public static Command People_of_the_Woods = new Command() {
private static final long serialVersionUID = 1987554325573387864L;
public void execute() {
// get all creatures
CardList list = new CardList();
list.addAll(AllZone.Human_Play.getCards());
list.addAll(AllZone.Computer_Play.getCards());
list = list.getName("People of the Woods");
for(int i = 0; i < list.size(); i++) {
Card c = list.get(i);
c.setBaseAttack(1);
c.setBaseDefense(countForests(c));
}
}// execute()
private int countForests(Card c) {
PlayerZone play = AllZone.getZone(
Constant.Zone.Play, c.getController());
CardList forests = new CardList(play.getCards());
forests = forests.getType("Forest");
return forests.size();
}
};
- Code: Select all
cardToEffectsList.put("People of the Woods", new String[] {"People_of_the_Woods"});
- Code: Select all
commands.put("People_of_the_Woods", People_of_the_Woods);
- Code: Select all
People of the Woods
G G
Creature Human
People of the Woods's toughness is equal to the number of Forests you control.
1/0
- Code: Select all
http://www.wizards.com/global/images/magic/general/people_of_the_woods.jpg
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: Code from slapshot5
by slapshot5 » 10 Apr 2010, 19:09
Here is Jandor's Saddlebags
CardFactory.java:
CardFactory.java:
- Code: Select all
//*****************************START*******************************
if(cardName.equals("Jandor's Saddlebags")) {
/* Assuing the Rules state that this can target an untapped card,
* but it won't do anything useful
*
* This would bring the ruling in line with Icy Manipulator
* */
final Ability_Tap ability = new Ability_Tap(card, "3") {
private static final long serialVersionUID = 6349074098650621348L;
public boolean canPlayAI() {
return false;
}
public void chooseTargetAI() {
//setTargetCard(c);
}//chooseTargetAI()
public void resolve() {
if(AllZone.GameAction.isCardInPlay(getTargetCard())) {
getTargetCard().untap();
}
}
};//SpellAbility
card.addSpellAbility(ability);
ability.setDescription("3, tap: Untap target creature.");
ability.setBeforePayMana(CardFactoryUtil.input_targetType(ability, "Creature"));
}//Jandor's Saddlebags
//****************END*******END***********************
- Code: Select all
Jandor's Saddlebags
2
Artifact
no text
- Code: Select all
http://www.wizards.com/global/images/magic/general/jandors_saddlebags.jpg
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: Code from slapshot5
by jim » 10 Apr 2010, 23:34
I like your implementation, and the side effect mechanism. When I played with it, I found that when I select a spell to cast and tap City of Brass to pay the mana cost, the point of damage goes on the stack right away. If you then hit 'cancel' to stop casting the spell you still have taken the point of damage, even though City of Brass untaps. If you tap it again to pay the cost of a different spell you'll take another point of damage.slapshot5 wrote:First pass at City of Brass
<snip>
(Also, note this provides a general mechanism for cards that have a side effect when tapped.)
-slapshot5
One way to do avoid this would be to defer side effect execution until the spell casting is done. It's hard to do because there are a couple of layers involved (Input_PayManaCostUtil.tapCard calls GameAction.playSpellAbility which calls tap()). We could have Input_PayManaCostUtil call a new routine called GameAction.playSpellAbilitySideEffectFree which calls tapSideEffectFree(), and then have Input_PayManaCost store a list of cards that were tapped. It would then call executeTapSideEffects on these cards afterward. Does anyone else have a better idea how to deal with this?
- jim
- Posts: 46
- Joined: 19 Feb 2010, 01:46
- Location: Sunny New England
- Has thanked: 0 time
- Been thanked: 0 time
Re: Code from slapshot5
by slapshot5 » 11 Apr 2010, 04:52
I think I have Winter Orb working:
Add this method to Input_Untap.java:
I believe this is on the card request list.
-slapshot5
Add this method to Input_Untap.java:
- Code: Select all
private boolean isWinterOrbInEffect() {
CardList all = new CardList();
all.addAll(AllZone.Human_Play.getCards());
all.addAll(AllZone.Computer_Play.getCards());
all = all.filter(new CardListFilter() {
public boolean addCard(Card c) {
return c.getName().equals("Winter Orb");
}
});
//if multiple Winter Orbs, check that at least 1 of them is untapped
for( int i = 0; i < all.size(); i++ ) {
if( all.get(i).isUntapped() ) {
return true;
}
}
return false;
}
- Code: Select all
private void doUntap()
{
PlayerZone p = AllZone.getZone(Constant.Zone.Play, AllZone.Phase.getActivePlayer());
CardList list = new CardList(p.getCards());
list = list.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
if( isMarbleTitanInPlay() && isWinterOrbInEffect() ) {
return !c.isLand() && c.getNetAttack() < 3;
}
else if( isWinterOrbInEffect() ) {
return !c.isLand();
}
else if (isMarbleTitanInPlay()) {
return c.getNetAttack() < 3;
}
return true;
}
});
for(Card c : list) {
if(!c.getKeyword().contains("This card doesn't untap during your untap step.")
&& !c.getKeyword().contains("This card doesn't untap during your next untap step.")) c.untap();
else c.removeExtrinsicKeyword("This card doesn't untap during your next untap step.");
}
if( isWinterOrbInEffect() ) {
if( AllZone.Phase.getActivePlayer().equals(Constant.Player.Computer) ) {
//search for lands the computer has and only untap 1
CardList landList = new CardList(p.getCards());
landList = landList.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
return c.isLand() && c.isTapped();
}
});
if( landList.size() > 0 ) {
landList.get(0).untap();
}
}
else {
Input target = new Input() {
private static final long serialVersionUID = 6653677835629939465L;
public void showMessage() {
AllZone.Display.showMessage("Winter Orb - Select one tapped land to untap");
ButtonUtil.enableOnlyCancel();
}
public void selectButtonCancel() {stop();}
public void selectCard(Card c, PlayerZone zone) {
if(c.isLand() && zone.is(Constant.Zone.Play) && c.isTapped()) {
c.untap();
stop();
}
}//selectCard()
};//Input
CardList landList = new CardList(p.getCards());
landList = landList.filter(new CardListFilter()
{
public boolean addCard(Card c)
{
return c.isLand() && c.isTapped();
}
});
if( landList.size() > 0 ) {
AllZone.InputControl.setInput(target);
}
}
}
}//end doUntap
- Code: Select all
Winter Orb
2
Artifact
As long as Winter Orb is untapped, players can't untap more than one land during their untap steps.
- Code: Select all
http://www.wizards.com/global/images/magic/general/winter_orb.jpg
I believe this is on the card request list.
-slapshot5
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: Code from slapshot5
by DennisBergkamp » 11 Apr 2010, 07:26
Very cool, Winter Orb is definitely a classic 
I guess it didn't make it into the latest Beta (I just posted it), but that's probably a good thing: we can give it some more testing now.

I guess it didn't make it into the latest Beta (I just posted it), but that's probably a good thing: we can give it some more testing now.
-
DennisBergkamp - AI Programmer
- Posts: 2602
- Joined: 09 Sep 2008, 15:46
- Has thanked: 0 time
- Been thanked: 0 time
Re: Code from slapshot5
by zerker2000 » 11 Apr 2010, 12:09
I'd say default Ability_Mana.undo() should have a line saying "if isTapAbility Stack.remove(tapTriggerAbility)".
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: Code from slapshot5
by jim » 11 Apr 2010, 12:27
I like that. To do it, we'd need to have the tapTriggerAbility added to the cards when they are created, because otherwise Ability_Mana can't find them...but this is probably a good idea anyway.zerker2000 wrote:I'd say default Ability_Mana.undo() should have a line saying "if isTapAbility Stack.remove(tapTriggerAbility)".
- jim
- Posts: 46
- Joined: 19 Feb 2010, 01:46
- Location: Sunny New England
- Has thanked: 0 time
- Been thanked: 0 time
Re: Code from slapshot5
by zerker2000 » 12 Apr 2010, 05:11
Actually, I'm pretty sure the stack doesn't error out on remove(null), so that could just be added as a line to Card(and if it does, put a check in undo()).
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: Code from slapshot5
by jim » 12 Apr 2010, 09:53
You're right -- that will handle cards without tapTriggerAbilities. I was pointing out that in the present implementation neither the card nor the spell ability have a link back to the tapTriggerAbility (unless I missed something). It's created on-the-fly in the 'executeTapTrigger' routine. I think we need to change that so they're created in the CardFactories and added to the card, in order to have an 'undo' capability.zerker2000 wrote:Actually, I'm pretty sure the stack doesn't error out on remove(null), so that could just be added as a line to Card(and if it does, put a check in undo()).
- jim
- Posts: 46
- Joined: 19 Feb 2010, 01:46
- Location: Sunny New England
- Has thanked: 0 time
- Been thanked: 0 time
Re: Code from slapshot5
by slapshot5 » 13 Apr 2010, 13:14
Here's Twiddle - pretty much the same as Icy Manipulator.
CardFactory.java:
CardFactory.java:
- Code: Select all
//*****************************START*******************************
if(cardName.equals("Twiddle")) {
final SpellAbility spell = new Spell(card) {
private static final long serialVersionUID = 1710491641333972105L;
public boolean canPlayAI() {
return false;
}
public void chooseTargetAI() {
//setTargetCard(c);
}//chooseTargetAI()
public void resolve() {
/* The rules provide that tap/untap is chosed on resolution.
* I think this simple implementation will suffice for Forge.
*/
if(AllZone.GameAction.isCardInPlay(getTargetCard())) {
if(getTargetCard().isTapped()) {
getTargetCard().untap();
}
else {
getTargetCard().tap();
}
}
}
};//SpellAbility
spell.setBeforePayMana(CardFactoryUtil.input_targetType(spell, "Artifact;Creature;Land"));
card.clearSpellAbility();
card.addSpellAbility(spell);
}//end Twiddle
//****************END*******END***********************
- Code: Select all
Twiddle
U
Instant
You may tap or untap target artifact, creature, or land.
- Code: Select all
http://www.wizards.com/global/images/magic/general/twiddle.jpg
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: Code from slapshot5
by slapshot5 » 13 Apr 2010, 14:30
I think I've got Zuran Orb working now for Human and AI:
It's been requested a few times in the other thread...
cards.txt
Add these two functions to CardFactoryUtil.java:
It's been requested a few times in the other thread...
cards.txt
- Code: Select all
Zuran Orb
0
Artifact
0: Sacrifice a land to gain 2 life.
- Code: Select all
//*************** START *********** START **************************
if(cardName.equals("Zuran Orb")) {
final SpellAbility ability = new Ability_Activated(card,"0") {
private static final long serialVersionUID = 6349074098650435648L;
public boolean canPlayAI() {
if( CardFactoryUtil.getLandsInPlay(Constant.Player.Computer).size() > 0 ) {
if( AllZone.GameAction.getPlayerLife(Constant.Player.Computer).getLife() < 5 ) {
return true;
}
else {
return false;
}
}
else return false;
}
public void chooseTargetAI() {
Card target = null;
target = CardFactoryUtil.getWorstLand(Constant.Player.Computer);
setTargetCard(target);
}//chooseTargetAI()
public void resolve() {
AllZone.GameAction.getPlayerLife(card.getController()).addLife(2);
AllZone.GameAction.sacrifice(getTargetCard());
}
};//SpellAbility
Input runtime = new Input() {
private static final long serialVersionUID = -64941510699003443L;
public void showMessage() {
ability.setStackDescription(card +" - Sacrifice a land to gain 2 life.");
PlayerZone play = AllZone.getZone(Constant.Zone.Play,card.getController());
CardList choice = new CardList(play.getCards());
choice = choice.getType("Land");
stopSetNext(CardFactoryUtil.input_sacrifice(ability,choice,"Select a land to sacrifice."));
}
};
ability.setStackDescription("Zuran Orb - Gain 2 life.");
card.addSpellAbility(ability);
ability.setBeforePayMana(runtime);
}//*************** END ************ END **************************
Add these two functions to CardFactoryUtil.java:
- Code: Select all
/**
* getWorstLand(String)
*
* This function finds the worst land a player has in play based on:
* worst
* 1. tapped, basic land
* 2. tapped, non-basic land
* 3. untapped, basic land
* 4. untapped, non-basic land
* best
*
* This is useful when the AI needs to find one of its lands to sacrifice
*
* @param player - Constant.Player.Human or Constant.Player.Computer
* @return the worst land found based on the description above
*/
public static Card getWorstLand(String player) {
Card worstLand = null;
CardList lands = CardFactoryUtil.getLandsInPlay(player);
//first, check for tapped, basic lands
for( int i = 0; i < lands.size(); i++ ) {
Card tmp = lands.get(i);
if(tmp.isTapped() && tmp.isBasicLand()) {
worstLand = tmp;
}
}
//next, check for tapped, non-basic lands
if(worstLand == null) {
for( int i = 0; i < lands.size(); i++ ) {
Card tmp = lands.get(i);
if(tmp.isTapped()) {
worstLand = tmp;
}
}
}
//next, untapped, basic lands
if(worstLand == null) {
for( int i = 0; i < lands.size(); i++ ) {
Card tmp = lands.get(i);
if(tmp.isUntapped() && tmp.isBasicLand()) {
worstLand = tmp;
}
}
}
//next, untapped, non-basic lands
if(worstLand == null) {
for( int i = 0; i < lands.size(); i++ ) {
Card tmp = lands.get(i);
if(tmp.isUntapped()) {
worstLand = tmp;
}
}
}
return worstLand;
}//end getWorstLand
/**
* getLandsInPlay(String)
*
* This function returns a CardList of all lands that the given
* player has in Constant.Zone.Play
*
* @param player - Constant.Player.Human or Constant.Player.Computer
* @return a CardList of that players lands
*/
public static CardList getLandsInPlay(String player) {
PlayerZone compBattlezone = AllZone.getZone(Constant.Zone.Play, player);
CardList list = new CardList(compBattlezone.getCards());
list = list.filter(new CardListFilter() {
public boolean addCard(Card c) {
if(c.isLand()) return true;
else return false;
}
});
return list;
}
- Code: Select all
http://www.wizards.com/global/images/magic/general/zuran_orb.jpg
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: Code from slapshot5
by slapshot5 » 13 Apr 2010, 14:51
This is Keldon Warlord
cards.txt:
StaticEffects.java:
cards.txt:
- Code: Select all
Keldon Warlord
2 R R
Creature Human Barbarian
Keldon Warlord's power and toughness are each equal to the number of non-Wall creatures you control.
1/1
- Code: Select all
commands.put("Keldon_Warlord", Keldon_Warlord);
- Code: Select all
public static Command Keldon_Warlord = new Command() {
private static final long serialVersionUID = 3804539422363462063L;
public void execute() {
// get all creatures
CardList list = new CardList();
list.addAll(AllZone.Human_Play.getCards());
list.addAll(AllZone.Computer_Play.getCards());
list = list.getName("Keldon Warlord");
for(int i = 0; i < list.size(); i++) {
Card c = list.get(i);
c.setBaseAttack(countCreatures(c));
c.setBaseDefense(c.getNetAttack());
}
}// execute()
private int countCreatures(Card c) {
PlayerZone play = AllZone.getZone(Constant.Zone.Play, c.getController());
CardList creatures = new CardList(play.getCards());
creatures = creatures.filter(new CardListFilter() {
public boolean addCard(Card c) {
return c.isCreature() && !c.isWall();
}
});
return creatures.size();
}
};
StaticEffects.java:
- Code: Select all
cardToEffectsList.put("Keldon Warlord", new String[] {"Keldon_Warlord"});
- Code: Select all
public boolean isWall() {
return type.contains("Wall");
}
- Code: Select all
http://www.wizards.com/global/images/magic/general/keldon_warlord.jpg
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: Code from slapshot5
by Rob Cashwalker » 13 Apr 2010, 17:02
FYI: generally, you can use the CardFactoryUtil.xCount method to provide the same functionality as the usual custom count____ code you have used. It should be easy to add a "Non" clause.... It would be something like this:
xCount("TypeYouCtrl.NonWall")
Also, this sort of ability is very common, and you should be able to turn the code into a keyword.
xCount("TypeYouCtrl.NonWall")
Also, this sort of ability is very common, and you should be able to turn the code into a keyword.
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
55 posts
• Page 2 of 4 • 1, 2, 3, 4
Who is online
Users browsing this forum: No registered users and 71 guests