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

EffectSource(): something of unexpected relevance

Moderator: CCGHQ Admins

EffectSource(): something of unexpected relevance

Postby thefiremind » 10 Aug 2012, 12:19

I discovered the functionality of the EffectSource() function only recently, and I realized that I had a ton of cards to fix after that, so I want to make those discoveries public and well explained.

Do you remember that bug that I found a few days after the release of DotP2013? I bounced Timbermaw Larva to its owner's hand in response to its triggered ability, then the opponent played it again and it had the pumping as it had always been on the battlefield. Same goes for Liliana's Shade, which has been reported on the Wizards forums.

Look at the code for Liliana's Shade (conveniently indented because the original code was all on the same line):
Code: Select all
    <CONTINUOUS_ACTION layer="7C">
    local characteristics = Object():GetCurrentCharacteristics()
    characteristics:Power_Add( 1 )
    characteristics:Toughness_Add( 1 )
    </CONTINUOUS_ACTION>
Compare it to the code for Dragon Hatchling:
Code: Select all
    <CONTINUOUS_ACTION layer="7C">
    if EffectSource() ~= nil then
       EffectSource():GetCurrentCharacteristics():Power_Add( 1 )
       EffectSource():GetCurrentCharacteristics():Toughness_Add( 0 )
    end
    </CONTINUOUS_ACTION>
The difference is obvious: Liliana's Shade works on Object() while Dragon Hatchling works on EffectSource().
The right way to handle this kind of effects, where a card modifies its own characteristics until end of turn, is with EffectSource(). The reason is that EffectSource() works the same way as a "CardPtr": after being automatically initialized during the processing of the ability, it gets deleted if the card changes zone. That's exactly what we want in this case. When our Timbermaw Larva or Liliana's Shade or whatever gets bounced back to hand, Object() still points at the card, while EffectSource() doesn't, so the effect gets nullified.

This also means that you have to be a little more careful when the zone change is planned to happen. Let's take the trigger for the undying mechanic as example:
Code: Select all
    <TRIGGER value="ZONECHANGE_BEGIN" simple_qualifier="self" to_zone="ZONE_GRAVEYARD" from_zone="ZONE_IN_PLAY">
    if (Object():CountCounters( MTG():PlusOnePlusOneCounters() ) == 0) then
      EffectDC():Protect_CardPtr(COMPARTMENT_ID_EFFECT_SOURCE)
      return true
    else
      return false
    end
    </TRIGGER>
As you can see, there's a call to EffectDC():Protect_CardPtr(COMPARTMENT_ID_EFFECT_SOURCE). This is needed because the card is about to change zone, and we want EffectSource() to preserve its address. Incidentally, this demonstrates that EffectSource() should be functionally equivalent to EffectDC():Get_CardPtr(COMPARTMENT_ID_EFFECT_SOURCE).

To all the DotP2013 modders: I hope this has been helpful. Check your cards and make sure that you follow those guidelines. :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

Return to Documentation

Who is online

Users browsing this forum: No registered users and 14 guests


Who is online

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

Login Form