It is currently 20 May 2013, 08:59
   
Text Size

Tooth and Nail (difficulties of Entwine)

Moderator: CCGHQ Admins

Tooth and Nail (difficulties of Entwine)

Postby thefiremind » 19 Apr 2012, 12:37

I wanted to code a famous card: Tooth and Nail. I'm showing the results here, hoping that some modders can learn something new from it, or show me an alternative solution that improves it somehow.

Before trying, I thought that Entwine could have been implemented with the old trick of using Kicker. But things are not so easy for Entwine. By doing it with Kicker, there are 2 problems:
1) The Object():Kicked() variable is not set until resolution time. So I can't avoid presenting the multiple choice when the Entwine cost has been paid, because I have no way of checking it!
2) A cosmetic bug: when the player chooses the second option, the card gains the kicker animation (that lightning and shaking thing) even if the kicker cost hasn't been paid.

So I had to follow another way. I made a trigger similar to the Cascade one, with a conditional cost equal to the Entwine cost. If the cost is paid, no multiple choice is presented. Either way, I save an integer that represents the choice (1=first, 2=second, 3=both) and the spell abilities check that integer in order to know what to do.

Note that Tooth and Nail actually is the easiest case of Entwine, because neither mode requires targets (the real meaning of "target", not the wider meaning it has in the cards' code). I don't know if it would be possible to code a targeted Entwine spell properly... maybe yes, but it would be harder (the trigger should activate only if there are valid targets for both modes... but I would be asked to choose the targets before or after the Entwine trigger?).

Enough with the explanations, here is the code:
Code: Select all
<?xml version='1.0'?>
<CARD_V2 custom="true">
  <FILENAME text="TOOTH_AND_NAIL_19991642" />
  <CARDNAME text="TOOTH_AND_NAIL" />
  <TITLE>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Tooth and Nail]]></LOCALISED_TEXT>
  </TITLE>
  <MULTIVERSEID value="19991642" />
  <ARTID value="19991642" />
  <FRAMECOLOUR name="G" />
  <COLOUR value="G" />
  <ARTIST name="Greg Hildebrandt" />
  <CASTING_COST cost="{5}{G}{G}" />
  <TYPE metaname="Sorcery" order_de-DE="0" order_es-ES="0" order_fr-FR="0" order_it-IT="0" order_jp-JA="0" />
  <EXPANSION value="MR" />
  <RARITY metaname="R" />
  <SPELL_ABILITY>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Choose one — Search your library for up to two creature cards, reveal them, put them into your hand, then shuffle your library; or put up to two creature cards from your hand onto the battlefield.]]></LOCALISED_TEXT>
    <RESOLUTION_TIME_ACTION>
    if MTG():ObjectDataChest():Int_Get(3) ~= 2 then
      local filter = Object():GetFilter()
      local player = Object():GetPlayer()
      filter:Clear()
      filter:NotTargetted()
      filter:AddCardType( CARD_TYPE_CREATURE )
      filter:May()
      filter:PlayerHint( Object():GetPlayer() )
      filter:SetPlayer( Object():GetPlayer() )
      filter:SetZone( ZONE_LIBRARY )
      filter:NotTargetted()
      player:SetTargetCount(2)
      for i=0,1 do
        player:SetTargetPrompt( i, "CARD_QUERY_CHOOSE_CREATURE_TO_PUT_INTO_HAND" )
      end
      player:ChooseTargetsDC( MTG():EffectDataChest():Make_Targets(0) )
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    if MTG():ObjectDataChest():Int_Get(3) ~= 2 then
      local targetDC = MTG():EffectDataChest():Get_Targets(0)
      if targetDC ~= nil then
        for i=0,1 do
          local target = targetDC:Get_NthCardPtr(i)
          if target ~= nil then
            MTG():EffectDataChest():Set_CardPtr(i, target)
          end
        end
      end
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    if MTG():ObjectDataChest():Int_Get(3) ~= 2 then
      for i=0,1 do
        local target = MTG():EffectDataChest():Get_CardPtr(i)
        if target ~= nil then
          target:GuidedReveal( ZONE_LIBRARY, ZONE_HAND )
          target:PutInHand()
        end
      end
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    if MTG():ObjectDataChest():Int_Get(3) ~= 2 then
      Object():GetOwner():ShuffleLibrary()
    end
    </RESOLUTION_TIME_ACTION>
  </SPELL_ABILITY>
  <SPELL_ABILITY>
    <RESOLUTION_TIME_ACTION>
    if MTG():ObjectDataChest():Int_Get(3) ~= 1 then
      local filter = Object():GetFilter()
      local player = Object():GetPlayer()
      filter:Clear()
      filter:NotTargetted()
      filter:AddCardType( CARD_TYPE_CREATURE )
      filter:SetPlayer( Object():GetPlayer() )
      filter:SetZone( ZONE_HAND )
      filter:May()
      player:SetTargetCount(2)
      for i=0,1 do
        player:SetTargetPrompt( i, "CARD_QUERY_CHOOSE_CREATURE_TO_PUT_ONTO_BATTLEFIELD" )
      end
      player:ChooseTargetsDC( MTG():EffectDataChest():Make_Targets(1) )
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    if MTG():ObjectDataChest():Int_Get(3) ~= 1 then
      local targetDC = MTG():EffectDataChest():Get_Targets(1)
      if targetDC ~= nil then
        for i=0,1 do
          local target = targetDC:Get_NthCardPtr(i)
          if target ~= nil then
            MTG():EffectDataChest():Set_CardPtr(i, target)
          end
        end
      end
    end
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION>
    if MTG():ObjectDataChest():Int_Get(3) ~= 1 then
      for i=0,1 do
        local target = MTG():EffectDataChest():Get_CardPtr(i)
        if target ~= nil then
          target:PutIntoPlay( Object():GetPlayer() )
        end
      end
    end
    </RESOLUTION_TIME_ACTION>
  </SPELL_ABILITY>
  <TRIGGERED_ABILITY forced_skip="1" active_zone="any">
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Entwine {2}]]></LOCALISED_TEXT>
    <TRIGGER value="SPELL_PLAYED" simple_qualifier="self" />
    <COST type="mana" cost="{2}" qualifier="conditional" />
    <RESOLUTION_TIME_ACTION conditional="if">
    MTG():ObjectDataChest():Int_Set(3, 3)
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION conditional="else">
    local player = Object():GetPlayer()
    player:BeginNewMultipleChoice()
    player:AddMultipleChoiceAnswer( "CARD_QUERY_OPTION_TUTOR_FOR_CREATURE" )
    player:AddMultipleChoiceAnswer( "CARD_QUERY_OPTION_PUT_CREATURE_ONTO_BATTLEFIELD_FROM_HAND" )
    player:AskMultipleChoiceQuestion( "CARD_QUERY_MC_CHOOSE_MODE" )
    </RESOLUTION_TIME_ACTION>
    <RESOLUTION_TIME_ACTION conditional="else">
    MTG():ObjectDataChest():Int_Set(3, Object():GetMultipleChoiceResult()+1)
    </RESOLUTION_TIME_ACTION>
  </TRIGGERED_ABILITY>
</CARD_V2>
I used the same multiple choice as Introductions Are in Order... not totally right, but understandable. :wink:
< DotP2013 (and formerly 2012) modder >
WADs unrecognized by the game? Look here.
Need a basic modding tutorial? Try this.
Want to start coding cards? Try my web generator.
User avatar
thefiremind
Programmer
 
Posts: 1638
Joined: 07 Nov 2011, 10:55
Has thanked: 60 times
Been thanked: 359 times

Re: Tooth and Nail (difficulties of Entwine)

Postby sadlyblue » 19 Apr 2012, 13:49

Nice work.
If you want the Entwine result earlier you can use the trick Nabeshin used for counterpell, the <TRIGGER value="ZONECHANGE">.
sadlyblue
 
Posts: 175
Joined: 06 Feb 2012, 13:18
Has thanked: 18 times
Been thanked: 16 times

Re: Tooth and Nail (difficulties of Entwine)

Postby Eglin » 19 Apr 2012, 15:53

thefiremind wrote:By doing it with Kicker, there are 2 problems:
1) The Object():Kicked() variable is not set until resolution time. So I can't avoid presenting the multiple choice when the Entwine cost has been paid, because I have no way of checking it!
2) A cosmetic bug: when the player chooses the second option, the card gains the kicker animation (that lightning and shaking thing) even if the kicker cost hasn't been paid.
I don't see why #1 is a problem. Just move everything into resolution time blocks and use if blocks for branches / guards. There's really nothing, at least for Tooth and Nail, that needs to be done at play-time instead of resolution time.

The kicked animation should only happen if the entwine cost has been paid, and that seems like a reasonable special effect under the circumstances.

pseudo-code
Code: Select all
resolution:
  if not kicked then
    ask which effect to do
  do first effect if applicable
  do second effect if applicable
I applaud you for managing to get it done, but I suspect there's an easier way. I don't see any problem whatsoever with making targets from within an entwined spell, either. Just guard the target selection stuff with if blocks, just like for the dialogs. As an example, my Ichorid conditionally suppresses both a dialog and a targeting block.

Cheers,
Eglin
User avatar
Eglin
Programmer
 
Posts: 185
Joined: 01 Mar 2012, 14:44
Has thanked: 35 times
Been thanked: 19 times

Re: Tooth and Nail (difficulties of Entwine)

Postby thefiremind » 19 Apr 2012, 18:29

Eglin wrote:I don't see why #1 is a problem. Just move everything into resolution time blocks and use if blocks for branches / guards. There's really nothing, at least for Tooth and Nail, that needs to be done at play-time instead of resolution time.
The choice for a modal spell should be made at play time, and the rule makes sense if you compare modal spells with non-modal spells that could be rewritten as modal. Let's pretend that Disenchant has a new wording and now says "Choose one - destroy target artifact; or destroy target enchantment". Would it be right to decide on resolution time? :roll: I know that there would be no difference on Tooth and Nail, but I like to follow the rules as closely as possible when I can.

Eglin wrote:I don't see any problem whatsoever with making targets from within an entwined spell, either.
After sadlyblue's advice, I'm positive about it, too. Anyway there must be lots of checks because the player should never be allowed to make a choice that has no legal targets at the moment.
< DotP2013 (and formerly 2012) modder >
WADs unrecognized by the game? Look here.
Need a basic modding tutorial? Try this.
Want to start coding cards? Try my web generator.
User avatar
thefiremind
Programmer
 
Posts: 1638
Joined: 07 Nov 2011, 10:55
Has thanked: 60 times
Been thanked: 359 times


Return to Programming Talk

Who is online

Users browsing this forum: No registered users and 2 guests


Who is online

In total there are 2 users online :: 0 registered, 0 hidden and 2 guests (based on users active over the past 10 minutes)
Most users ever online was 177 on 10 Oct 2011, 16:37

Users browsing this forum: No registered users and 2 guests

Login Form