It is currently 20 Apr 2024, 10:09
   
Text Size

[DotP2013] Help with Cipher

Moderator: CCGHQ Admins

[DotP2013] Help with Cipher

Postby BETenner » 13 Mar 2013, 03:45

I need help again... for Cipher.
My code doesn't work for the cipher part:

Code: Select all
  <SPELL_ABILITY dangerous="1" filter_zone="ZONE_IN_PLAY">
    <TARGET_DEFINITION id="0">
      local filter = Object():GetFilter()
      filter:Clear()
      filter:AddCardType( CARD_TYPE_CREATURE )
      filter:SetControllersTeam( EffectController():GetTeam() )
      filter:AddExtra( FILTER_EXTRA_FLIP_TEAM )
      filter:SetHint( HINT_ENEMY_ONLY, EffectController() )
      filter:SetZone( ZONE_IN_PLAY )
    </TARGET_DEFINITION>
    <TARGET_DETERMINATION>
      return AtLeastOneTargetFromDefinition(0)
    </TARGET_DETERMINATION>
    <TARGET_DEFINITION id="1">
      local filter = Object():GetFilter()
      filter:Clear()
      filter:AddCardType( CARD_TYPE_CREATURE )
      filter:SetPlayer( EffectController() )
      filter:SetZone( ZONE_IN_PLAY )
    </TARGET_DEFINITION>
    <PLAY_TIME_ACTION target_choosing="1">
      EffectController():ChooseTarget( 0, "CARD_QUERY_CHOOSE_CREATURE_TO_TAPHOLD", EffectDC():Make_Targets(0) )
    </PLAY_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
       local target = EffectDC():Get_Targets(0):Get_CardPtr(0)
      if (target ~= nil) then
          target:TapAndHold()
      end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
      if (Object():GetErstwhileZone() ~= ZONE_NOWHERE_YET) then
        local filter = Object():LoadTargetDefinition(1)
        if (filter:CountStopAt(1) == 1) then
          EffectController():ChooseTargetWithFlags( 1, "CARD_QUERY_CHOOSE_CREATURE_TO_CIPHER", EffectDC():Make_Targets(1), QUERY_FLAG_CAN_BE_FINISHED_EARLY + QUERY_FLAG_CAN_BE_FINISHED_EARLY_FOR_AI_AS_WELL )
        end
      end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_Targets(1):Get_CardPtr(0)
      if (target ~= nil) then
        ObjectDC():Set_CardPtr(0, target)
        ObjectDC():Protect_CardPtr(0)
        Object():SetResolutionZone( ZONE_REMOVED_FROM_GAME )
      end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
      local target = ObjectDC():Get_CardPtr(0)
      if (target ~= nil) then
        Object():NailOnto(target)
      end
    </RESOLUTION_TIME_ACTION>
  </SPELL_ABILITY>
  <TRIGGERED_ABILITY internal="1" active_zone="ZONE_REMOVED_FROM_GAME">
    <TRIGGER value="CREATURE_DEALS_COMBAT_DAMAGE_TO_PLAYER">
      local target = ObjectDC():Get_CardPtr(0)
      return (target ~= nil and target == TriggerObject())
    </TRIGGER>
    <RESOLUTION_TIME_ACTION>
      local target = ObjectDC():Get_CardPtr(0)
      if (target ~= nil) then
        local player = target:GetController()
        if (Object():CanBePlayed(player)) then
          player:CopySpellWithNewTargets(Object())
        end
      end
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
BETenner
 
Posts: 36
Joined: 07 Mar 2013, 14:20
Has thanked: 7 times
Been thanked: 4 times

Re: [DotP2013] Help with Cipher

Postby thefiremind » 13 Mar 2013, 10:32

First of all, I would put cipher in a separate spell ability: the card will work the same way, but it will be easier to copy cipher to other cards when needed. You also forgot NotTargetted() in the second target definition: cipher says "on a creature you control", not "on target creature you control"... I would have integrated the target filter directly in the resolution time action but that's just a personal choice.

Now, for the problem that prevents cipher from working: I think that it's because ObjectDC gets wiped when the card changes zone. You protected the card pointer, but it's useless because the whole ObjectDC gets wiped. Actually, not all zone changes wipe ObjectDC, that's something I never completely understood and that's why I like to avoid using ObjectDC when I can... but in this case you must use it. I'd suggest to exile the card first, and save the pointer to the target later. So this action:
Code: Select all
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_Targets(1):Get_CardPtr(0)
      if (target ~= nil) then
        ObjectDC():Set_CardPtr(0, target)
        ObjectDC():Protect_CardPtr(0)
        Object():SetResolutionZone( ZONE_REMOVED_FROM_GAME )
      end
    </RESOLUTION_TIME_ACTION>
would become:
Code: Select all
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_Targets(1):Get_CardPtr(0)
      if (target ~= nil) then
        Object():RemoveFromGame()
      end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_Targets(1):Get_CardPtr(0)
      if (target ~= nil) then
        ObjectDC():Set_CardPtr(0, target)
      end
    </RESOLUTION_TIME_ACTION>
There's a function, Object():RetainDataChest(), that should act as a protection for the whole ObjectDC, but while I was quite sure of its way of working on DotP2012, I'm not so sure on DotP2013 so I think it's better to find another solution when possible.
< 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: [DotP2013] Help with Cipher

Postby BETenner » 13 Mar 2013, 11:56

Thanks!
I'll try and test it in DotP2013.
BETenner
 
Posts: 36
Joined: 07 Mar 2013, 14:20
Has thanked: 7 times
Been thanked: 4 times

Re: [DotP2013] Help with Cipher

Postby BETenner » 13 Mar 2013, 13:18

It doesn't work.
Even if you exile the card first, then save the card pointer later. I still can't get the saved card pointer in the trigger (always get nil).
So any other idea?

Code: Select all
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_Targets(1):Get_CardPtr(0)
      if (target ~= nil) then
        Object():RemoveFromGame()
      end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_Targets(1):Get_CardPtr(0)
      if (target ~= nil) then
        ObjectDC():Set_CardPtr(0, target)
        Object():NailOnto(target)
      end
    </RESOLUTION_TIME_ACTION>
  </SPELL_ABILITY>
  <TRIGGERED_ABILITY internal="1" active_zone="ZONE_REMOVED_FROM_GAME">
    <TRIGGER value="CREATURE_DEALS_COMBAT_DAMAGE_TO_PLAYER">
      local target = ObjectDC():Get_CardPtr(0) -- Always get nil here
      return (target ~= nil and target == TriggerObject())
    </TRIGGER>
    <RESOLUTION_TIME_ACTION>
      local target = ObjectDC():Get_CardPtr(0)
      if (target ~= nil) then
        local player = target:GetController()
        if (Object():CanBePlayed(player)) then
          player:CopySpellWithNewTargets(Object())
        end
      end
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
BETenner
 
Posts: 36
Joined: 07 Mar 2013, 14:20
Has thanked: 7 times
Been thanked: 4 times

Re: [DotP2013] Help with Cipher

Postby RiiakShiNal » 13 Mar 2013, 13:39

What about using a delayed trigger to handle this? Then you don't have to mess around with whether the ObjectDC() gets wiped or not and you can simply use EffectDC().

Code: Select all
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_Targets(1):Get_CardPtr(0)
      if (target ~= nil) then
        local delayDC = EffectDC():Make_Chest(2)
        delayDC:Set_CardPtr(0, target)
        delayDC:Set_ProtectedCardPtr(1, Object())
        Object():RemoveFromGame()
        Object():NailOnto(target)
        MTG():CreateDelayedTrigger(1, delayDC)
      end
    </RESOLUTION_TIME_ACTION>
  </SPELL_ABILITY>
  <TRIGGERED_ABILITY resource_id="1" active_zone="ZONE_REMOVED_FROM_GAME">
    <TRIGGER value="CREATURE_DEALS_COMBAT_DAMAGE_TO_PLAYER">
      local target = EffectDC():Get_CardPtr(0)
      return (target ~= nil and target == TriggerObject())
    </TRIGGER>
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_CardPtr(0)
      local spell = EffectDC():Get_ProtectedCardPtr(1)
      if (target ~= nil) then
        local player = target:GetController()
        if (spell ~= nil) then
          if (spell:CanBePlayed(player)) then
            player:CopySpellAndCastIt(spell)
          end
        end
      end
    </RESOLUTION_TIME_ACTION>
    <CLEANUP>
      -- Remove DelayedTrigger when creature is no longer valid (changed zones)
      local target = EffectDC():Get_CardPtr(0)
      return (target == nil)
    </CLEANUP>
  </TRIGGERED_ABILITY>
Edit: Changed to use CopySpellAndCastIt() instead of CopySpellWithNewTargets() due to a problem pointed out in another thread.
Last edited by RiiakShiNal on 31 Mar 2013, 15:41, edited 1 time in total.
RiiakShiNal
Programmer
 
Posts: 2185
Joined: 16 May 2011, 21:37
Has thanked: 75 times
Been thanked: 497 times

Re: [DotP2013] Help with Cipher

Postby BETenner » 13 Mar 2013, 14:17

DelayedTrigger works!
Finally, cipher is done!
Thanks to you masters!

The final code are:
Code: Select all
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_Targets(1):Get_CardPtr(0)
      if (target ~= nil) then
        local delayDC = EffectDC():Make_Chest(2)
        delayDC:Set_CardPtr(0, target)
        delayDC:Set_ProtectedCardPtr(1, Object())
        Object():RemoveFromGame()
        Object():NailOnto(target)
        MTG():CreateDelayedTrigger(1, delayDC)
      end
    </RESOLUTION_TIME_ACTION>
  </SPELL_ABILITY>
  <TRIGGERED_ABILITY resource_id="1" active_zone="ZONE_REMOVED_FROM_GAME">
    <TRIGGER value="CREATURE_DEALS_COMBAT_DAMAGE_TO_PLAYER">
      local target = EffectDC():Get_CardPtr(0)
      return (target ~= nil and target == TriggerObject())
    </TRIGGER>
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_CardPtr(0)
      local spell = EffectDC():Get_ProtectedCardPtr(1)
      if (target ~= nil) then
        local player = target:GetController()
        if (spell ~= nil) then
          if (spell:CanBePlayed(player)) then
            -- Ask the player whether wants to play the ciphered spell or not
            player:BeginNewMultipleChoice()
            player:AddMultipleChoiceAnswer("CARD_QUERY_OPTION_YES")
            player:AddMultipleChoiceAnswer("CARD_QUERY_OPTION_NO")
            player:AskMultipleChoiceQuestion("CARD_QUERY_ASK_PLAY_CIPHERED_SPELL")
          end
        end
      end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
      local target = EffectDC():Get_CardPtr(0)
      local spell = EffectDC():Get_ProtectedCardPtr(1)
      if (target ~= nil) then
        local player = target:GetController()
        if (spell ~= nil) then
          if (spell:CanBePlayed(player)) then
            if (Object():GetMultipleChoiceResult() == 0) then
              player:CopySpellWithNewTargets(spell)
            end
          end
        end
      end
    </RESOLUTION_TIME_ACTION>
    <CLEANUP>
      -- Remove DelayedTrigger when creature is no longer valid (changed zones)
      local target = EffectDC():Get_CardPtr(0)
      return (target == nil)
    </CLEANUP>
  </TRIGGERED_ABILITY>
BETenner
 
Posts: 36
Joined: 07 Mar 2013, 14:20
Has thanked: 7 times
Been thanked: 4 times

Re: [DotP2013] Help with Cipher

Postby thefiremind » 13 Mar 2013, 14:49

Thanks from me, too: I was still missing a confirmation that the <CLEANUP> block can contain custom code like the <DURATION> block. :)
< 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: [DotP2013] Help with Cipher

Postby BETenner » 13 Mar 2013, 16:13

A small problem:

My Hands of Binding now works perfectly (all actions are done correctly including cipher mechanic). But I found the following line in SCRIPT_LOG.TXT:

Code: Select all
[lua] [string "HANDS_OF_BINDING_GTC_037_TITLE (RESOLUTION_TIME_ACTION) [902]"]:2: attempt to index a nil value
What could possibly wrong?
BETenner
 
Posts: 36
Joined: 07 Mar 2013, 14:20
Has thanked: 7 times
Been thanked: 4 times

Re: [DotP2013] Help with Cipher

Postby thefiremind » 13 Mar 2013, 17:31

BETenner wrote:A small problem:

My Hands of Binding now works perfectly (all actions are done correctly including cipher mechanic). But I found the following line in SCRIPT_LOG.TXT:

Code: Select all
[lua] [string "HANDS_OF_BINDING_GTC_037_TITLE (RESOLUTION_TIME_ACTION) [902]"]:2: attempt to index a nil value
What could possibly wrong?
There must be some scenario where a pointer gets deleted but everything working as expected anyway.
First, a bit of knowledge about SCRIPT_LOG.TXT: the message you got basically means that this error occurred in the 2nd line of a RESOLUTION_TIME_ACTION, where the 2nd line is actually the 1st line of code (I think it adds one line internally when picking up the code). The problem is, it doesn't tell you which RESOLUTION_TIME_ACTION it refers to... but in this case I think I can't go wrong: the EffectDC inside the delayed trigger is always initialised by the CreateDelayedTrigger, so it must be the RESOLUTION_TIME_ACTION before it. Try to change
Code: Select all
local target = EffectDC():Get_Targets(1):Get_CardPtr(0)
with
Code: Select all
local target = EffectDC():Get_Targets(1) and EffectDC():Get_Targets(1):Get_CardPtr(0)
It's a trick that pcastellazzi taught me: Lua language works so that
Code: Select all
(non_nil_value and A) = A
(nil and A) = nil
and because of the "short-circuit rule", when the first operand is nil, the second operand is ignored because there's no need to check it, so the error isn't generated.
< 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: [DotP2013] Help with Cipher

Postby RiiakShiNal » 13 Mar 2013, 19:57

thefiremind wrote:Thanks from me, too: I was still missing a confirmation that the <CLEANUP> block can contain custom code like the <DURATION> block. :)
Eh, it was more of a guess, but I thought why not.
RiiakShiNal
Programmer
 
Posts: 2185
Joined: 16 May 2011, 21:37
Has thanked: 75 times
Been thanked: 497 times

Re: [DotP2013] Help with Cipher

Postby sumomole » 17 Mar 2013, 22:01

702.97a Cipher appears on some instants and sorceries. It represents two static abilities, one that functions while the spell is on the stack and one that functions while the card with cipher is in the exile zone. "Cipher" means "If this spell is represented by a card, you may exile this card encoded on a creature you control" and "As long as this card is encoded on that creature, that creature has 'Whenever this creature deals combat damage to a player, you may copy this card and you may cast the copy without paying its mana cost.'"

The triggered ability on the endowed creature rather than the card with cipher. So you should use "GrantAbility", not "CreateDelayedTrigger".

I use an unconventional way to code Whispering Madness.
Code: Select all
  <SPELL_ABILITY filter_zone="ZONE_IN_PLAY">
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Cipher]]></LOCALISED_TEXT>
    <RESOLUTION_TIME_ACTION>
    if EffectSource() ~= nil and EffectSource():IsToken() == 0 then
      local filter = Object():GetFilter()
      filter:Clear()
      filter:May()
      filter:NotTargetted()
      filter:AddCardType( CARD_TYPE_CREATURE )
      filter:SetZone( ZONE_IN_PLAY )
      filter:SetController( EffectController() )   
      filter:SetHint( HINT_ALLIED, EffectController() )
      EffectController():ChooseTarget( NO_VALIDATION, "CARD_QUERY_CHOOSE_CREATURE_TO_ENCODE", EffectDC():Make_Targets(0) )
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    if EffectDC():Get_Targets(0) ~= nil then
      local target = EffectDC():Get_Targets(0):Get_CardPtr(0)
      if target ~= nil then
         EffectDC():Protect_CardPtr(COMPARTMENT_ID_EFFECT_SOURCE)
        EffectSource():RemoveFromGame()
      end
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    if EffectDC():Get_Targets(0) ~= nil then
      local target = EffectDC():Get_Targets(0):Get_CardPtr(0)
      if target ~= nil then
        if EffectSource():GetZone() == ZONE_REMOVED_FROM_GAME then
          EffectSource():NailOnto( target )
        end
      end
    end
    </RESOLUTION_TIME_ACTION>
    <CONTINUOUS_ACTION layer="6">
    if EffectDC():Get_Targets(0) ~= nil then
      local target = EffectDC():Get_Targets(0):Get_CardPtr(0)
      if target ~= nil then
        target:GetCurrentCharacteristics():GrantAbility(2)
      end
    end
    </CONTINUOUS_ACTION>
    <DURATION>
    return EffectSource():GetZone() ~= ZONE_REMOVED_FROM_GAME or EffectSource() == nil
    </DURATION>
  </SPELL_ABILITY>
Code: Select all
  <TRIGGERED_ABILITY resource_id="2" filter_zone="ZONE_IN_PLAY">
    <TRIGGER value="CREATURE_DEALS_COMBAT_DAMAGE_TO_PLAYER" simple_qualifier="self" />
    <RESOLUTION_TIME_ACTION>
    if EffectSource() ~= nil then
      local filter = Object():GetFilter()
      filter:Clear()
      filter:SetUnique()
      filter:NotTargetted()
      filter:SetZone( ZONE_REMOVED_FROM_GAME )
      filter:AddCardName( "WHISPERING_MADNESS" )
      local total = filter:EvaluateObjects()
      if total &gt; 0 then
        local cipherDC = EffectDC():Make_Chest(0)
        for i=0,total-1 do
          local card = filter:GetNthEvaluatedObject(i)      
          if card ~= nil then       
               cipherDC:Set_CardPtr(0, card)
          end
        end               
        end     
      end 
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    local browser = EffectDC():Get_Chest(0)
    local player = EffectController()
    if player ~= nil then
       if browser ~= nil then
          player:SetTargetCount( 1 )
          player:SetTargetPrompt( 0, "CARD_QUERY_CHOOSE_CARD_TO_PLAY" )
          player:ChooseTargetsFromDCWithFlags( NO_VALIDATION, browser, EffectDC():Make_Targets(1), QUERY_FLAG_CAN_BE_FINISHED_EARLY + QUERY_FLAG_CAN_BE_FINISHED_EARLY_FOR_AI_AS_WELL )
       end
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    if EffectDC():Get_Targets(1) ~= nil then
      local target = EffectDC():Get_Targets(1):Get_CardPtr(0)
      if target ~= nil then
        if target:CanBePlayed(EffectController()) then
          EffectController():CopySpellAndCastIt( target )   
        end   
      end   
    end
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
User avatar
sumomole
Programmer
 
Posts: 611
Joined: 07 Jun 2011, 08:34
Has thanked: 51 times
Been thanked: 234 times

Re: [DotP2013] Help with Cipher

Postby BETenner » 18 Mar 2013, 15:32

It's easier to implement with "CreateDelayedTrigger", the result actually the same as the ruling. If you want to be more real, you can grant a "fake" static ability (just has text) to the encoded creature so that you can read "Whenever this creature deals combat damage to a player, you may copy the ciphered card and you may cast the copy without paying its mana cost." on the creature card.
BETenner
 
Posts: 36
Joined: 07 Mar 2013, 14:20
Has thanked: 7 times
Been thanked: 4 times

Re: [DotP2013] Help with Cipher

Postby thefiremind » 29 Mar 2013, 12:12

BETenner wrote:It's easier to implement with "CreateDelayedTrigger", the result actually the same as the ruling.
That's not entirely true. Being a granted ability means that Snakeform, for example, can shut it down.
I started from sumomole's idea and tried to simplify the code as much as I could, this is the result on Last Thoughts:
Code: Select all
<?xml version='1.0' encoding='UTF-8'?>
<CARD_V2>
  <FILENAME text="LAST_THOUGHTS_366407" />
  <CARDNAME text="LAST_THOUGHTS" />
  <TITLE>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Last Thoughts]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Dernières pensées]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Últimos pensamientos]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Letzter Gedanken]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Ultimi Pensieri]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[最後の思考]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[마지막 생각]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Последние Мысли]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Últimos Pensamentos]]></LOCALISED_TEXT>
  </TITLE>
  <MULTIVERSEID value="366407" />
  <ARTID value="A366407" />
  <ARTIST name="Peter Mohrbacher" />
  <CASTING_COST cost="{3}{U}" />
  <TYPE metaname="Sorcery" />
  <EXPANSION value="GTC" />
  <RARITY metaname="C" />
  <SPELL_ABILITY>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Draw a card.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Piochez une carte.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Roba una carta.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Ziehe eine Karte.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Pesca una carta.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[カードを1枚引く。]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[카드 한 장을 뽑는다.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Возьмите карту.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Compre um card.]]></LOCALISED_TEXT>
    <RESOLUTION_TIME_ACTION>
    EffectController():DrawCard()
    </RESOLUTION_TIME_ACTION>
  </SPELL_ABILITY>
  <SPELL_ABILITY>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Cipher]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Cryptage]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Cifrar.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Chiffrieren]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Cifrare]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[暗号]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[암호문]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Шифр]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Cifrar]]></LOCALISED_TEXT>
    <RESOLUTION_TIME_ACTION>
    if EffectSource():GetErstwhileZone() ~= ZONE_CEASED_TO_EXIST then
       local player = EffectController()
       local filter = Object():GetFilter()
       filter:Clear()
       filter:NotTargetted()
       filter:May()
       filter:SetZone( ZONE_IN_PLAY )
       filter:AddCardType( CARD_TYPE_CREATURE )
       filter:SetPlayer( player )
       filter:SetHint( HINT_ALLIED, player )
       if filter:CountStopAt(1) == 1 then
          player:ChooseTarget( NO_VALIDATION, "CARD_QUERY_CHOOSE_CREATURE_YOU_CONTROL", EffectDC():Make_Targets(3) )
       end
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    local creature = EffectDC():Get_Targets(3) and EffectDC():Get_Targets(3):Get_CardPtr(0)
    if creature ~= nil then
       EffectDC():Protect_CardPtr( COMPARTMENT_ID_EFFECT_SOURCE )
       EffectSource():RemoveFromGame()
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    local creature = EffectDC():Get_Targets(3) and EffectDC():Get_Targets(3):Get_CardPtr(0)
    if creature ~= nil then
       local source = EffectSource()
       if source ~= nil then
          source:NailOnto(creature)
       end
    end
    </RESOLUTION_TIME_ACTION>
    <CONTINUOUS_ACTION layer="6">
    local creature = EffectDC():Get_Targets(3) and EffectDC():Get_Targets(3):Get_CardPtr(0)
    if creature ~= nil then
       creature:GetCurrentCharacteristics():GrantAbility(1)
    end
    </CONTINUOUS_ACTION>
    <DURATION>
    return EffectSource() == nil or ( EffectDC():Get_Targets(3) and EffectDC():Get_Targets(3):Get_CardPtr(0) ) == nil
    </DURATION>
  </SPELL_ABILITY>
  <TRIGGERED_ABILITY resource_id="1">
    <TRIGGER value="CREATURE_DEALS_COMBAT_DAMAGE_TO_PLAYER" simple_qualifier="self" />
    <RESOLUTION_TIME_ACTION>
    local player = EffectController()
    local filter = Object():GetFilter()
    filter:Clear()
    filter:NotTargetted()
    filter:SetZone( ZONE_REMOVED_FROM_GAME )
    filter:AddCardName( "LAST_THOUGHTS" )
    local filter_count = filter:EvaluateObjects()
    if filter_count &gt; 0 then
       local browser = EffectDC():Make_Chest(0)
       browser:Set_CardPtr( 0, filter:GetNthEvaluatedObject(0) )
       player:SetTargetCount( 1 )
       player:SetTargetPrompt( 0, "CARD_QUERY_CHOOSE_SPELL_TO_COPY" )
       player:ChooseTargetsFromDCWithFlags( NO_VALIDATION, browser, EffectDC():Make_Targets(1),
          QUERY_FLAG_CAN_BE_FINISHED_EARLY + QUERY_FLAG_CAN_BE_FINISHED_EARLY_FOR_AI_AS_WELL )
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    local player = EffectController()
    local spell = EffectDC() and EffectDC():Get_Targets(1) and EffectDC():Get_Targets(1):Get_CardPtr(0)
    if spell ~= nil and spell:CanBePlayed(player) then
       player:CopySpellAndCastIt(spell)
    end
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
</CARD_V2>
It works perfectly and it's easy to paste onto other cards: just change
Code: Select all
filter:AddCardName( "LAST_THOUGHTS" )
with the cardname of the card you are coding, and eventually use a higher register instead of #3 for the creature choice if you need #3 for something else (I used #3 because using more than 3 registers for a spell isn't something really common, so you need to change it less times).

Incidentally, this allowed me to discover that a spell copy starts from ZONE_NOWHERE_YET but makes a zone change to ZONE_CEASED_TO_EXIST before going to the stack.

EDIT: I didn't notice it before, but the implementations of cipher before sumomole's post are using "CopySpellWithNewTargets" instead of "CopySpellAndCastIt", this is wrong.
< 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 Programming Talk

Who is online

Users browsing this forum: No registered users and 32 guests


Who is online

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

Login Form