Board index
Programs with AI or Rules Enforcement
Magic: The Gathering - Duels of the Planeswalkers
Programming Talk
Programs with AI or Rules Enforcement
Magic: The Gathering - Duels of the Planeswalkers
Programming Talk
Tooth and Nail (difficulties of Entwine)
Moderator: CCGHQ Admins
Tooth and Nail (difficulties of Entwine)
by 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:

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>
< 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.
WADs unrecognized by the game? Look here.
Need a basic modding tutorial? Try this.
Want to start coding cards? Try my web generator.
-

thefiremind - Programmer
- Posts: 1631
- Joined: 07 Nov 2011, 10:55
- Has thanked: 60 times
- Been thanked: 358 times
Re: Tooth and Nail (difficulties of Entwine)
by 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">.
If you want the Entwine result earlier you can use the trick Nabeshin used for counterpell, the <TRIGGER value="ZONECHANGE">.
Re: Tooth and Nail (difficulties of Entwine)
by Eglin » 19 Apr 2012, 15:53
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.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.
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
Cheers,
Eglin
Re: Tooth and Nail (difficulties of Entwine)
by thefiremind » 19 Apr 2012, 18:29
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?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.
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.Eglin wrote:I don't see any problem whatsoever with making targets from within an entwined spell, either.
< 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.
WADs unrecognized by the game? Look here.
Need a basic modding tutorial? Try this.
Want to start coding cards? Try my web generator.
-

thefiremind - Programmer
- Posts: 1631
- Joined: 07 Nov 2011, 10:55
- Has thanked: 60 times
- Been thanked: 358 times
4 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 2 guests


