It is currently 20 Apr 2024, 03:11
   
Text Size

Trigger Handling

Post MTG Forge Related Programming Questions Here

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

Trigger Handling

Postby friarsol » 17 Sep 2014, 15:46

Last night I was playing around with Trigger Handling. Basically what I'm going to try to do is the following:

After state is finished being checked, just before a player gets priority each trigger that is "active" will be locked in, and recorded to a list in TriggerHandler. I'll check many of the trigger requirements (host card zone, threshold, etc) before being marked as active. Then when we run the waiting triggers during the next state check, we'll run the second half of the active trigger's requirements (those specific to the runParams). This also should help speed up this portion of the code, since for each trigger we were looping through all of the cards and checking for its triggers, where now we'll just be assigning active triggers once for each check, and then we only loop through those triggers. Basically, since these triggers will already be "locked" then we won't have to worry about LKI information when dealing with the trigger firing.


My first tests are ETB, and LTB/Dies.

So for example, I want to do the following:
Cast Sengir Autocrat
Cast Blood Artist
Cast Damnation.

Autocrat should trigger once on ETB, once on LTB.
Blood Artist should trigger 5 times on Damnation resolution.


If anyone has specific triggers they want me to test while I work on this, please let me know. I'll slowly expand out as I get specific triggers working.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Trigger Handling

Postby KrazyTheFox » 17 Sep 2014, 16:47

Sounds good to me and it seems like this'll be halfway there as far as the engine rewrite is concerned. Here's my general outline for handling triggers for that:

Each card will register triggers with the Game object (which is where the new game loop will be). When a GameAction is executed by the Game, it'll check to see if there's any triggers listed for that particular action, then it'll loop through those to figure out which ones should activate, then store the activated triggers in a list.

The Game will then wait until whatever it was doing is finished, then it'll add the triggers to the stack in order.

For example, I cast and resolve a creature that triggers a Soul Attendant's ability. That ability is added to the game's active trigger list. The game will finish the GameEvent that moves the creature, after which it'll add the triggers to the stack and remove them from the active triggers list.

--

As for particular triggers I'd like to see, Life Gain is high on my list since I like running tokens/life gain a lot (there's also those couple life gain decks in quest mode), which activates sometimes 100s of triggers.

Good luck implementing this; it'll be really nice to be able to copy and paste some of it to the new engine code!
User avatar
KrazyTheFox
Programmer
 
Posts: 725
Joined: 18 Mar 2014, 23:51
Has thanked: 66 times
Been thanked: 226 times

Re: Trigger Handling

Postby Marek14 » 17 Sep 2014, 16:52

How would this handle state triggers like Endangered Armodon? The main problem (for me) with these is that it's hard to make a list of them since their wordings are very variable...

Also, with Sidisi and Rakshasa Vizier, it might be time for another look at damage triggers which trigger on something "dealing damage" or "being dealt damage" and which should therefore trigger only once even if there are multiple recipients/sources of damage (Dromad Purebred or Soul Link being an example).
Marek14
Tester
 
Posts: 2759
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 296 times

Re: Trigger Handling

Postby friarsol » 17 Sep 2014, 17:10

Marek14 wrote:How would this handle state triggers like Endangered Armodon? The main problem (for me) with these is that it's hard to make a list of them since their wordings are very variable...

Also, with Sidisi and Rakshasa Vizier, it might be time for another look at damage triggers which trigger on something "dealing damage" or "being dealt damage" and which should therefore trigger only once even if there are multiple recipients/sources of damage (Dromad Purebred or Soul Link being an example).
"Always" triggers are already treated a bit differently in the code, since they can only be on the stack one at a time and they don't really "trigger" in the same fashion that other triggers do. They just check for their conditions constantly. I'll put Endangered Armodon on the list (examples of other "Always" triggers are Islandhome creatures). I don't believe any of that should change, an "Always" trigger is active as long as it meets the standard requirements AND that trigger isn't on the stack already.

Yea if this goes smoothly I can take a look at how the damage is firing right now. Although most (if not all) of this work will be in the core of receiving and running triggers as oppposed to when they fire (which is what the problem that damage triggers have right now).
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Trigger Handling

Postby friarsol » 18 Sep 2014, 03:18

Looks like all of the above are working right now (not counting the consolidation of damage). I just noticed an issue with Clones copying triggering, which makes sense since the Clone isn't actually cloned when the triggers are set. I'll see what I can do about that. The code changes aren't that huge, so I'm hoping this will work with all my testing.

I'll try to at least test one of each Trigger type as I play some more matches.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Trigger Handling

Postby friarsol » 18 Sep 2014, 17:44

Mostly a reminder for myself:

Test Ashcloud Phoenix and also test Loyal Cathar
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Trigger Handling

Postby Marek14 » 18 Sep 2014, 18:30

friarsol wrote:Mostly a reminder for myself:

Test Ashcloud Phoenix and also test Loyal Cathar
If you test these two, maybe also Homura, Human Ascendant, just in case? :)
Marek14
Tester
 
Posts: 2759
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 296 times

Re: Trigger Handling

Postby friarsol » 18 Sep 2014, 23:46

Marek14 wrote:If you test these two, maybe also Homura, Human Ascendant, just in case? :)
Does this work right now at all? I was just testing it and it seems to come back into play flipped (when killing it), but then I goto cast Disenchant on enchantment variety, it flips before I can target it?

Edit: Ahh.. I think the script is wrong. If someone can confirm for me that the return to play ability doesn't actually flip properly in a current/snapshot build. I'll just fix the script to work the way it should.

Also, it's good I tested Loyal Cathar, because apparently delayed triggers were broken and I hadn't tested those yet.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Trigger Handling

Postby Marek14 » 19 Sep 2014, 04:36

friarsol wrote:
Marek14 wrote:If you test these two, maybe also Homura, Human Ascendant, just in case? :)
Does this work right now at all? I was just testing it and it seems to come back into play flipped (when killing it), but then I goto cast Disenchant on enchantment variety, it flips before I can target it?

Edit: Ahh.. I think the script is wrong. If someone can confirm for me that the return to play ability doesn't actually flip properly in a current/snapshot build. I'll just fix the script to work the way it should.

Also, it's good I tested Loyal Cathar, because apparently delayed triggers were broken and I hadn't tested those yet.
I didn't actually test Homura, but it seemed very similar to those two :)
Marek14
Tester
 
Posts: 2759
Joined: 07 Jun 2008, 07:54
Has thanked: 0 time
Been thanked: 296 times

Re: Trigger Handling

Postby friarsol » 19 Sep 2014, 16:38

I just tested it on my desktop, the first half seems to work without the script change, but then it tries to retrigger each time the enchantment part dies. I'll commit the script fix when I commit the trigger changes.

Hopefully I can figure out the Clone LTB Trigger crash this weekend and get this all committed.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Trigger Handling

Postby friarsol » 21 Sep 2014, 03:26

Alright just committed this. I'm sure there's a few things left to tweak, but hopefully it's mostly working for everyone. I tried testing as many of the triggers I could test easily.
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times

Re: Trigger Handling

Postby friarsol » 05 Oct 2014, 21:52

Just noticed this one today. If Essence of the Wild is in play, and a creature ETB has an ETB trigger you get this:

ETB Crash | Open
Game-0 > java.lang.RuntimeException: AbilityFactory : getAbility -- no API in Essence of the Wild
at forge.game.ability.AbilityFactory.getAbility(AbilityFactory.java:108)
at forge.game.trigger.TriggerHandler.runSingleTrigger(TriggerHandler.java:438)
at forge.game.trigger.TriggerHandler.runNonStaticTriggersForPlayer(TriggerHandler.java:318)
at forge.game.trigger.TriggerHandler.runWaitingTrigger(TriggerHandler.java:287)
at forge.game.trigger.TriggerHandler.runWaitingTriggers(TriggerHandler.java:251)
at forge.game.zone.MagicStack.unfreezeStack(MagicStack.java:198)
at forge.game.zone.MagicStack.finishResolving(MagicStack.java:639)
at forge.game.zone.MagicStack.resolveStack(MagicStack.java:591)
at forge.game.phase.PhaseHandler.startFirstTurn(PhaseHandler.java:1077)
at forge.game.GameAction.startGame(GameAction.java:1585)
at forge.game.Match.startGame(Match.java:81)
at forge.match.MatchUtil$2.run(MatchUtil.java:232)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)


This is because the Card has changed in the middle of ETB (but the Trigger is already "Active").

I believe all I need to do to fix it is call:

game.getTriggerHandler().clearInstrinsicActiveTriggers(etbCreature) just before it turns into an EotW. Unfortunately, I'm not sure where in the code that inverted cloning happens. Anyone know?
friarsol
Global Moderator
 
Posts: 7593
Joined: 15 May 2010, 04:20
Has thanked: 243 times
Been thanked: 965 times


Return to Developer's Corner

Who is online

Users browsing this forum: KeithOvart and 90 guests


Who is online

In total there are 91 users online :: 1 registered, 0 hidden and 90 guests (based on users active over the past 10 minutes)
Most users ever online was 4143 on 23 Jan 2024, 08:21

Users browsing this forum: KeithOvart and 90 guests

Login Form