Trigger discussion (was WheneverKeyword reference)
Post MTG Forge Related Programming Questions Here
Moderators: timmermac, Blacksmith, KrazyTheFox, Agetian, friarsol, CCGHQ Admins
Re: Trigger discussion (was WheneverKeyword reference)
by Hellfish » 10 Jan 2011, 18:01
Patch: http://pastebin.com/1gvXjiZZ
Based on r5000.
The clumsy beginnings of the DamageDone mode is in there as well. I already know that is hideous, please focus on the big picture
EDIT: Also I havn't gotten around to properly commenting the code.. Just ask if you have questions!
EDIT2: Couldn't sleep, so I added a bunch of modes and requirements/restrictions!
Patch:
Based on r5032.
New modes: SpellCast,LifeGained,LifeLost,BeginningOfPhase,EndOfPhase,Attacks & Blocks.
New requirements/restrictions: Metalcraft,Threshold,PlayersPoisoned,ControlsNoValid & ControlsValid.
Didn't manage to fix the text bug, though, got distracted by MBS spoilers.
(Incidentally, what's the common opinion on when we start to implement cards from upcoming sets?I'm asking because I have theoretically sound code for all spoiled cards except Flayer Husk & technically Signal Pest, using the new modes mostly.)
Based on r5000.
The clumsy beginnings of the DamageDone mode is in there as well. I already know that is hideous, please focus on the big picture

EDIT: Also I havn't gotten around to properly commenting the code.. Just ask if you have questions!
EDIT2: Couldn't sleep, so I added a bunch of modes and requirements/restrictions!

Patch:
patch.zip
- (8.99 KiB) Downloaded 411 times
Based on r5032.
New modes: SpellCast,LifeGained,LifeLost,BeginningOfPhase,EndOfPhase,Attacks & Blocks.
New requirements/restrictions: Metalcraft,Threshold,PlayersPoisoned,ControlsNoValid & ControlsValid.
Didn't manage to fix the text bug, though, got distracted by MBS spoilers.

So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
-
Hellfish - Programmer
- Posts: 1297
- Joined: 07 Jun 2009, 10:41
- Location: South of the Pumphouse
- Has thanked: 110 times
- Been thanked: 169 times
Re: Trigger discussion (was WheneverKeyword reference)
by Hellfish » 11 Jan 2011, 03:12
Thinking closer on it, maybe I should just commit the source-part of the triggersystem? That way it won't interfere with the cards currently in but you'd have an easier time getting at the code than with a patch. EDIT: Did this, looks fine. 

Last edited by Hellfish on 11 Jan 2011, 03:38, edited 1 time in total.
So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
-
Hellfish - Programmer
- Posts: 1297
- Joined: 07 Jun 2009, 10:41
- Location: South of the Pumphouse
- Has thanked: 110 times
- Been thanked: 169 times
Re: Trigger discussion (was WheneverKeyword reference)
by friarsol » 11 Jan 2011, 03:15
I would prefer that Spoiled cards not happen until the spoilers were in magiccards.info since the Scripts require it. But I bet I'll be overruled.Hellfish wrote:(Incidentally, what's the common opinion on when we start to implement cards from upcoming sets?I'm asking because I have theoretically sound code for all spoiled cards except Flayer Husk & technically Signal Pest, using the new modes mostly.)
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Trigger discussion (was WheneverKeyword reference)
by slapshot5 » 11 Jan 2011, 04:00
We're talking Mirrodin:Beseiged, right? I would say we shouldn't add cards at least until WotC officially releases the set.friarsol wrote:I would prefer that Spoiled cards not happen until the spoilers were in magiccards.info since the Scripts require it. But I bet I'll be overruled.Hellfish wrote:(Incidentally, what's the common opinion on when we start to implement cards from upcoming sets?I'm asking because I have theoretically sound code for all spoiled cards except Flayer Husk & technically Signal Pest, using the new modes mostly.)
-slapshot5
- slapshot5
- Programmer
- Posts: 1391
- Joined: 03 Jan 2010, 17:47
- Location: Mac OS X
- Has thanked: 25 times
- Been thanked: 68 times
Re: Trigger discussion (was WheneverKeyword reference)
by Hellfish » 11 Jan 2011, 04:03
Yep. I think we were a bit early with either Scars or ROE but my memory is hazy or the decisionmaking may have changed. I'm cool with either way.slapshot5 wrote:We're talking Mirrodin:Beseiged, right?

So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
-
Hellfish - Programmer
- Posts: 1297
- Joined: 07 Jun 2009, 10:41
- Location: South of the Pumphouse
- Has thanked: 110 times
- Been thanked: 169 times
Re: Trigger discussion (was WheneverKeyword reference)
by friarsol » 11 Jan 2011, 04:50
Hellfish, it looks like the area of getAbilityText() you added your triggers in is for Instants and Sorceries only. I'm not sure why there is a need for two different sections in this code, but there seems that there is. So scroll down further in this function and add it down there as well. I think instead of this ugly line of code...
With that change I was able to get the trigger text working properly.
- Code: Select all
sb.append(trig.getMapParams().get("TriggerDescription").replace("CARDNAME", getName()) + "\r\n");
- Code: Select all
sb.append(trigger.toString())
With that change I was able to get the trigger text working properly.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Trigger discussion (was WheneverKeyword reference)
by sentient6 » 11 Jan 2011, 04:53
I may be a bit off base with this, and considering how new I am to the project there is absolutely no need to listen to what I say. But:
It seems to me that some of the logic in the TriggerHandler class might better be moved into the Trigger class, with subclasses of the Trigger class for each Trigger condition or something of the sort, mirroring the structuring of the AbilityFactory classes. Then the tests of validity could be handled in each subclass. Also, perhaps the spell abilities could be created in the trigger instances instead of being recreated each time the ability is triggered. Maybe these could be put in a subpackage of the forge package. If that makes sense to you, feel free to consider any or none of these ideas. Looking good by the way. That's my 1.5-2.1 cents...
It seems to me that some of the logic in the TriggerHandler class might better be moved into the Trigger class, with subclasses of the Trigger class for each Trigger condition or something of the sort, mirroring the structuring of the AbilityFactory classes. Then the tests of validity could be handled in each subclass. Also, perhaps the spell abilities could be created in the trigger instances instead of being recreated each time the ability is triggered. Maybe these could be put in a subpackage of the forge package. If that makes sense to you, feel free to consider any or none of these ideas. Looking good by the way. That's my 1.5-2.1 cents...
- sentient6
- Posts: 13
- Joined: 03 Jan 2011, 00:48
- Has thanked: 0 time
- Been thanked: 0 time
Re: Trigger discussion (was WheneverKeyword reference)
by Hellfish » 11 Jan 2011, 05:20
Mirrroring the AbilityFactories was my first intention, but I sort of drifted from that as I worked more towards "Just work" rather than "work good, look nice". But hey, that's what first drafts are for 
Oh and ideas are usually worth listening to, no matter how new the source is
EDIT: The description fix worked! Thanks, Sol!

Oh and ideas are usually worth listening to, no matter how new the source is

EDIT: The description fix worked! Thanks, Sol!
So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
-
Hellfish - Programmer
- Posts: 1297
- Joined: 07 Jun 2009, 10:41
- Location: South of the Pumphouse
- Has thanked: 110 times
- Been thanked: 169 times
Re: Trigger discussion (was WheneverKeyword reference)
by Sloth » 11 Jan 2011, 10:23
I just saw that you added RequireCounters as a parameter and want to point out, that I think that ControlsValid could have handled that with a restriction like: ControlsValid$ Card.Self+countersGE8LEVEL.
I would also propose to replace ControlsValid with isPresent (and thus considering all cards on the battlefield) and check the controller with YouCtrl or YouDontCtrl in the restriction string.
I would also propose to replace ControlsValid with isPresent (and thus considering all cards on the battlefield) and check the controller with YouCtrl or YouDontCtrl in the restriction string.
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: Trigger discussion (was WheneverKeyword reference)
by Hellfish » 11 Jan 2011, 10:58
Thanks for the tip! I'll commit the replacement in just a little while.
So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
-
Hellfish - Programmer
- Posts: 1297
- Joined: 07 Jun 2009, 10:41
- Location: South of the Pumphouse
- Has thanked: 110 times
- Been thanked: 169 times
Re: Trigger discussion (was WheneverKeyword reference)
by Hellfish » 12 Jan 2011, 14:54
Threw together a bit of a tutorial for triggers here but I'd like a second pair of eyes to go over it since I've been waistdeep in the code for about 2 days straight. 
EDIT: Ugh, posted the wrong version and deleted the actual finished one
A section on trigger restrictions is forthcoming.

EDIT: Ugh, posted the wrong version and deleted the actual finished one

So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
-
Hellfish - Programmer
- Posts: 1297
- Joined: 07 Jun 2009, 10:41
- Location: South of the Pumphouse
- Has thanked: 110 times
- Been thanked: 169 times
Re: Trigger discussion (was WheneverKeyword reference)
by friarsol » 12 Jan 2011, 15:48
Some comments just on what I'm reading since I haven't really looked too much into your code.
Attacks>Unblocked/ValidBlocker. A creature isn't Unblocked until after blockers are declared. But your docs suggest this triggers before then, so does this work properly? Does that trigger happen later? Maybe just specify that there is one for Attacking and one for being blocked/not being blocked.
Phase: Are there any cards that trigger at the end of a phase? I thought all cards were errata'd so triggers happen at the beginning of phases.
Example: Your Example has Contagion Clasp's ability putting a counter on itself (oops) since it's missing the target parameter.
General thought: If more than one trigger happens during the same trigger segment, how is the ordering handled? I'm guessing right now it's just in whatever order it happens to go.
We should make note that all triggers that happen at the same time follow the APNAP rule. Since whoever controls the trigger gets to choose the order, active players triggers go on first, then non-active players does the same.
Triggers
Lastly, and this will probably come in after the initial deployment, is the "intervening if clause" but I have a feeling this needs more work on the AF and the Trigger side. (Since the Trigger checks the conditional before it hits the stack, and the Ability needs to check the conditional as it's resolving)
Attacks>Unblocked/ValidBlocker. A creature isn't Unblocked until after blockers are declared. But your docs suggest this triggers before then, so does this work properly? Does that trigger happen later? Maybe just specify that there is one for Attacking and one for being blocked/not being blocked.
Phase: Are there any cards that trigger at the end of a phase? I thought all cards were errata'd so triggers happen at the beginning of phases.
Example: Your Example has Contagion Clasp's ability putting a counter on itself (oops) since it's missing the target parameter.
General thought: If more than one trigger happens during the same trigger segment, how is the ordering handled? I'm guessing right now it's just in whatever order it happens to go.
We should make note that all triggers that happen at the same time follow the APNAP rule. Since whoever controls the trigger gets to choose the order, active players triggers go on first, then non-active players does the same.
Triggers
Lastly, and this will probably come in after the initial deployment, is the "intervening if clause" but I have a feeling this needs more work on the AF and the Trigger side. (Since the Trigger checks the conditional before it hits the stack, and the Ability needs to check the conditional as it's resolving)
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Re: Trigger discussion (was WheneverKeyword reference)
by Sloth » 12 Jan 2011, 16:00
Looking at the Restrictions, I propose to merge CardsIn and IsPresent. I think everything could be done by three parameters IsPresent$ (using isValid), PresentCompare$ (LE5, EQ1, etc, defaults to GE1) and PresentZone$ (defaults to Battlefield). That way all restrictions are taken care of and we only need one syntax (which happens to be the same as the syntax of the AF's, but for PresentZone).Hellfish wrote:Threw together a bit of a tutorial for triggers here but I'd like a second pair of eyes to go over it since I've been waistdeep in the code for about 2 days straight.
EDIT: Ugh, posted the wrong version and deleted the actual finished oneA section on trigger restrictions is forthcoming.
-
Sloth - Programmer
- Posts: 3498
- Joined: 23 Jun 2009, 19:40
- Has thanked: 125 times
- Been thanked: 507 times
Re: Trigger discussion (was WheneverKeyword reference)
by Hellfish » 12 Jan 2011, 17:46
I'll be the first to admit the combat code slightly makes my head spin. I am looking at some candidates for places to put the runTrigger calls,tough.friarsol wrote:Attacks>Unblocked/ValidBlocker. A creature isn't Unblocked until after blockers are declared. But your docs suggest this triggers before then, so does this work properly? Does that trigger happen later? Maybe just specify that there is one for Attacking and one for being blocked/not being blocked.
Huh, could've sworn there were older cards that triggered on ends of phases. Must be my Shandalar-itis acting upPhase: Are there any cards that trigger at the end of a phase? I thought all cards were errata'd so triggers happen at the beginning of phases.

Misspelling in a big wayExample: Your Example has Contagion Clasp's ability putting a counter on itself (oops) since it's missing the target parameter.

Currently they go off in the order they were registered with the triggerhandler which depends on the order the cards are in in the Deck object passed to GameAction.newGame. I'll look into it right away.General thought: If more than one trigger happens during the same trigger segment, how is the ordering handled? I'm guessing right now it's just in whatever order it happens to go.
We should make note that all triggers that happen at the same time follow the APNAP rule. Since whoever controls the trigger gets to choose the order, active players triggers go on first, then non-active players does the same.
Triggers
Yeah, currently AFs are completely separate from Triggers (in the sense of no overlapping code I mean..I think.)Lastly, and this will probably come in after the initial deployment, is the "intervening if clause" but I have a feeling this needs more work on the AF and the Trigger side. (Since the Trigger checks the conditional before it hits the stack, and the Ability needs to check the conditional as it's resolving)
Good call. Consider it done!Sloth wrote:Looking at the Restrictions, I propose to merge CardsIn and IsPresent. I think everything could be done by three parameters IsPresent$ (using isValid), PresentCompare$ (LE5, EQ1, etc, defaults to GE1) and PresentZone$ (defaults to Battlefield). That way all restrictions are taken care of and we only need one syntax (which happens to be the same as the syntax of the AF's, but for PresentZone).
So now you're
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
Screaming for the blood of the cookie monster
Evil puppet demon of obesity
Time to change the tune of his fearful ballad
C is for "Lettuce," that's good enough for me
-
Hellfish - Programmer
- Posts: 1297
- Joined: 07 Jun 2009, 10:41
- Location: South of the Pumphouse
- Has thanked: 110 times
- Been thanked: 169 times
Re: Trigger discussion (was WheneverKeyword reference)
by friarsol » 12 Jan 2011, 18:33
I think we can probably just reuse the functions that are already being called instead of having them in the DeclareAttackers/DeclareBlockers functions.Hellfish wrote:I'll be the first to admit the combat code slightly makes my head spin. I am looking at some candidates for places to put the runTrigger calls,tough.
In CombatUtil, there is checkDeclareAttackers(), checkUnblockedAttackers(), checkDeclareBlockers(), checkBlockedAttackers() that all use checkWheneverKeyword().
Since the goal is to have Triggers ultimately replace the wheneverKeyword, I would call those prime candidates.
- friarsol
- Global Moderator
- Posts: 7593
- Joined: 15 May 2010, 04:20
- Has thanked: 243 times
- Been thanked: 965 times
Who is online
Users browsing this forum: No registered users and 4 guests