Implementing new Ability Factories and Card Support Code
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Agetian, friarsol, Blacksmith, KrazyTheFox, CCGHQ Admins
Re: Implementing new Ability Factories and Card Support Code
by Agetian » 27 Nov 2012, 17:09
I have several questions related to the Nafs Asp implementation:
1. Can anyone please direct me to the right place where the Nafs Asp script above actually deals damage (no sound is playing there, I want to make sure the proper event is generated) and where the Nafs Asp effect card actually goes away (I'd like to add a sound event for that, too).
2. I was thinking of adding the AI for Nafs Asp along the lines of: 1) if there is enough mana to pay for the ability effect during the player's turn, do it on player's M2 phase (so that all the lands are untapped during the AI's turn again); 2) if there's not enough mana to pay for the damaging effect in player's M2, pay for it during the AI's upkeep phase. Would this be sufficient?
3. If 2 is sufficient, what would be the proper files/routines to look for to link a code like that? I tried looking up the phase code but couldn't even find where the Main2 routines for the AI are supposed to fire by digging from PhaseHandler.java... also, I'm not sure where the AI pays its upkeep costs - is that best linked in the upkeep phase code itself in forge.game.phase.Upkeep (probably not) or is it better to link that to something in forge.game.player.AIPlayer or forge.game.player.ComputerAIGeneral?
Thank you very much in advance for your advice!
- Agetian
1. Can anyone please direct me to the right place where the Nafs Asp script above actually deals damage (no sound is playing there, I want to make sure the proper event is generated) and where the Nafs Asp effect card actually goes away (I'd like to add a sound event for that, too).
2. I was thinking of adding the AI for Nafs Asp along the lines of: 1) if there is enough mana to pay for the ability effect during the player's turn, do it on player's M2 phase (so that all the lands are untapped during the AI's turn again); 2) if there's not enough mana to pay for the damaging effect in player's M2, pay for it during the AI's upkeep phase. Would this be sufficient?
3. If 2 is sufficient, what would be the proper files/routines to look for to link a code like that? I tried looking up the phase code but couldn't even find where the Main2 routines for the AI are supposed to fire by digging from PhaseHandler.java... also, I'm not sure where the AI pays its upkeep costs - is that best linked in the upkeep phase code itself in forge.game.phase.Upkeep (probably not) or is it better to link that to something in forge.game.player.AIPlayer or forge.game.player.ComputerAIGeneral?
Thank you very much in advance for your advice!
- Agetian
- Agetian
- Programmer
- Posts: 3490
- Joined: 14 Mar 2011, 05:58
- Has thanked: 684 times
- Been thanked: 572 times
Re: Implementing new Ability Factories and Card Support Code
by moomarc » 27 Nov 2012, 17:15
1 - The delayed "damage" is actually a straightforward loselife. So probably check the life modifying code (can't remember exactly where that is offhand). When the effect disappears, it is linked to changezone exile. I think that was in GameAction.Agetian wrote:I have several questions related to the Nafs Asp implementation:
1. Can anyone please direct me to the right place where the Nafs Asp script above actually deals damage (no sound is playing there, I want to make sure the proper event is generated) and where the Nafs Asp effect card actually goes away (I'd like to add a sound event for that, too).
2. I was thinking of adding the AI for Nafs Asp along the lines of: 1) if there is enough mana to pay for the ability effect during the player's turn, do it on player's M2 phase (so that all the lands are untapped during the AI's turn again); 2) if there's not enough mana to pay for the damaging effect in player's M2, pay for it during the AI's upkeep phase. Would this be sufficient?
3. If 2 is sufficient, what would be the proper files/routines to look for to link a code like that? I tried looking up the phase code but couldn't even find where the Main2 routines for the AI are supposed to fire by digging from PhaseHandler.java... also, I'm not sure where the AI pays its upkeep costs - is that best linked in the upkeep phase code itself in forge.game.phase.Upkeep (probably not) or is it better to link that to something in forge.game.player.AIPlayer or forge.game.player.ComputerAIGeneral?
Thank you very much in advance for your advice!
- Agetian
2 - Sounds like the right solution to me
3 - Beyond my ability to help
-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: Implementing new Ability Factories and Card Support Code
by friarsol » 27 Nov 2012, 17:20
I would think the right timing to pay for it is during the Discard Phase right before the AI would untap. Other cards that use a similar AI are called something like "Reusable" or something. This is when the AI activates Prodigal Sorcerer and friends to make sure they still do damage but don't do it too early.Agetian wrote:2. I was thinking of adding the AI for Nafs Asp along the lines of: 1) if there is enough mana to pay for the ability effect during the player's turn, do it on player's M2 phase (so that all the lands are untapped during the AI's turn again); 2) if there's not enough mana to pay for the damaging effect in player's M2, pay for it during the AI's upkeep phase. Would this be sufficient?
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Implementing new Ability Factories and Card Support Code
by Agetian » 27 Nov 2012, 17:37
Thanks for your advice!
Yep, I agree that the Discard Phase is good timing to pay for it, as long as the AI has mana - if the AI has no mana, probably the upkeep phase should be the phase to pay, right?
- Agetian
Yep, I agree that the Discard Phase is good timing to pay for it, as long as the AI has mana - if the AI has no mana, probably the upkeep phase should be the phase to pay, right?
- Agetian
- Agetian
- Programmer
- Posts: 3490
- Joined: 14 Mar 2011, 05:58
- Has thanked: 684 times
- Been thanked: 572 times
Re: Implementing new Ability Factories and Card Support Code
by Sloth » 27 Nov 2012, 21:37
Don't make it complicated. Add the parameter "AILogic$ Always" to the script and check for it in the canPlayAI function in ChangeZoneAI to always return true. Finished.Agetian wrote:Thanks for your advice!
Yep, I agree that the Discard Phase is good timing to pay for it, as long as the AI has mana - if the AI has no mana, probably the upkeep phase should be the phase to pay, right?
- Agetian
-

Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: Implementing new Ability Factories and Card Support Code
by Agetian » 28 Nov 2012, 03:43
That's nice, Sloth, thanks so much for the valuable tip, I'll implement it ASAP!
- Agetian
- Agetian
- Agetian
- Programmer
- Posts: 3490
- Joined: 14 Mar 2011, 05:58
- Has thanked: 684 times
- Been thanked: 572 times
Re: Implementing new Ability Factories and Card Support Code
by Agetian » 28 Nov 2012, 05:20
For some reason it doesn't work this way... I'm probably adding things to the wrong place or something, but... I added the following lines to the canPlayAI method of ChangeZoneAi:Sloth wrote:Don't make it complicated. Add the parameter "AILogic$ Always" to the script and check for it in the canPlayAI function in ChangeZoneAI to always return true. Finished.
- Code: Select all
if (sa.hasParam("AILogic")) {
System.out.println("HERE");
if (sa.getParam("AILogic").equals("Always")) {
return true;
}
}
- Code: Select all
Name:Nafs Asp
ManaCost:G
Types:Creature Snake
Text:no text
PT:1/1
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ NafsEffect | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals damage to a player, that player loses 1 life at the beginning of his or her next draw step unless he or she pays 1 before that draw step.
SVar:NafsEffect:AB$ Effect | Cost$ 0 | Name$ Nafs Effect | EffectOwner$ TriggeredTarget | Duration$ Permanent | Triggers$ DrawTrig | Abilities$ PayUp | SVars$ Bleed,ExileEffect
SVar:DrawTrig:Mode$ Phase | Phase$ Draw | ValidPlayer$ You | TriggerZones$ Command | Execute$ Bleed | TriggerDescription$ You lose 1 life at the beginning of your next draw step unless you pay 1 before that draw step.
SVar:Bleed:AB$ LoseLife | Cost$ 0 | Defined$ You | LifeAmount$ 1 | SubAbility$ ExileEffect
SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
SVar:PayUp:AB$ ChangeZone | Cost$ 1 | Defined$ Self | Origin$ Command | Destination$ Exile | Static$ True | AILogic$ Always | SpellDescription$ Pay 1 to remove this effect.
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/nafs_asp.jpg
SetInfo:4ED|Common|http://magiccards.info/scans/en/4e/148.jpg
SetInfo:ARN|Common|http://magiccards.info/scans/en/an/36.jpg|2
Oracle:Whenever Nafs Asp deals damage to a player, that player loses 1 life at the beginning of his or her next draw step unless he or she pays {1} before that draw step.
End
- Agetian
- Agetian
- Programmer
- Posts: 3490
- Joined: 14 Mar 2011, 05:58
- Has thanked: 684 times
- Been thanked: 572 times
Re: Implementing new Ability Factories and Card Support Code
by moomarc » 28 Nov 2012, 07:28
My guess is that you tried after the Vanguard branch was merged, so you need to add "ActivationZone$ Command" to the PayUp ability (that should be the only line with AILogic). You can also optionally add "TriggerZones$ Command" to the TrigDraw line. Doesn't really make a difference though.Agetian wrote:For some reason it doesn't work this way... I'm probably adding things to the wrong place or something, but... I added the following lines to the canPlayAI method of ChangeZoneAi:Sloth wrote:Don't make it complicated. Add the parameter "AILogic$ Always" to the script and check for it in the canPlayAI function in ChangeZoneAI to always return true. Finished.The line "HERE" is never printed to the console, so apparently this check is never made or always fails because AILogic$ Always is added to the wrong place. Here's the current Nafs Asp script:
- Code: Select all
if (sa.hasParam("AILogic")) {
System.out.println("HERE");
if (sa.getParam("AILogic").equals("Always")) {
return true;
}
}I tried adding the AILogic$ Always line to the PayUp SVar, to the Bleed SVar, to the ExileEffect, as well as to the T:Mode$ line, but the check is never fired (or never succeeds) anyway. Can you please tell me what I'm doing wrong?
- Code: Select all
Name:Nafs Asp
ManaCost:G
Types:Creature Snake
Text:no text
PT:1/1
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ NafsEffect | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals damage to a player, that player loses 1 life at the beginning of his or her next draw step unless he or she pays 1 before that draw step.
SVar:NafsEffect:AB$ Effect | Cost$ 0 | Name$ Nafs Effect | EffectOwner$ TriggeredTarget | Duration$ Permanent | Triggers$ DrawTrig | Abilities$ PayUp | SVars$ Bleed,ExileEffect
SVar:DrawTrig:Mode$ Phase | Phase$ Draw | ValidPlayer$ You | TriggerZones$ Command | Execute$ Bleed | TriggerDescription$ You lose 1 life at the beginning of your next draw step unless you pay 1 before that draw step.
SVar:Bleed:AB$ LoseLife | Cost$ 0 | Defined$ You | LifeAmount$ 1 | SubAbility$ ExileEffect
SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
SVar:PayUp:AB$ ChangeZone | Cost$ 1 | Defined$ Self | Origin$ Command | Destination$ Exile | Static$ True | AILogic$ Always | SpellDescription$ Pay 1 to remove this effect.
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/nafs_asp.jpg
SetInfo:4ED|Common|http://magiccards.info/scans/en/4e/148.jpg
SetInfo:ARN|Common|http://magiccards.info/scans/en/an/36.jpg|2
Oracle:Whenever Nafs Asp deals damage to a player, that player loses 1 life at the beginning of his or her next draw step unless he or she pays {1} before that draw step.
End
- Agetian
-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: Implementing new Ability Factories and Card Support Code
by Agetian » 28 Nov 2012, 13:38
Oh, that's interesting, I'll give it a shot! Thanks a lot, Moomarc!
- Agetian
- Agetian
- Agetian
- Programmer
- Posts: 3490
- Joined: 14 Mar 2011, 05:58
- Has thanked: 684 times
- Been thanked: 572 times
Re: Implementing new Ability Factories and Card Support Code
by Agetian » 28 Nov 2012, 13:46
Yay, it works. Submitted to SVN.
Thanks to everyone involved for help!
- Agetian
- Agetian
- Agetian
- Programmer
- Posts: 3490
- Joined: 14 Mar 2011, 05:58
- Has thanked: 684 times
- Been thanked: 572 times
Re: Implementing new Ability Factories and Card Support Code
by Agetian » 30 Nov 2012, 15:51
OK, now that the new version is released, I think I'll experiment a bit with my original idea of implementing chained "Unless" costs. I looked at the code again and I'd probably need a bit more clarification here:
1) I found the payCostDuringAbilityResolve method, and I see the costs that require inputs in the end of the method. There is apparently only one cost that must remain by then, at least according to the current code, am I right? I mean, I'm looking at the following:
I've read Max's suggested solution above as well, but I'm not sure how InputSelectManyCards can help here - should it replace the calls to e.g. InputPayReturnCost etc.? I'm afraid I'm not quite certain how it's supposed to work in the end... Any clarification would be highly welcome.
Thanks a lot in advance for any help.
- Agetian
- Agetian
1) I found the payCostDuringAbilityResolve method, and I see the costs that require inputs in the end of the method. There is apparently only one cost that must remain by then, at least according to the current code, am I right? I mean, I'm looking at the following:
- Code: Select all
if (remainingParts.size() > 1) {
throw new RuntimeException("GameActionUtil::payCostDuringAbilityResolve - Too many payment types - " + source);
}
costPart = remainingParts.get(0);
- Code: Select all
for (CostPart part : parts) {
...
}
I've read Max's suggested solution above as well, but I'm not sure how InputSelectManyCards can help here - should it replace the calls to e.g. InputPayReturnCost etc.? I'm afraid I'm not quite certain how it's supposed to work in the end... Any clarification would be highly welcome.
Thanks a lot in advance for any help.
- Agetian
- Agetian
- Agetian
- Programmer
- Posts: 3490
- Joined: 14 Mar 2011, 05:58
- Has thanked: 684 times
- Been thanked: 572 times
Re: Implementing new Ability Factories and Card Support Code
by friarsol » 30 Nov 2012, 16:25
Was this for combining cards like Propaganda with other cards with attack costs? Or something else? If it was for attack costs, I think the way I'd try to handle it is to merge all required costs into a new single cost and then just pass that into the appropriate function.Agetian wrote:OK, now that the new version is released, I think I'll experiment a bit with my original idea of implementing chained "Unless" costs. I looked at the code again and I'd probably need a bit more clarification here:
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Implementing new Ability Factories and Card Support Code
by Agetian » 30 Nov 2012, 16:32
Yeah, it was exactly for Propaganda and other similar cards and attack costs. Interesting, but currently all the costs have their own distinct type and each cost, as far as I can see, kind of "handles itself" in its own class, wouldn't combining calls to all of them together in one class be more or less the same as what payCostDuringAbilityResolve currently does? (it serves as the function that tries to take care of all the individual components of the cost in one place)
- Agetian
- Agetian
- Agetian
- Programmer
- Posts: 3490
- Joined: 14 Mar 2011, 05:58
- Has thanked: 684 times
- Been thanked: 572 times
Re: Implementing new Ability Factories and Card Support Code
by friarsol » 30 Nov 2012, 16:40
Oh I just looked in CombatUtil.checkPropagandaEffects() and all of the costs are already combined and then passed in wholesale to payCostDuringAbilityResolve(). I think this is the right way to do it for Attacking. Since you may not be able to "Undo" if you only pay like half the costs and each cost was handled separately. Plus it's nice to know how much in advance each attacker is going to cost to attack, as opposed to "Ok pay 2" "Ok now sac a land" etcAgetian wrote:Yeah, it was exactly for Propaganda and other similar cards and attack costs. Interesting, but currently all the costs have their own distinct type and each cost, as far as I can see, kind of "handles itself" in its own class, wouldn't combining calls to all of them together in one class be more or less the same as what payCostDuringAbilityResolve currently does? (it serves as the function that tries to take care of all the individual components of the cost in one place)
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Implementing new Ability Factories and Card Support Code
by Agetian » 30 Nov 2012, 16:48
Right, it's already passed completely to payCostDuringAbilityResolve, the problems start inside payCostDuringAbilityResolve when, closer to the end of it, certain calls are executed outside of the chain because they require input on behalf of the user and, as such, happen "delayed"... So, that's where the change must be made, but I'm afraid I can't quite grasp the essence of the change yet (at least outside of what I've outlined above). :\
- Agetian
- Agetian
- Agetian
- Programmer
- Posts: 3490
- Joined: 14 Mar 2011, 05:58
- Has thanked: 684 times
- Been thanked: 572 times
Who is online
Users browsing this forum: No registered users and 16 guests