It is currently 25 Apr 2024, 04:57
   
Text Size

DotP 2014 - Trying to force state based effects...

Moderator: CCGHQ Admins

DotP 2014 - Trying to force state based effects...

Postby RiiakShiNal » 10 Feb 2014, 23:18

I'm currently facing a dilemma I'm trying to grant and take away an ability from a STATIC_ABILITY using a LinkedDC() register to determine whether I need to add/remove the ability. In most cases this is very easy, but I need to trigger this change from a TRIGGERED_ABILITY that is set for replacement_effect and pre_trigger which is where things get dicey as setting the LinkedDC() variable there does not trigger STATE_BASED_EFFECTS so the ability doesn't get granted/removed until later. I can't grant the ability directly from the TRIGGERED_ABILITY because if I do then the ability will get added multiple times with no way to remove it other than LoseAllAbilities() which prevents re-adding the ability due to the ability that adds it being removed as well before STATE_BASED_EFFECTS are evaluated again.

It may be easier to understand if I provide some test code:
Non-Functional Test Code | Open
Code: Select all
   <MANA_ABILITY resource_id="0">
      <COST type="TapSelf" />
      <PRODUCES amount="{1}" />
   </MANA_ABILITY>
   <STATIC_ABILITY linked_ability_group="1">
      <CONTINUOUS_ACTION>
         if ((EffectSource() ~= nil) and (LinkedDC():Int_Get(0) == 1)) then
            EffectSource():GetCurrentCharacteristics():GrantAbility(0)
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
   <TRIGGERED_ABILITY replacement_effect="1" linked_ability_group="1">
      <TRIGGER value="CONSIDERED_FOR_CAST" pre_trigger="1">
         return ((TriggerObject() ~= nil) and
            (TriggerPlayer() == EffectController()))
      </TRIGGER>
      <RESOLUTION_TIME_ACTION>
         if (TriggerObject():GetCardType():Test( CARD_TYPE_ARTIFACT )) then
            LinkedDC():Int_Set( 0, 1 )
         else
            LinkedDC():Int_Set( 0, 0 )
         end
      </RESOLUTION_TIME_ACTION>
   </TRIGGERED_ABILITY>
The problem stems from the fact that the CONSIDERED_FOR_CAST trigger can activate multiple times (and even run it's RESOLUTION_TIME_ACTION multiple times) without triggering STATE_BASED_EFFECTS (so the STATIC_ABILITY doesn't get a chance to do its job). If you put the GrantAbility() in the TRIGGERED_ABILITY it will be granted to the card multiple times (which is wrong) thus causing the usual problems with more than one MANA_ABILITY being active on a card at once.
RiiakShiNal
Programmer
 
Posts: 2185
Joined: 16 May 2011, 21:37
Has thanked: 75 times
Been thanked: 497 times

Re: DotP 2014 - Trying to force state based effects...

Postby MC Brodie » 10 Feb 2014, 23:48

I don't understand what you are trying to do (and I'm probably out of my league). Would it work if you used another LinkedDC() register to see if the "CONSIDER_FOR_CAST" trigger should actually trigger? Something like this:

| Open
Code: Select all
   <MANA_ABILITY resource_id="0">
      <COST type="TapSelf" />
      <PRODUCES amount="{1}" />
   </MANA_ABILITY>
   <STATIC_ABILITY linked_ability_group="1">
      <CONTINUOUS_ACTION>
         if ((EffectSource() ~= nil) and (LinkedDC():Int_Get(0) == 1)) then
            EffectSource():GetCurrentCharacteristics():GrantAbility(0)
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
   <TRIGGERED_ABILITY replacement_effect="1" linked_ability_group="1">
      <TRIGGER value="CONSIDERED_FOR_CAST" pre_trigger="1">
         return ((TriggerObject() ~= nil) and
            (TriggerPlayer() == EffectController()) and
            (LinkedDC():Int_Get(1) == 0))
      </TRIGGER>
      <RESOLUTION_TIME_ACTION>
         LinkedDC():Int_Set( 1, 1 )
         if (TriggerObject():GetCardType():Test( CARD_TYPE_ARTIFACT )) then
            LinkedDC():Int_Set( 0, 1 )
         else
            LinkedDC():Int_Set( 0, 0 )
         end
      </RESOLUTION_TIME_ACTION>
   </TRIGGERED_ABILITY>
   <TRIGGERED_ABILITY linked_ability_group="1">
      <TRIGGER value="STATE_BASED_EFFECTS" /> -- just threw some triggers out there
      <TRIGGER value="SPELL_PLAYED" /> -- not sure what is correct for what you are doing
      <TRIGGER value="ABILITY_PLAYED" />
      <TRIGGER value="BEGINNING_OF_STEP" />
      <RESOLUTION_TIME_ACTION>
         LinkedDC():Int_Set( 1, 0 )
      </RESOLUTION_TIME_ACTION>
   </TRIGGERED_ABILITY>
-----------------------------------------------------------------------
Song of the Day: 46 and 2 (cover)
MC Brodie
 
Posts: 310
Joined: 01 Jun 2013, 00:10
Has thanked: 44 times
Been thanked: 34 times

Re: DotP 2014 - Trying to force state based effects...

Postby RiiakShiNal » 11 Feb 2014, 01:40

MC Brodie wrote:I don't understand what you are trying to do (and I'm probably out of my league). Would it work if you used another LinkedDC() register to see if the "CONSIDER_FOR_CAST" trigger should actually trigger? Something like this:

| Open
Code: Select all
   <MANA_ABILITY resource_id="0">
      <COST type="TapSelf" />
      <PRODUCES amount="{1}" />
   </MANA_ABILITY>
   <STATIC_ABILITY linked_ability_group="1">
      <CONTINUOUS_ACTION>
         if ((EffectSource() ~= nil) and (LinkedDC():Int_Get(0) == 1)) then
            EffectSource():GetCurrentCharacteristics():GrantAbility(0)
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
   <TRIGGERED_ABILITY replacement_effect="1" linked_ability_group="1">
      <TRIGGER value="CONSIDERED_FOR_CAST" pre_trigger="1">
         return ((TriggerObject() ~= nil) and
            (TriggerPlayer() == EffectController()) and
            (LinkedDC():Int_Get(1) == 0))
      </TRIGGER>
      <RESOLUTION_TIME_ACTION>
         LinkedDC():Int_Set( 1, 1 )
         if (TriggerObject():GetCardType():Test( CARD_TYPE_ARTIFACT )) then
            LinkedDC():Int_Set( 0, 1 )
         else
            LinkedDC():Int_Set( 0, 0 )
         end
      </RESOLUTION_TIME_ACTION>
   </TRIGGERED_ABILITY>
   <TRIGGERED_ABILITY linked_ability_group="1">
      <TRIGGER value="STATE_BASED_EFFECTS" /> -- just threw some triggers out there
      <TRIGGER value="SPELL_PLAYED" /> -- not sure what is correct for what you are doing
      <TRIGGER value="ABILITY_PLAYED" />
      <TRIGGER value="BEGINNING_OF_STEP" />
      <RESOLUTION_TIME_ACTION>
         LinkedDC():Int_Set( 1, 0 )
      </RESOLUTION_TIME_ACTION>
   </TRIGGERED_ABILITY>
The problem is that it always needs to trigger. Essentially this is my idea on how to get Mana restrictions working for cards like Mishra's Workshop. It needs to trigger whenever the player "considers" wanting to cast any spell if the player hovers over an allowable spell the CONSIDERED_FOR_CAST trigger sets the LinkedDC() register to 1 and the mana is usable, if the spell is not allowed then the LinkedDC() register is set to 0 and the mana is unusable for that spell. The problem comes in because after the LinkedDC() register has been set, by the TRIGGERED_ABILITY, STATE_BASED_EFFECTS need to be processed to allow the STATIC_ABILITY to grant the MANA_ABILITY, however, no matter how many times the CONSIDERED_FOR_CAST ability triggers STATE_BASED_EFFECTS don't run. So if I can force STATE_BASED_EFFECTS to run in between setting the LinkedDC() registers then I'll be set and can make the code generic to handle all sorts of conditions.

So for example the player has a Mishra's Workshop and an Island in play and an Azorius Keyrune, a Brainstorm, and a Chronozoa in hand. Given the lands in play the player should be able to cast both the Azorius Keyrune and the Brainstorm, but should not be able to cast the Chronozoa as the {3} provided by Mishra's Workshop can only be used for artifacts. Basically when hovers over Azorius Keyrune the CONSIDERED_FOR_CAST triggers and sets the LinkedDC() register to 1 and when the player hovers over either of the other cards it should trigger, set the LinkedDC() register to 0.

Your example won't work because it will only trigger once and even then doesn't solve the problem of getting the STATIC_ABILITY to process. There is no valid way to put the GrantAbility() in the TRIGGERED_ABILITY because once granted there is no way to remove it without use of LoseAllAbilities(), but then I can't re-grant it when they hover over another card (I could theoretically use a GrantAbility() afterwards to regain the TRIGGERED_ABILITY, but I would have to do that for all abilities meaning I would either need to rewrite the entire card to use granted abilities almost exclusively or have a second set of virtually identical abilities for all important abilities). Additionally, I'm not even sure that LoseAllAbilities() will affect MANA_ABILITYs in this case.

Ultimately, it may turn out that my idea won't work at all and I'll have to give it up.
RiiakShiNal
Programmer
 
Posts: 2185
Joined: 16 May 2011, 21:37
Has thanked: 75 times
Been thanked: 497 times

Re: DotP 2014 - Trying to force state based effects...

Postby thefiremind » 11 Feb 2014, 09:52

I'm afraid that what you are trying to do isn't possible (but I'd wait for an opinion by sumomole as well before giving up :wink:).
< Former DotP 2012/2013/2014 modder >
Currently busy with life...
User avatar
thefiremind
Programmer
 
Posts: 3515
Joined: 07 Nov 2011, 10:55
Has thanked: 118 times
Been thanked: 721 times

Re: DotP 2014 - Trying to force state based effects...

Postby sumomole » 11 Feb 2014, 12:32

I don't think CONSIDERED_FOR_CAST(CFC) ability can be used as a switch, because its trigger timing is very special. I use the following code to do a test and find its trigger timing consists of three parts.
1. when the test card onto the battlefield, CFC ability will trigger once for each nonland card in your hand.
2. when your mouse to point(not zoom in or click) a nonland card in your hand, CFC ability will continue to trigger until you move the mouse.
3. when your graveyard has a nonland card can be normal cast, such as Gravecrawler, CFC will continue to trigger, I think library and exile zone are the same.
I don't think we have a solution to the problems posed by the 3rd.
the trigger timing of CFC | Open
Code: Select all
  <CASTING_COST cost="" />
  <TYPE metaname="Creature" />
  <SUB_TYPE metaname="Human" />
  <SUB_TYPE metaname="Soldier" />
  <EXPANSION value="DPI" />
  <RARITY metaname="R" />
  <POWER value="2" />
  <TOUGHNESS value="2" />
  <TRIGGERED_ABILITY replacement_effect="1" linked_ability_group="1">
    <TRIGGER value="CONSIDERED_FOR_CAST" simple_qualifier="controller" pre_trigger="1" />
    <RESOLUTION_TIME_ACTION>
    EffectController():GainLife(1)
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
  <TRIGGERED_ABILITY active_zone="ZONE_STACK">
    <TRIGGER value="SPELL_PLAYED" simple_qualifier="self" />
    <RESOLUTION_TIME_ACTION>
    EffectController():MillCards(3)
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
  <UTILITY_ABILITY qualifier="Normal_Cast" active_zone="ZONE_GRAVEYARD">
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[You may cast from your graveyard.]]></LOCALISED_TEXT>
  </UTILITY_ABILITY>
User avatar
sumomole
Programmer
 
Posts: 611
Joined: 07 Jun 2011, 08:34
Has thanked: 51 times
Been thanked: 234 times

Re: DotP 2014 - Trying to force state based effects...

Postby RiiakShiNal » 11 Feb 2014, 13:40

sumomole wrote:I don't think CONSIDERED_FOR_CAST(CFC) ability can be used as a switch, because its trigger timing is very special. I use the following code to do a test and find its trigger timing consists of three parts.
1. when the test card onto the battlefield, CFC ability will trigger once for each nonland card in your hand.
2. when your mouse to point(not zoom in or click) a nonland card in your hand, CFC ability will continue to trigger until you move the mouse.
3. when your graveyard has a nonland card can be normal cast, such as Gravecrawler, CFC will continue to trigger, I think library and exile zone are the same.
I don't think we have a solution to the problems posed by the 3rd.
the trigger timing of CFC | Open
Code: Select all
  <CASTING_COST cost="" />
  <TYPE metaname="Creature" />
  <SUB_TYPE metaname="Human" />
  <SUB_TYPE metaname="Soldier" />
  <EXPANSION value="DPI" />
  <RARITY metaname="R" />
  <POWER value="2" />
  <TOUGHNESS value="2" />
  <TRIGGERED_ABILITY replacement_effect="1" linked_ability_group="1">
    <TRIGGER value="CONSIDERED_FOR_CAST" simple_qualifier="controller" pre_trigger="1" />
    <RESOLUTION_TIME_ACTION>
    EffectController():GainLife(1)
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
  <TRIGGERED_ABILITY active_zone="ZONE_STACK">
    <TRIGGER value="SPELL_PLAYED" simple_qualifier="self" />
    <RESOLUTION_TIME_ACTION>
    EffectController():MillCards(3)
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
  <UTILITY_ABILITY qualifier="Normal_Cast" active_zone="ZONE_GRAVEYARD">
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[You may cast from your graveyard.]]></LOCALISED_TEXT>
  </UTILITY_ABILITY>
Actually I pretty well understand how the CONSIDERED_FOR_CAST trigger works and continuing to trigger isn't really the problem. Also CONSIDERED_FOR_CAST will also trigger for land cards in your hand (it did so in several of my tests). I can limit how often the register is set and even how often the TRIGGERED_ABILITY fires. The issue is that regardless of whether CONSIDERED_FOR_CAST triggers once or a thousand times it does not run STATE_BASED_EFFECTS afterwards so the STATIC_ABILITY never gets a chance to do its job.
RiiakShiNal
Programmer
 
Posts: 2185
Joined: 16 May 2011, 21:37
Has thanked: 75 times
Been thanked: 497 times

Re: DotP 2014 - Trying to force state based effects...

Postby NeoAnderson » 11 Feb 2014, 17:28

Riiak i made some test I think you can resolve this issue using the function MTG():ReevaluateContinuousEffects(). (It seems to force the State_Base_Effect evaluation so could be what you are looking for)
I also find the follow thing :
1. CONSIDERED_FOR_CAST will automatically called for the first left card on your hand, doesn't matter if you are pointing it with the mouse.

I also made some modify to your code and i think you could avoid to grant the ability into static ability, just adding it into the trigger ability, but i still have some troubles with the duration.
Anyway you could make some test using the follow code :
Code: Select all
<TRIGGERED_ABILITY replacement_effect="1" linked_ability_group="1">
      <TRIGGER value="CONSIDERED_FOR_CAST" pre_trigger="1">
         if ((TriggerObject() ~= nil) and (TriggerPlayer() == EffectController())) then
            if (TriggerObject():GetCardType():Test( CARD_TYPE_ARTIFACT )) then
               if (LinkedDC():Int_Get(0) == 0) then
                   LinkedDC():Int_Set( 0, 1 )
                   if ((EffectSource() ~= nil)  and (LinkedDC():Int_Get(0) == 1)) then
                    MTG():ReevaluateContinuousEffects()
                      return true
                   end
               end
            else
              LinkedDC():Int_Set( 0, 0 )
              return false
            end 
         end
      </TRIGGER>
      <CONTINUOUS_ACTION layer="6" >
         if (EffectSource() ~= nil) then
            if (LinkedDC():Int_Get(0) == 1) then
               EffectSource():GetCurrentCharacteristics():GrantAbility(0)
               LinkedDC():Int_Inc(0)
            end
         end
      </CONTINUOUS_ACTION>
      <DURATION>
       if LinkedDC():Int_Get(0) == 0 then
          return true
       end
      </DURATION>
</TRIGGERED_ABILITY>
I am still not sure it works as you expected but try it, i have tested it with a non mana ability and it is granted while the card to cast is an artifact.
NeoAnderson
 
Posts: 914
Joined: 10 Sep 2013, 07:49
Has thanked: 18 times
Been thanked: 139 times

Re: DotP 2014 - Trying to force state based effects...

Postby RiiakShiNal » 11 Feb 2014, 19:32

NeoAnderson wrote:Riiak i made some test I think you can resolve this issue using the function MTG():ReevaluateContinuousEffects(). (It seems to force the State_Base_Effect evaluation so could be what you are looking for)
ReevaluateContinuousEffects() is exactly what I was looking for, though I don't know how I missed it on the function list. #-o

NeoAnderson wrote:I also find the follow thing :
1. CONSIDERED_FOR_CAST will automatically called for the first left card on your hand, doesn't matter if you are pointing it with the mouse.
Actually, when the card first enters the battlefield it seems to trigger for all cards in your hand.

NeoAnderson wrote:I also made some modify to your code and i think you could avoid to grant the ability into static ability, just adding it into the trigger ability, but i still have some troubles with the duration.
Anyway you could make some test using the follow code :
Code: Select all
<TRIGGERED_ABILITY replacement_effect="1" linked_ability_group="1">
      <TRIGGER value="CONSIDERED_FOR_CAST" pre_trigger="1">
         if ((TriggerObject() ~= nil) and (TriggerPlayer() == EffectController())) then
            if (TriggerObject():GetCardType():Test( CARD_TYPE_ARTIFACT )) then
               if (LinkedDC():Int_Get(0) == 0) then
                   LinkedDC():Int_Set( 0, 1 )
                   if ((EffectSource() ~= nil)  and (LinkedDC():Int_Get(0) == 1)) then
                    MTG():ReevaluateContinuousEffects()
                      return true
                   end
               end
            else
              LinkedDC():Int_Set( 0, 0 )
              return false
            end 
         end
      </TRIGGER>
      <CONTINUOUS_ACTION layer="6" >
         if (EffectSource() ~= nil) then
            if (LinkedDC():Int_Get(0) == 1) then
               EffectSource():GetCurrentCharacteristics():GrantAbility(0)
               LinkedDC():Int_Inc(0)
            end
         end
      </CONTINUOUS_ACTION>
      <DURATION>
       if LinkedDC():Int_Get(0) == 0 then
          return true
       end
      </DURATION>
</TRIGGERED_ABILITY>
I am still not sure it works as you expected but try it, i have tested it with a non mana ability and it is granted while the card to cast is an artifact.
Your method will create and remove new continuous effects all the time (which will then require checking the durations), a STATIC_ABILITY works better in this case as you have a single ability that gets updated rather than continuously creating and removing effects.

Using ReevaluateContinuousEffects() I have managed to get a mostly working version, but there is still a timing issue with the actual casting (though I may be able to solve that with a few more tests).
Closer to working code | Open
Code: Select all
   <MANA_ABILITY resource_id="0">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[{T}: Produce {1}]]></LOCALISED_TEXT>
      <COST type="TapSelf" />
      <PRODUCES amount="{1}" />
   </MANA_ABILITY>
   <STATIC_ABILITY linked_ability_group="1">
      <CONTINUOUS_ACTION layer="0">
         if ((EffectSource() ~= nil) and (LinkedDC():Int_Get(0) == 1)) then
            EffectSource():GetCurrentCharacteristics():GrantAbility(0)
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
   <TRIGGERED_ABILITY replacement_effect="1" linked_ability_group="1">
      <TRIGGER value="CONSIDERED_FOR_CAST" pre_trigger="1">
         return ((TriggerObject() ~= nil) and
            (TriggerObject() ~= LinkedDC():Get_CardPtr(1)) and
            (TriggerPlayer() == EffectController()))
      </TRIGGER>
      <RESOLUTION_TIME_ACTION>
         LinkedDC():Set_CardPtr( 1, TriggerObject() )
         if (TriggerObject():GetCardType():Test( CARD_TYPE_ARTIFACT )) then
            if (LinkedDC():Int_Get(0) ~= 1) then
               LinkedDC():Int_Set( 0, 1 )
               MTG():ReevaluateContinuousEffects()
            end
         else
            if (LinkedDC():Int_Get(0) ~= 0) then
               LinkedDC():Int_Set( 0, 0 )
               MTG():ReevaluateContinuousEffects()
            end
         end
      </RESOLUTION_TIME_ACTION>
   </TRIGGERED_ABILITY>
You can watch the " {T}: Produce {1}" text appear and disappear on the card as you move over the cards in your hand, but it seems to remove the mana ability right as you cast an artifact so the artifact gets cast for free (which is obviously wrong).

Edit: After several more tests I can say the mana ability is not being removed before cast and it does not seem it will be possible to get it working properly as the game does not seem to properly update the available mana sources on the fly. It does show that it is possible to cast artifacts using the restricted mana (which indicates at least a partial update of the MANA_ABILITY calculations), but when cast it does not correctly use the restricted mana for the artifact spell (so it gets cast for free). Then when you cast another spell after that which should not be able to use the restricted mana (because it isn't an artifact) it will still use the restricted mana even though the ability has already been removed from the card.

Example: I had 2 copies of Sejiri Refuge, 1 Kabira Crossroads, plus my test card (which produces {1}) in play and in hand I had an Azorius Keyrune, AEther Figment, and an Ajani's Sunstriker. I tapped a Sejiri Refuge (produced {U}), tapped the other Sejiri Refuge (produced {W}), Azorius Keyrune appeared available for cast (so far so good). I cast Azorius Keyrune (it cast for free, not good), then I cast AEther Figment (it tapped the test card even though the test card did not show the mana ability, not good). Now either it used the test card or the test card disappeared as a delayed reaction, if it used the test card then I should still have 1 {W} left over so I tapped the Kabira Crossroads (produced {W}) and Ajani's Sunstriker appeared as available to cast so I cast it and it used the remaining mana and was cast.

So it appears that the engine just can't handle enabling/disabling mana abilities on the fly like this. Thus ends my hopes at updating manual mana to be able to work with mana restrictions (unless I get lucky, have a stroke of genius, or someone else has a bright idea).
RiiakShiNal
Programmer
 
Posts: 2185
Joined: 16 May 2011, 21:37
Has thanked: 75 times
Been thanked: 497 times

Re: DotP 2014 - Trying to force state based effects...

Postby NeoAnderson » 11 Feb 2014, 22:30

As you pointed the Engine doesn't handle the mana resources in a right way, but this is not a new thing for this game.
I am sorry but i haven't other ideas to implement this code.
NeoAnderson
 
Posts: 914
Joined: 10 Sep 2013, 07:49
Has thanked: 18 times
Been thanked: 139 times

Re: DotP 2014 - Trying to force state based effects...

Postby RiiakShiNal » 11 Feb 2014, 23:14

NeoAnderson wrote:As you pointed the Engine doesn't handle the mana resources in a right way, but this is not a new thing for this game.
I am sorry but i haven't other ideas to implement this code.
No, it probably isn't new, but I also don't think it had been tested like this before either.

I did have another idea after I wrote my last post, but it only worked partly and that was to do another round of updates for continuous effects (essentially doubling the number of calls to ReevaluateContinuousEffects()), but that only served to prevent the restricted mana from being used for spells it shouldn't (still did not allow it to be used for spells it should). So still no way to make restricted mana work right.
RiiakShiNal
Programmer
 
Posts: 2185
Joined: 16 May 2011, 21:37
Has thanked: 75 times
Been thanked: 497 times


Return to Programming Talk

Who is online

Users browsing this forum: No registered users and 25 guests


Who is online

In total there are 25 users online :: 0 registered, 0 hidden and 25 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: No registered users and 25 guests

Login Form