Card Development Questions
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
Re: Card Development Questions
by jeffwadsworth » 10 Mar 2012, 02:49
Cheers.
Last edited by jeffwadsworth on 10 Mar 2012, 17:52, edited 1 time in total.
- jeffwadsworth
- Super Tester Elite
- Posts: 1172
- Joined: 20 Oct 2010, 04:47
- Location: USA
- Has thanked: 287 times
- Been thanked: 70 times
Re: Card Development Questions
by moomarc » 10 Mar 2012, 13:32
I was looking to add the keyword "CARDNAME can't be equipped." (for Goblin Brawlers) by looking at "CARDNAME can't be enchanted." but noticed a small problem with it. Currently it acts as a targeting restriction whereas the targeting should be legal, just resolution fizzles. Any ideas on how to fix it?
-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: Card Development Questions
by friarsol » 10 Mar 2012, 14:02
Probably the right place is in Card.equipCard()moomarc wrote:I was looking to add the keyword "CARDNAME can't be equipped." (for Goblin Brawlers) by looking at "CARDNAME can't be enchanted." but noticed a small problem with it. Currently it acts as a targeting restriction whereas the targeting should be legal, just resolution fizzles. Any ideas on how to fix it?
with:
- Code: Select all
if (c.hasKeyword("CARDNAME can't be equipped.")){
// Write to game log that we're trying to equip to a creature that can't be equipped
return;
}
We probably also want the AI to remove all targets/choices for Equipment that can't be equipped.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Card Development Questions
by moomarc » 10 Mar 2012, 14:10
Thanks! I'll look into it first thing tomorrow.
-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: Card Development Questions
by jeffwadsworth » 10 Mar 2012, 22:13
For the card Ward Sliver, would the following text on each Sliver be "good enough".
"CARDNAME" has protection from the chosen color.
The chosen color is displayed on the Ward Sliver only. Otherwise, it works fine.
"CARDNAME" has protection from the chosen color.
The chosen color is displayed on the Ward Sliver only. Otherwise, it works fine.
- jeffwadsworth
- Super Tester Elite
- Posts: 1172
- Joined: 20 Oct 2010, 04:47
- Location: USA
- Has thanked: 287 times
- Been thanked: 70 times
Re: Card Development Questions
by Xitax » 11 Mar 2012, 04:27
Seems like with the addition of Blood Feud and Contested Cliffs that Arena might be possible, but the AI has to choose his creature. Can this be done?
I'm trying to find similar cards on which to base the code for this card, but this is my first attempt at a card. For the 'each player chooses a creature' part I'm looking to find an extant card for some guidance. Balance, and Global Ruin don't seem to have any info in their text files that helps in any way. Where is the code for their abilities located?
I'm trying to find similar cards on which to base the code for this card, but this is my first attempt at a card. For the 'each player chooses a creature' part I'm looking to find an extant card for some guidance. Balance, and Global Ruin don't seem to have any info in their text files that helps in any way. Where is the code for their abilities located?
Re: Card Development Questions
by moomarc » 11 Mar 2012, 07:04
I'm pretty sure the AI choice would have to be hardcoded rather than scripted. There's just too many factors to take into account. If the human activates it the chances are it should just import the good choices list from Sacrifice AF because the chances are the human will only activate it expecting at least a good trade, and because the AI won't use instants to pump its creatures after the 'contestants' have been chosen, the human will have his way.Xitax wrote:Seems like with the addition of Blood Feud and Contested Cliffs that Arena might be possible, but the AI has to choose his creature. Can this be done?
I'm trying to find similar cards on which to base the code for this card, but this is my first attempt at a card. For the 'each player chooses a creature' part I'm looking to find an extant card for some guidance. Balance, and Global Ruin don't seem to have any info in their text files that helps in any way. Where is the code for their abilities located?
Then to make it feasable for the AI to activate it, it must check that either its strongest creature can kill each other creature the human controls without dying. It should also consider deathtouch, wither and infect etc.
-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: Card Development Questions
by moomarc » 11 Mar 2012, 20:56
Okay, I've got the two keywords working, including writing to the game log and the affected cards being removed from AI targeting, but there's two issues that have popped up now.friarsol wrote:Probably the right place is in Card.equipCard()moomarc wrote:I was looking to add the keyword "CARDNAME can't be equipped." (for Goblin Brawlers) by looking at "CARDNAME can't be enchanted." but noticed a small problem with it. Currently it acts as a targeting restriction whereas the targeting should be legal, just resolution fizzles. Any ideas on how to fix it?
with:Edit: Auras should probably get the same makeover.
- Code: Select all
if (c.hasKeyword("CARDNAME can't be equipped.")){
// Write to game log that we're trying to equip to a creature that can't be equipped
return;
}
We probably also want the AI to remove all targets/choices for Equipment that can't be equipped.
I can't find a definitive ruling on the first issue so I just want clarification that I've understood correctly. In the case of "CARDNAME can't be equipped.", if the equipment is already equipped to another creature then you try to equip Goblin Brawler, the equipment should stay on the original creature. I'm struggling to get this to work though. At the moment the equipment becomes unattached even though I've made the following change in AbilityFactoryAttach:
- Code: Select all
else if (card.isEquipment()) {
if (card.isEquipping()) {
card.unEquipCard(card.getEquipping().get(0));
}
}
card.equipCard(c);
- Code: Select all
else if (card.isEquipment()) {
if (card.isEquipping()) {
if (c.hasKeyword("CARDNAME can't be equipped.")) {
AllZone.getGameLog().add("ResolveStack", "Trying to equip " + c.getName()
+ " but it can't be equipped.", 2);
return;
} else {
card.unEquipCard(card.getEquipping().get(0));
}
}
card.equipCard(c);
The second issue is if you try to enchant a creature with "CARDNAME can't be enchanted." the spell will fizzle on resolution BUT it will not be moved to the graveyard. Instead it will just lie around on the battlefield waiting for brighter days. Instead of using 'return;' here should I instead use the code to move it to the graveyard?
Thanks in advance for the help and for your patience in dealing with a coding null like me (coding noob would probably be too generous

-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: Card Development Questions
by friarsol » 12 Mar 2012, 03:06
Try this:moomarc wrote:Okay, I've got the two keywords working, including writing to the game log and the affected cards being removed from AI targeting, but there's two issues that have popped up now.
I can't find a definitive ruling on the first issue so I just want clarification that I've understood correctly. In the case of "CARDNAME can't be equipped.", if the equipment is already equipped to another creature then you try to equip Goblin Brawler, the equipment should stay on the original creature. I'm struggling to get this to work though. At the moment the equipment becomes unattached even though I've made the following change in AbilityFactoryAttach:
I also tried moving the unequip section into Card.equipCard() but it had exactly the same result. Any idea how to fix it?
The second issue is if you try to enchant a creature with "CARDNAME can't be enchanted." the spell will fizzle on resolution BUT it will not be moved to the graveyard. Instead it will just lie around on the battlefield waiting for brighter days. Instead of using 'return;' here should I instead use the code to move it to the graveyard?
Thanks in advance for the help and for your patience in dealing with a coding null like me (coding noob would probably be too generous)
- Equipment code | Open
- else if (card.isEquipment()) {
if (c.hasKeyword("CARDNAME can't be equipped.")) {
AllZone.getGameLog().add("ResolveStack", "Trying to equip " + c.getName() + " but it can't be equipped.", 2);
return;
}
if (card.isEquipping()) {
card.unEquipCard(card.getEquipping().get(0));
}
card.equipCard(c);
Or we can move the unequipping inside of equipCard(c)...
As far as Auras and Can't be Enchanted, the spell doesn't fizzle (this is unofficial terminology only used with targeting). The Aura resolves, but when it tries to attach it can't. Now since a spell finished resolving, state based effects should kick in, see there's an Aura on the battlefield that isn't attached to anything and send it to the graveyard.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Card Development Questions
by moomarc » 12 Mar 2012, 09:40
Thanks Sol, but I tried that last night already while trying everything I could think of to get it to work. The equipment still gets unequipped.
With regards to the state based effects removing the unattached aura, I got that to work but would probably recommend someone checks to make sure that it doesn't break anything. I just added this to the end of GameAction.checkStateEffects (at line 957):
Should I commit what I have so far and let one of you guru's try crack the equip issue? Otherwise here's a patch:

With regards to the state based effects removing the unattached aura, I got that to work but would probably recommend someone checks to make sure that it doesn't break anything. I just added this to the end of GameAction.checkStateEffects (at line 957):
- Code: Select all
if (AllZoneUtil.isCardInPlay(c) && !c.isEnchanting()) {
this.moveToGraveyard(c);
checkAgain = true;
}
Should I commit what I have so far and let one of you guru's try crack the equip issue? Otherwise here's a patch:
- Patch - can't enchant/equip | Open
- Code: Select all
Index: res/cardsfolder/g/goblin_brawler.txt
===================================================================
--- res/cardsfolder/g/goblin_brawler.txt (revision 0)
+++ res/cardsfolder/g/goblin_brawler.txt (revision 0)
@@ -0,0 +1,12 @@
+Name:Goblin Brawler
+ManaCost:2 R
+Types:Creature Goblin Warrior
+Text:no text
+PT:2/2
+K:First Strike
+K:CARDNAME can't be equipped.
+SVar:Rarity:Common
+SVar:Picture:http://www.wizards.com/global/images/magic/general/goblin_brawler.jpg
+SetInfo:5DN|Common|http://magiccards.info/scans/en/5dn/66.jpg
+Oracle:First strike\nGoblin Brawler can't be equipped.
+End
\ No newline at end of file
Index: src/main/java/forge/Card.java
===================================================================
--- src/main/java/forge/Card.java (revision 14720)
+++ src/main/java/forge/Card.java (working copy)
@@ -4174,6 +4174,14 @@
* a {@link forge.Card} object.
*/
public final void equipCard(final Card c) {
+ if (c.hasKeyword("CARDNAME can't be equipped.")) {
+ AllZone.getGameLog().add("ResolveStack", "Trying to equip " + c.getName()
+ + " but it can't be equipped.", 2);
+ return;
+ }
+ if (this.isEquipping()) {
+ this.unEquipCard(this.getEquipping().get(0));
+ }
this.addEquipping(c);
c.addEquippedBy(this);
this.equip();
@@ -4352,6 +4360,11 @@
* a {@link forge.GameEntity} object.
*/
public final void enchantEntity(final GameEntity entity) {
+ if (entity.hasKeyword("CARDNAME can't be enchanted.")) {
+ AllZone.getGameLog().add("ResolveStack", "Trying to enchant " + entity.getName()
+ + " but it can't be enchanted.", 2);
+ return;
+ }
this.addEnchanting(entity);
entity.addEnchantedBy(this);
this.enchant();
@@ -8849,13 +8862,24 @@
}
}
- if (kw.equals("CARDNAME can't be the target of Aura spells.")
- || kw.equals("CARDNAME can't be enchanted.")) {
+ if (kw.equals("CARDNAME can't be the target of Aura spells.")) {
if (source.isAura() && sa.isSpell()) {
return false;
}
}
+ if (kw.equals("CARDNAME can't be enchanted.")) {
+ if (source.isAura() && source.getController().isComputer()) {
+ return false;
+ }
+ } //Sets source as invalid enchant target for computer player only.
+
+ if (kw.equals("CARDNAME can't be equipped.")) {
+ if (source.isEquipment() && source.getController().isComputer()) {
+ return false;
+ }
+ } //Sets source as invalid equip target for computer player only.
+
if (kw.equals("CARDNAME can't be the target of red spells or abilities from red sources.")) {
if (source.isRed()) {
return false;
@@ -8899,7 +8923,7 @@
}
if (this.hasProtectionFrom(aura) || this.hasKeyword("CARDNAME can't be enchanted.")
- || ((tgt != null) && !this.isValid(tgt.getValidTgts(), aura.getController(), aura))) {
+ || ((tgt != null) && !this.isValid(tgt.getValidTgts(), aura.getController(), aura))) {
return false;
}
return true;
Index: src/main/java/forge/GameAction.java
===================================================================
--- src/main/java/forge/GameAction.java (revision 14696)
+++ src/main/java/forge/GameAction.java (working copy)
@@ -955,6 +955,11 @@
}
}
+ if (AllZoneUtil.isCardInPlay(c) && !c.isEnchanting()) {
+ this.moveToGraveyard(c);
+ checkAgain = true;
+ }
+
} // if isAura
if (c.isCreature()) {
Index: src/main/java/forge/card/abilityfactory/AbilityFactoryAttach.java
===================================================================
--- src/main/java/forge/card/abilityfactory/AbilityFactoryAttach.java (revision 14696)
+++ src/main/java/forge/card/abilityfactory/AbilityFactoryAttach.java (working copy)
@@ -1044,10 +1044,6 @@
final boolean gainControl = "GainControl".equals(af.getMapParams().get("AILogic"));
AbilityFactoryAttach.handleAura(card, c, gainControl);
} else if (card.isEquipment()) {
- if (card.isEquipping()) {
- card.unEquipCard(card.getEquipping().get(0));
- }
-
card.equipCard(c);
// else if (card.isFortification())
// card.fortifyCard(c);
-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: Card Development Questions
by moomarc » 15 Mar 2012, 07:43
If that's the only issue I'm sure it should be fine, but have you tested the following scenarios:jeffwadsworth wrote:For the card Ward Sliver, would the following text on each Sliver be "good enough".
"CARDNAME" has protection from the chosen color.
The chosen color is displayed on the Ward Sliver only. Otherwise, it works fine.
- If another WS enters play, do slivers have protection against both?
- If a second WS enters play and choses the same color (the ChooseColor AILogic would return the same color for each WS), then one of them dies, are slivers still protected against that color?
-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: Card Development Questions
by jeffwadsworth » 15 Mar 2012, 15:21
All of that was tested and worked fine, but I do not like the generic description on the affected Slivers. Stowed away.moomarc wrote:If that's the only issue I'm sure it should be fine, but have you tested the following scenarios:jeffwadsworth wrote:For the card Ward Sliver, would the following text on each Sliver be "good enough".
"CARDNAME" has protection from the chosen color.
The chosen color is displayed on the Ward Sliver only. Otherwise, it works fine.
- If another WS enters play, do slivers have protection against both?
- If a second WS enters play and choses the same color (the ChooseColor AILogic would return the same color for each WS), then one of them dies, are slivers still protected against that color?
Messing with SpellWeaver Helix at the moment. The trick there is to get Imprinted.notSharesNameWith TriggeredCard implemented for getDefinedCards since you are using ArrayList instead of CardList.
Last edited by jeffwadsworth on 15 Mar 2012, 15:56, edited 1 time in total.
- jeffwadsworth
- Super Tester Elite
- Posts: 1172
- Joined: 20 Oct 2010, 04:47
- Location: USA
- Has thanked: 287 times
- Been thanked: 70 times
Re: Card Development Questions
by moomarc » 15 Mar 2012, 15:38
Would you mind sharing the script? Depending on how it's scripted, I want to try a few things to get it to display something more useful.
-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Re: Card Development Questions
by jeffwadsworth » 15 Mar 2012, 16:13
Code added to StaticAbilityContinuous.java
It just replaces "ChosenColor" with the actual chosen color in addKeywords.
- Code: Select all
String color = hostCard.getChosenColor().get(0);
for (int w = 0; w < addKeywords.length; w++) {
addKeywords[w] = addKeywords[w].replaceAll("ChosenColor", color.substring(0, 1).toUpperCase().concat(color.substring(1, color.length())));
}
- | Open
- Name:Ward Sliver
ManaCost:4 W
Types:Creature Sliver
Text:no text
PT:2/2
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ ChooseColor | Static$ True | TriggerDescription$ As CARDNAME enters the battlefield, choose a color.
SVar:ChooseColor:DB$ ChooseColor | Defined$ You
S:Mode$ Continuous | Affected$ Sliver | AddKeyword$ Protection:Card.ChosenColor:CARDNAME has protection from the chosen color. | Description$ All Slivers have protection from the chosen color.
SVar:RemAIDeck:True
SVar:Rarity:Uncommon
SVar:Picture:http://www.wizards.com/global/images/magic/general/ward_sliver.jpg
End
It just replaces "ChosenColor" with the actual chosen color in addKeywords.
- jeffwadsworth
- Super Tester Elite
- Posts: 1172
- Joined: 20 Oct 2010, 04:47
- Location: USA
- Has thanked: 287 times
- Been thanked: 70 times
Re: Card Development Questions
by moomarc » 18 Mar 2012, 17:44
Jeff, there was a REALLY simple solution to the problem and you had already solved it without realising. Just tack on the additional replacement:
I'll leave you commit seeing as you solved the initial problem.
- Code: Select all
addKeywords[w] = addKeywords[w].replaceAll("the chosen color", color.substring(0, 1).concat(color.substring(1, color.length())));
I'll leave you commit seeing as you solved the initial problem.

-Marc
-
moomarc - Pixel Commander
- Posts: 2091
- Joined: 04 Jun 2010, 15:22
- Location: Johannesburg, South Africa
- Has thanked: 371 times
- Been thanked: 372 times
Who is online
Users browsing this forum: No registered users and 48 guests