Board index Programs with AI or Rules Enforcement Magic: The Gathering - Duels of the Planeswalkers Programming Talk
How to correctly copy */* tokens?
Moderator: CCGHQ Admins
How to correctly copy */* tokens?
by thefiremind » 13 Nov 2012, 11:12
I was about to code Slime Molding when I thought about this problem: does anyone have a good idea about how to code */* tokens (and the cards that generate them, of course) so that eventual copies of those tokens still retain their power and toughness? I'm sure that the code I used for Phyrexian Rebirth wouldn't work in that case. I'd also like to avoid adding things to the cards that make the copies, if possible.
< Former DotP 2012/2013/2014 modder >
Currently busy with life...
Currently busy with life...
-
thefiremind - Programmer
- Posts: 3515
- Joined: 07 Nov 2011, 10:55
- Has thanked: 118 times
- Been thanked: 721 times
Re: How to correctly copy */* tokens?
by thefiremind » 29 Jan 2013, 14:54
I worked some more on this problem and made a small step forward, though I still miss the big idea to make everything work as expected.
I made a storage (much like nabeshin's storage in DotP2012... I actually started from his work ) that can be used to save power and toughness of */* tokens. The complexity of the cards generating */* tokens isn't higher than before, and the code for the tokens themselves is modular (I mean you can copy-paste it).
Here is the functions file, and an example, the RTR card Slime Molding:
This is also compatible with Doubling Season (and similar cards)! The "while" loop passes the index to any number of generated tokens.
With this code, the base power and toughness of every */* token are in a safe place, and passing the index to the created token is easy with GetDataChest()... but the main problem is still unsolved: is there a way to pass the same index to a copy of the token without recoding all the cards that can copy tokens (Clone, Rite of Replication, etc.)? I really can't think of anything.
I made a storage (much like nabeshin's storage in DotP2012... I actually started from his work ) that can be used to save power and toughness of */* tokens. The complexity of the cards generating */* tokens isn't higher than before, and the code for the tokens themselves is modular (I mean you can copy-paste it).
Here is the functions file, and an example, the RTR card Slime Molding:
- Functions file | Open
- Code: Select all
COMPARTMENT_ID_STAR_TOKEN_INDEX = 2222
STMChest = {}
function StarTokensManager()
local v = {}
v.CreateNext = function()
local i = 0
while STMChest[i] ~= nil do
i = i + 1
end
local subchest = {}
subchest[1] = -1
subchest[2] = -1
STMChest[i] = subchest
return i
end
v.Set = function(index, power, toughness)
if STMChest[index] ~= nil then
STMChest[index][1] = power
STMChest[index][2] = toughness
end
end
v.GetPower = function(index)
return STMChest[index] and STMChest[index][1]
end
v.GetToughness = function(index)
return STMChest[index] and STMChest[index][2]
end
return v
end
- Slime Molding | Open
- Code: Select all
<?xml version='1.0'?>
<CARD_V2>
<FILENAME text="SLIME_MOLDING_290533" />
<CARDNAME text="SLIME_MOLDING" />
<TITLE>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Slime Molding]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Plasmare la Melma]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schleimformung]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Façonnage de boue]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Moldear el cieno]]></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[Moldagem de Limo]]></LOCALISED_TEXT>
</TITLE>
<MULTIVERSEID value="290533" />
<ARTID value="A290533" />
<ARTIST name="Marco Nelor" />
<CASTING_COST cost="{X}{G}" />
<FLAVOURTEXT>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[“Give me enough refuse and mana and I will summon an ooze that can engulf all of Ravnica.”
—Cevraya, Golgari shaman]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[“Dammi abbastanza rifiuti e mana e ti evocherò una melma in grado di ingoiare Ravnica intera.”
—Cevraya, sciamana Golgari]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[„Gib mir nur genug Abfälle und Mana, und ich beschwöre einen Schleim herbei, der ganz Ravnica verschlingen kann.”
—Cevraya, Golgari-Schamane]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[« Donnez-moi suffisamment de déchets et de mana et j’invoquerai un limon capable d’engloutir tout Ravnica. »
—Cevraya, shamane de Golgari]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[“Dame suficientes desechos y maná e invocaré un cieno que sepultará toda Rávnica.”
—Cevraya, chamán golgari]]></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[“Com lixo e mana suficiente, eu posso invocar um lodo capaz de engolir toda Ravnica.” — Cevraya, xamã Golgari]]></LOCALISED_TEXT>
</FLAVOURTEXT>
<TYPE metaname="Sorcery" />
<EXPANSION value="RTR" />
<RARITY metaname="U" />
<SPELL_ABILITY>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Put an X/X green Ooze creature token onto the battlefield.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Metti sul campo di battaglia una pedina creatura Melma X/X verde.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Bringe einen X/X grünen Schlammwesen-Kreaturenspielstein ins Spiel.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Mettez sur le champ de bataille un jeton de créature X/X verte Limon.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Pon en el campo de batalla una ficha de criatura Cieno verde X/X.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[緑のX/Xのウーズ・クリーチャー・トークンを1体戦場に出す。]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[X/X 녹색 점액괴물 생물 토큰 한 개를 전장에 놓는다.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Положите на поле битвы одну фишку существа Х/Х зеленая Тина.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Coloque no campo de batalha uma ficha de criatura verde X/X do tipo Lodo.]]></LOCALISED_TEXT>
<RESOLUTION_TIME_ACTION>
local x = GetObjectX()
local index = StarTokensManager().CreateNext()
StarTokensManager().Set(index, x, x)
EffectDC():Set_Int(0, index)
MTG():PutTokensIntoPlay( "TOKEN_OOZE_S_S_19990127", 1, EffectController(), EffectDC():Make_Chest(1) )
</RESOLUTION_TIME_ACTION>
<RESOLUTION_TIME_ACTION>
local chest = EffectDC():Get_Chest(1)
if chest ~= nil then
local n = 0
while chest:Get_CardPtr(n) ~= nil do
chest:Get_CardPtr(n):GetDataChest():Set_Int( COMPARTMENT_ID_STAR_TOKEN_INDEX, EffectDC():Get_Int(0) )
n = n + 1
end
end
</RESOLUTION_TIME_ACTION>
</SPELL_ABILITY>
<TOKEN_REGISTRATION reservation="1" type="TOKEN_OOZE_S_S_19990127" />
<AI_BASE_SCORE score="600" zone="ZONE_HAND" />
</CARD_V2>
- Ooze token | Open
- Code: Select all
<?xml version='1.0'?>
<CARD_V2>
<FILENAME text="TOKEN_OOZE_S_S_19990127" />
<CARDNAME text="OOZE" />
<TITLE>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[OOZE]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[LIMON]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[CIENO]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[SCHLAMMWESEN]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[MELMA]]></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[LODO]]></LOCALISED_TEXT>
</TITLE>
<MULTIVERSEID value="19990127" />
<ARTID value="A19990127" />
<COLOUR value="G" />
<ARTIST name="Marco Nelor" />
<CASTING_COST cost="" />
<TYPE metaname="Creature" />
<SUB_TYPE metaname="Ooze" />
<EXPANSION value="DPG" />
<RARITY metaname="T" />
<POWER value="*" />
<TOUGHNESS value="*" />
<TOKEN />
<STATIC_ABILITY filter_zone="ZONE_IN_PLAY">
<CONTINUOUS_ACTION layer="7A">
local index = ObjectDC():Get_Int(COMPARTMENT_ID_STAR_TOKEN_INDEX)
local stm = StarTokensManager()
local power = stm.GetPower(index)
local toughness = stm.GetToughness(index)
local characteristics = Object():GetCurrentCharacteristics()
characteristics:Power_Set(power)
characteristics:Toughness_Set(toughness)
</CONTINUOUS_ACTION>
</STATIC_ABILITY>
<SFX text="COMBAT_BLUNT_LARGE_ATTACK" power_boundary_min="4" power_boundary_max="-1" />
<SFX text="COMBAT_BLUNT_SMALL_ATTACK" power_boundary_min="1" power_boundary_max="3" />
</CARD_V2>
This is also compatible with Doubling Season (and similar cards)! The "while" loop passes the index to any number of generated tokens.
With this code, the base power and toughness of every */* token are in a safe place, and passing the index to the created token is easy with GetDataChest()... but the main problem is still unsolved: is there a way to pass the same index to a copy of the token without recoding all the cards that can copy tokens (Clone, Rite of Replication, etc.)? I really can't think of anything.
- Attachments
-
- SLIME_MOLDING_290533.zip
- Slime Molding example, with illustrations, token and functions
- (188.23 KiB) Downloaded 259 times
< Former DotP 2012/2013/2014 modder >
Currently busy with life...
Currently busy with life...
-
thefiremind - Programmer
- Posts: 3515
- Joined: 07 Nov 2011, 10:55
- Has thanked: 118 times
- Been thanked: 721 times
Re: How to correctly copy */* tokens?
by pcastellazzi » 30 Jan 2013, 00:27
I would try with something along the lines of:
- Code: Select all
-- token generator code
local token = ObtainToken("TOKEN_X_X", EffectController())
token:GetDataChest():SetInt(0, X_VALUE)
token:PutIntoPlay(EffectController())
- Code: Select all
-- 0/0 token static ablity
<static_ability>
local x = ObjectDC():Get_Int(0)
local c = Object():GetCurrentCharacteristics()
c:Power_Set(x)
c:Toughness_Set(x)
</static_ability>
The lights then came up and the crowd erupted in applause, because that's what the crowd does after it watches destruction on a large screen.
— Ben Kuchera, Mordern Warfare 3 review.
— Ben Kuchera, Mordern Warfare 3 review.
-
pcastellazzi - Posts: 184
- Joined: 25 Apr 2012, 00:40
- Location: Montevideo, Uruguay
- Has thanked: 11 times
- Been thanked: 30 times
Re: How to correctly copy */* tokens?
by thefiremind » 30 Jan 2013, 00:35
This is a lot easier than the code I produced, but it still doesn't solve the problem... when you make a copy or clone something, you don't copy the ObjectDC, and as far as I know there's no trigger that can get a pointer to object B when it's trying to copy object A so that object A can send its ObjectDC data to object B.
< Former DotP 2012/2013/2014 modder >
Currently busy with life...
Currently busy with life...
-
thefiremind - Programmer
- Posts: 3515
- Joined: 07 Nov 2011, 10:55
- Has thanked: 118 times
- Been thanked: 721 times
Re: How to correctly copy */* tokens?
by pcastellazzi » 31 Jan 2013, 03:21
I am not sure about ObjectDC not being duplicated, i guess it make sense.
The rest should work as expected.
The rest should work as expected.
The lights then came up and the crowd erupted in applause, because that's what the crowd does after it watches destruction on a large screen.
— Ben Kuchera, Mordern Warfare 3 review.
— Ben Kuchera, Mordern Warfare 3 review.
-
pcastellazzi - Posts: 184
- Joined: 25 Apr 2012, 00:40
- Location: Montevideo, Uruguay
- Has thanked: 11 times
- Been thanked: 30 times
Re: How to correctly copy */* tokens?
by thefiremind » 31 Jan 2013, 09:52
But that can't solve the problem as well, because X_TOKEN_CACHE[token] indexes through a pointer to the original token. When I copy the original token, X_TOKEN_CACHE[Object()] inside the copy indexes through a pointer to the copy itself, which is different.
< Former DotP 2012/2013/2014 modder >
Currently busy with life...
Currently busy with life...
-
thefiremind - Programmer
- Posts: 3515
- Joined: 07 Nov 2011, 10:55
- Has thanked: 118 times
- Been thanked: 721 times
Re: How to correctly copy */* tokens?
by pcastellazzi » 02 Feb 2013, 03:52
All our solutions where overly complicated. I believe the setters can be used like this without the need to dynamically set P/T with a static ability.
- Code: Select all
local token = ObtainToken("TOKEN_X_X", EffectController())
token:GetCurrentCharacteristics():Power_Set(X_VALUE)
token:GetCurrentCharacteristics():Toughness_Set(X_VALUE)
token:PutIntoPlay(EffectController())
The lights then came up and the crowd erupted in applause, because that's what the crowd does after it watches destruction on a large screen.
— Ben Kuchera, Mordern Warfare 3 review.
— Ben Kuchera, Mordern Warfare 3 review.
-
pcastellazzi - Posts: 184
- Joined: 25 Apr 2012, 00:40
- Location: Montevideo, Uruguay
- Has thanked: 11 times
- Been thanked: 30 times
Re: How to correctly copy */* tokens?
by thefiremind » 02 Feb 2013, 10:39
Really??? I'll test it right now!pcastellazzi wrote:All our solutions where overly complicated. I believe the setters can be used like this without the need to dynamically set P/T with a static ability.
- Code: Select all
local token = MTG():ObtainToken("TOKEN_X_X", EffectController())
token:GetCurrentCharacteristics():Power_Set(X_VALUE)
token:GetCurrentCharacteristics():Toughness_Set(X_VALUE)
token:PutIntoPlay(EffectController())
EDIT: No, it doesn't work. The token can't be even seen. Setting characteristics in a resolution time action probably lasts only until the next time state-based effects are checked.
< Former DotP 2012/2013/2014 modder >
Currently busy with life...
Currently busy with life...
-
thefiremind - Programmer
- Posts: 3515
- Joined: 07 Nov 2011, 10:55
- Has thanked: 118 times
- Been thanked: 721 times
Re: How to correctly copy */* tokens?
by pcastellazzi » 02 Feb 2013, 13:19
Different strategy then, on the spell, use the resolution time action to create a */* token and put it into play, also add a continous action on layer 7a with a duration of "while the token is in play" to set its P/T.
The lights then came up and the crowd erupted in applause, because that's what the crowd does after it watches destruction on a large screen.
— Ben Kuchera, Mordern Warfare 3 review.
— Ben Kuchera, Mordern Warfare 3 review.
-
pcastellazzi - Posts: 184
- Joined: 25 Apr 2012, 00:40
- Location: Montevideo, Uruguay
- Has thanked: 11 times
- Been thanked: 30 times
Re: How to correctly copy */* tokens?
by thefiremind » 02 Feb 2013, 13:58
...which was my first implementation of Phyrexian Rebirth, but you can't Clone such a token: the continuous action is simply ignored by the copy. I know that Phyrexian Processor is coded this way (using layer="0"), but it's a challenge card, so nobody tries to copy it (and I tried to use layer="0" myself, but the Clone is immediately dumped to the graveyard as usual).pcastellazzi wrote:Different strategy then, on the spell, use the resolution time action to create a */* token and put it into play, also add a continous action on layer 7a with a duration of "while the token is in play" to set its P/T.
EDIT: Do you want to hear something funny? You sure suggested lots of ideas without testing them, but I did something far worse: I classified my functions as not working with Clone without testing them first! And surprise surprise, they work! I think that the ObjectDC gets copied along with the card. Now I just have to test if putting copies on the battlefield (for example with Followed Footsteps) works as good as Clone.
EDIT 2: It works also with Followed Footsteps! So many doubts, and my functions were the right answer already... Well now I can make an Ooze deck or something like that.
< Former DotP 2012/2013/2014 modder >
Currently busy with life...
Currently busy with life...
-
thefiremind - Programmer
- Posts: 3515
- Joined: 07 Nov 2011, 10:55
- Has thanked: 118 times
- Been thanked: 721 times
Re: How to correctly copy */* tokens?
by pcastellazzi » 02 Feb 2013, 19:45
Then the first solution i gave you should work too. Or i am wrong?thefiremind wrote: I think that the ObjectDC gets copied along with the card.
The lights then came up and the crowd erupted in applause, because that's what the crowd does after it watches destruction on a large screen.
— Ben Kuchera, Mordern Warfare 3 review.
— Ben Kuchera, Mordern Warfare 3 review.
-
pcastellazzi - Posts: 184
- Joined: 25 Apr 2012, 00:40
- Location: Montevideo, Uruguay
- Has thanked: 11 times
- Been thanked: 30 times
Re: How to correctly copy */* tokens?
by thefiremind » 02 Feb 2013, 20:16
Yes, it's the same principle, but I'll keep my functions just in case I have to code a */* token where power and toughness are different (my functions would still need only 1 slot in the ObjectDC).pcastellazzi wrote:Then the first solution i gave you should work too. Or i am wrong?thefiremind wrote: I think that the ObjectDC gets copied along with the card.
< Former DotP 2012/2013/2014 modder >
Currently busy with life...
Currently busy with life...
-
thefiremind - Programmer
- Posts: 3515
- Joined: 07 Nov 2011, 10:55
- Has thanked: 118 times
- Been thanked: 721 times
12 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 36 guests