It is currently 16 Sep 2025, 22:28
   
Text Size

Card Development Questions

Post MTG Forge Related Programming Questions Here

Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins

Re: Card Development Questions

Postby 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

Postby 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
User avatar
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

Postby friarsol » 10 Mar 2012, 14:02

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?
Probably the right place is in Card.equipCard()

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;
}
Edit: Auras should probably get the same makeover.
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

Postby moomarc » 10 Mar 2012, 14:10

Thanks! I'll look into it first thing tomorrow.
-Marc
User avatar
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

Postby 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.
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

Postby 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?
Xitax
 
Posts: 918
Joined: 16 May 2010, 17:19
Has thanked: 183 times
Been thanked: 133 times

Re: Card Development Questions

Postby moomarc » 11 Mar 2012, 07:04

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?
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.

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
User avatar
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

Postby moomarc » 11 Mar 2012, 20:56

friarsol wrote:
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?
Probably the right place is in Card.equipCard()

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;
}
Edit: Auras should probably get the same makeover.
We probably also want the AI to remove all targets/choices for Equipment that can't be equipped.
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:
Code: Select all
else if (card.isEquipment()) {
    if (card.isEquipping()) {
        card.unEquipCard(card.getEquipping().get(0));
        }
    }
    card.equipCard(c);
became this:
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);
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 :) )
-Marc
User avatar
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

Postby friarsol » 12 Mar 2012, 03:06

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 :) )
Try this:
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

Postby 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):
Code: Select all
if (AllZoneUtil.isCardInPlay(c) && !c.isEnchanting()) {
    this.moveToGraveyard(c);
    checkAgain = true;
}
I happened to test with just the right cards to make a small bug show up that's unrelated to my changes (as far as I can tell). If an aura is removed due to a state-based effect, it doesn't trigger Wheel of Sun and Moon. I'm not sure how to test whether it affects other similar situations too.

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
User avatar
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

Postby moomarc » 15 Mar 2012, 07:43

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 that's the only issue I'm sure it should be fine, but have you tested the following scenarios:
- 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
User avatar
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

Postby jeffwadsworth » 15 Mar 2012, 15:21

moomarc wrote:
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 that's the only issue I'm sure it should be fine, but have you tested the following scenarios:
- 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?
All of that was tested and worked fine, but I do not like the generic description on the affected Slivers. Stowed away.
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

Postby 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
User avatar
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

Postby jeffwadsworth » 15 Mar 2012, 16:13

Code added to StaticAbilityContinuous.java

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())));
            }
Script for Ward Sliver

| 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

Postby 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:
Code: Select all
addKeywords[w] = addKeywords[w].replaceAll("the chosen color", color.substring(0, 1).concat(color.substring(1, color.length())));
EDIT: WOW! We've been THICK! The other option which is even better and requires no additional code is to change the AddKeyword param to "Protection:Card.ChosenColor:Protection from ChosenColor". Your code does the rest without any additions! That way it even reads the same as other protection from keywords instead of CARDNAME has protection from color.

I'll leave you commit seeing as you solved the initial problem. =D>
-Marc
User avatar
moomarc
Pixel Commander
 
Posts: 2091
Joined: 04 Jun 2010, 15:22
Location: Johannesburg, South Africa
Has thanked: 371 times
Been thanked: 372 times

PreviousNext

Return to Developer's Corner

Who is online

Users browsing this forum: No registered users and 48 guests

Main Menu

User Menu

Our Partners


Who is online

In total there are 48 users online :: 0 registered, 0 hidden and 48 guests (based on users active over the past 10 minutes)
Most users ever online was 7967 on 09 Sep 2025, 23:08

Users browsing this forum: No registered users and 48 guests

Login Form