It is currently 18 Apr 2024, 22:03
   
Text Size

Approximating "counter target (activated) ability"

Moderator: CCGHQ Admins

Approximating "counter target (activated) ability"

Postby thefiremind » 20 Nov 2016, 20:24

I invented a way to make "counter target (activated) ability" possible. It's still barebone, and it suffers from approximations. My hope is to get new ideas from the other modders that will make it better.

Here are the currently known approximations:
  1. I wrote "activated" in brackets because my code works for activated abilities. You can try to generalize it for any ability, but it will start registering all of them, even replacement triggers, and it will become a mess, so I don't recommend to do it.
  2. You won't really "target" the ability, you'll just select it. This means that if you put my code on Squelch, you won't be able to change its target through other spells/abilities, unless you take the possibility into account on those other spells/abilities.
  3. The ability selection won't be very detailed: you will see the position in the stack (as a number) and the card title, that's all. A card choice from a chest would have been better, but how would I re-convert the chosen card to its position on the stack? The stack may contain multiple instances of activated abilities from the same card. I'm open to improvement suggestions.

The code uses my TFM_ObjectDC (which I made for Magic Duels), but you can use RSN_ObjectDC and obtain the same result. I'm not using LinkedDC because if you're planning to put the code on an activated ability (such as Azorius Guildmage's) you'll need to access the number of registered abilities in an AVAILABILITY block (so that you can't activate it if there are no targets), and LinkedDC can't be accessed from there.

The first part of the code registers the activated abilities in TFM_ObjectDC. You can put it into a manager if you wish, but then you should remember to access the manager's ObjectDC in the cards that use it.
Code: Select all
  <TRIGGERED_ABILITY replacement_effect="1">
    <TRIGGER value="ACTIVATED_ABILITY_PLAYED" />
    <RESOLUTION_TIME_ACTION>
    TFM_ObjectDC():Set_Int( TFM_ObjectDC():Get_Int(-1111), TriggerStackObjectID() )
    TFM_ObjectDC():Int_Add(-1111, 1) -- In DotP2014 you can use Int_Inc
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
  <TRIGGERED_ABILITY replacement_effect="1">
    <TRIGGER value="STATE_BASED_EFFECTS">
    local count = TFM_ObjectDC():Get_Int(-1111)
    return count &gt; 0 and MTG():GetStackObjectController( TFM_ObjectDC():Get_Int(count-1) ) == nil
    </TRIGGER>
    <RESOLUTION_TIME_ACTION>
    TFM_ObjectDC():Int_Add(-1111, -1) -- In DotP2014 you can use Int_Dec
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
I haven't been able to find a suitable trigger that's more specific than STATE_BASED_EFFECTS for removing abilities that left the stack from my list. STACK_POPPED seems broken, while ABILITY_RESOLVED fires too early (the ability is still on the stack) and doesn't bring a TriggerStackObjectID so I can't make any useful check with it. This happens on Magic Duels, results may vary on DotP2014: feel free to experiment.

The second part is the true ability that counters target activated ability. My example is for Azorius Guildmage:
Code: Select all
  <ACTIVATED_ABILITY>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[{2}{U}: Counter target activated ability.]]></LOCALISED_TEXT>
    <COST mana_cost="{2}{U}" type="Mana" />
    <AVAILABILITY>
    return TFM_ObjectDC():Get_Int(-1111) &gt; 0
    </AVAILABILITY>
    <PLAY_TIME_ACTION>
    local player = EffectController()
    local first = 0
    local count = TFM_ObjectDC():Get_Int(-1111)
    if count &gt; 7 then
       first = count-7
    end
    EffectDC():Set_Int(0, first)
    player:BeginNewMultipleChoice()
    for i=count-1,first do
       local id = TFM_ObjectDC():Get_Int(i)
       local card = MTG():GetStackObjectCard(id)
       if card ~= nil then
          player:AddMultipleChoiceAnswer( "("..id..") "..card:GetCardName() )
       end
    end
    player:AskMultipleChoiceQuestion("CARD_QUERY_CHOOSE_ABILITY_TO_COUNTER")
    </PLAY_TIME_ACTION>
    <PLAY_TIME_ACTION>
    local first = EffectDC():Get_Int(0)
    local id = TFM_ObjectDC():Get_Int( EffectController():GetMultipleChoiceResult()+first )
    EffectDC():Set_Int(1, id)
    </PLAY_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    local id = EffectDC():Get_Int(1)
    if MTG():GetStackObjectController(id) ~= nil then
       MTG():CounterStackObject(id)
    end
    </RESOLUTION_TIME_ACTION>
    <AI_AVAILABILITY type="in_response" />
  </ACTIVATED_ABILITY>
Since the limit for query choices in DotP2014 is 7, in case there are more than 7 activated abilities I'm picking the most recent 7 to get to the stack (it's quite a rare scenario anyway).

What do you think? :)
< 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: Approximating "counter target (activated) ability"

Postby Splinterverse2 » 28 Nov 2016, 21:36

thefiremind wrote:I invented a way to make "counter target (activated) ability" possible. It's still barebone, and it suffers from approximations. My hope is to get new ideas from the other modders that will make it better.

Here are the currently known approximations:
  1. I wrote "activated" in brackets because my code works for activated abilities. You can try to generalize it for any ability, but it will start registering all of them, even replacement triggers, and it will become a mess, so I don't recommend to do it.
  2. You won't really "target" the ability, you'll just select it. This means that if you put my code on Squelch, you won't be able to change its target through other spells/abilities, unless you take the possibility into account on those other spells/abilities.
  3. The ability selection won't be very detailed: you will see the position in the stack (as a number) and the card title, that's all. A card choice from a chest would have been better, but how would I re-convert the chosen card to its position on the stack? The stack may contain multiple instances of activated abilities from the same card. I'm open to improvement suggestions.

The code uses my TFM_ObjectDC (which I made for Magic Duels), but you can use RSN_ObjectDC and obtain the same result. I'm not using LinkedDC because if you're planning to put the code on an activated ability (such as Azorius Guildmage's) you'll need to access the number of registered abilities in an AVAILABILITY block (so that you can't activate it if there are no targets), and LinkedDC can't be accessed from there.

The first part of the code registers the activated abilities in TFM_ObjectDC. You can put it into a manager if you wish, but then you should remember to access the manager's ObjectDC in the cards that use it.
Code: Select all
  <TRIGGERED_ABILITY replacement_effect="1">
    <TRIGGER value="ACTIVATED_ABILITY_PLAYED" />
    <RESOLUTION_TIME_ACTION>
    TFM_ObjectDC():Set_Int( TFM_ObjectDC():Get_Int(-1111), TriggerStackObjectID() )
    TFM_ObjectDC():Int_Add(-1111, 1) -- In DotP2014 you can use Int_Inc
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
  <TRIGGERED_ABILITY replacement_effect="1">
    <TRIGGER value="STATE_BASED_EFFECTS">
    local count = TFM_ObjectDC():Get_Int(-1111)
    return count &gt; 0 and MTG():GetStackObjectController( TFM_ObjectDC():Get_Int(count-1) ) == nil
    </TRIGGER>
    <RESOLUTION_TIME_ACTION>
    TFM_ObjectDC():Int_Add(-1111, -1) -- In DotP2014 you can use Int_Dec
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
I haven't been able to find a suitable trigger that's more specific than STATE_BASED_EFFECTS for removing abilities that left the stack from my list. STACK_POPPED seems broken, while ABILITY_RESOLVED fires too early (the ability is still on the stack) and doesn't bring a TriggerStackObjectID so I can't make any useful check with it. This happens on Magic Duels, results may vary on DotP2014: feel free to experiment.

The second part is the true ability that counters target activated ability. My example is for Azorius Guildmage:
Code: Select all
  <ACTIVATED_ABILITY>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[{2}{U}: Counter target activated ability.]]></LOCALISED_TEXT>
    <COST mana_cost="{2}{U}" type="Mana" />
    <AVAILABILITY>
    return TFM_ObjectDC():Get_Int(-1111) &gt; 0
    </AVAILABILITY>
    <PLAY_TIME_ACTION>
    local player = EffectController()
    local first = 0
    local count = TFM_ObjectDC():Get_Int(-1111)
    if count &gt; 7 then
       first = count-7
    end
    EffectDC():Set_Int(0, first)
    player:BeginNewMultipleChoice()
    for i=count-1,first do
       local id = TFM_ObjectDC():Get_Int(i)
       local card = MTG():GetStackObjectCard(id)
       if card ~= nil then
          player:AddMultipleChoiceAnswer( "("..id..") "..card:GetCardName() )
       end
    end
    player:AskMultipleChoiceQuestion("CARD_QUERY_CHOOSE_ABILITY_TO_COUNTER")
    </PLAY_TIME_ACTION>
    <PLAY_TIME_ACTION>
    local first = EffectDC():Get_Int(0)
    local id = TFM_ObjectDC():Get_Int( EffectController():GetMultipleChoiceResult()+first )
    EffectDC():Set_Int(1, id)
    </PLAY_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    local id = EffectDC():Get_Int(1)
    if MTG():GetStackObjectController(id) ~= nil then
       MTG():CounterStackObject(id)
    end
    </RESOLUTION_TIME_ACTION>
    <AI_AVAILABILITY type="in_response" />
  </ACTIVATED_ABILITY>
Since the limit for query choices in DotP2014 is 7, in case there are more than 7 activated abilities I'm picking the most recent 7 to get to the stack (it's quite a rare scenario anyway).

What do you think? :)
I haven't read all of the code since I am on my phone but it looks/sounds good. It is nice to potentially have these cards be viable.
Splinterverse2
 
Posts: 52
Joined: 20 Sep 2016, 13:52
Has thanked: 13 times
Been thanked: 0 time

Re: Approximating "counter target (activated) ability"

Postby Xander9009 » 21 Jun 2018, 22:43

I've kept this in the back of my mind until I finally had the chance to mess with it, and I finally put this to use. It wasn't for targeting an ability, so it wasn't quite how you had it set up, but it was for Sundial of the Infinite, which needed to counter everything on the stack, which needed to include abilities. It worked well, so I imagine it'll work well for the original purpose, too.

EDIT: I'm aware it should technically be "exiling" the ability, but we have limited stack-ability interaction, so I'll take what I can get.
_______________________________
Community Wad - Community Wad Website - How to Help and Report Bugs
Discord: discord.gg/4AXvHzW
User avatar
Xander9009
Programmer
 
Posts: 2905
Joined: 29 Jun 2013, 07:44
Location: Indiana, United States
Has thanked: 121 times
Been thanked: 445 times


Return to Programming Talk

Who is online

Users browsing this forum: No registered users and 22 guests


Who is online

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

Login Form