Board index Programs with AI or Rules Enforcement Magic: The Gathering - Duels of the Planeswalkers Programming Talk
How would you code Rooftop Storm?
Moderator: CCGHQ Admins
How would you code Rooftop Storm?
by thefiremind » 13 Jul 2013, 19:58
It could seem easy, but it isn't. Rooftop Storm says "You may pay rather than pay the mana cost for Zombie creature spells you cast". Only the controller of the enchantment benefits from this, but the benefit should include all zones where that player could cast a Zombie from.
First attempt:
Second attempt:
Third attempt:
I'm afraid this is like the problem with activating abilities from hand that don't move the card before resolution: we know the right way to do it, but a stupid engine bug prevents us from acting that way. I still hope I'm wrong and someone else finds a good implementation that doesn't freeze the game, though. Any ideas?
EDIT: I found a combination that doesn't cause freezes, too bad it isn't totally correct.
It doesn't end here: if I keep only the TRIGGERED_ABILITY, removing the cost doesn't solve the problem and the game still freezes. This is becoming frustrating...
EDIT 2: I tried to add this:
First attempt:
- Code: Select all
<STATIC_ABILITY>
<FILTER filter_id="0">
local filter = ClearFilter()
filter:SetZone(ZONE_ANYWHERE)
filter:Add(FE_TYPE, OP_IS, CARD_TYPE_CREATURE)
filter:Add(FE_SUBTYPE, OP_IS, CREATURE_TYPE_ZOMBIE)
filter:Add( FE_CONTROLLER, OP_IS, EffectController() )
</FILTER>
<CONTINUOUS_ACTION layer="8" filter_id="0">
if FilteredCard() ~= nil then
FilteredCard():GetCurrentCharacteristics():GrantAbility(0)
end
</CONTINUOUS_ACTION>
</STATIC_ABILITY>
<UTILITY_ABILITY resource_id="0" qualifier="Alternate" active_zone="ZONE_ANY">
<COST mana_cost="{0}" type="Mana" />
<ABILITY_TEXT tag="ALTERNATE_COST_PAY_0" />
</UTILITY_ABILITY>
Second attempt:
- Code: Select all
<STATIC_ABILITY>
<FILTER filter_id="0">
local filter = ClearFilter()
filter:SetZone(ZONE_STACK)
filter:Add(FE_TYPE, OP_IS, CARD_TYPE_CREATURE)
filter:Add(FE_SUBTYPE, OP_IS, CREATURE_TYPE_ZOMBIE)
filter:Add( FE_CONTROLLER, OP_IS, EffectController() )
</FILTER>
<CONTINUOUS_ACTION layer="8" filter_id="0">
if FilteredCard() ~= nil then
FilteredCard():GetCurrentCharacteristics():GrantAbility(0)
end
</CONTINUOUS_ACTION>
</STATIC_ABILITY>
<UTILITY_ABILITY resource_id="0" qualifier="Alternate" active_zone="ZONE_ANY">
<COST mana_cost="{0}" type="Mana" />
<ABILITY_TEXT tag="ALTERNATE_COST_PAY_0" />
</UTILITY_ABILITY>
Third attempt:
- Code: Select all
<TRIGGERED_ABILITY replacement_effect="1">
<TRIGGER value="CONSIDERED_FOR_CAST" simple_qualifier="controller" pre_trigger="1">
return TriggerObject():GetCardType():Test(CARD_TYPE_CREATURE) and TriggerObject():GetSubType():Test(CREATURE_TYPE_ZOMBIE)
</TRIGGER>
<RESOLUTION_TIME_ACTION>
if TriggerObject() ~= nil then
TriggerObject():GetCurrentCharacteristics():GrantAbility(0)
end
</RESOLUTION_TIME_ACTION>
</TRIGGERED_ABILITY>
<UTILITY_ABILITY resource_id="0" qualifier="Alternate" active_zone="ZONE_ANY">
<COST mana_cost="{0}" type="Mana" />
<ABILITY_TEXT tag="ALTERNATE_COST_PAY_0" />
</UTILITY_ABILITY>
I'm afraid this is like the problem with activating abilities from hand that don't move the card before resolution: we know the right way to do it, but a stupid engine bug prevents us from acting that way. I still hope I'm wrong and someone else finds a good implementation that doesn't freeze the game, though. Any ideas?
EDIT: I found a combination that doesn't cause freezes, too bad it isn't totally correct.
- Code: Select all
<TRIGGERED_ABILITY replacement_effect="1">
<TRIGGER value="CONSIDERED_FOR_CAST" simple_qualifier="controller" pre_trigger="1">
return TriggerObject():GetCardType():Test(CARD_TYPE_CREATURE) and TriggerObject():GetSubType():Test(CREATURE_TYPE_ZOMBIE)
</TRIGGER>
<RESOLUTION_TIME_ACTION>
if TriggerObject() ~= nil then
TriggerObject():GetCurrentCharacteristics():GrantAbility(0)
end
</RESOLUTION_TIME_ACTION>
</TRIGGERED_ABILITY>
<STATIC_ABILITY>
<FILTER filter_id="0">
local filter = ClearFilter()
filter:SetZone(ZONE_STACK)
filter:Add(FE_TYPE, OP_IS, CARD_TYPE_CREATURE)
filter:Add(FE_SUBTYPE, OP_IS, CREATURE_TYPE_ZOMBIE)
filter:Add( FE_CONTROLLER, OP_IS, EffectController() )
</FILTER>
<CONTINUOUS_ACTION layer="8" filter_id="0">
if FilteredCard() ~= nil then
FilteredCard():GetCurrentCharacteristics():GrantAbility(0)
end
</CONTINUOUS_ACTION>
</STATIC_ABILITY>
<UTILITY_ABILITY resource_id="0" qualifier="Alternate" active_zone="ZONE_ANY">
<ABILITY_TEXT tag="ALTERNATE_COST_PAY_0" />
</UTILITY_ABILITY>
It doesn't end here: if I keep only the TRIGGERED_ABILITY, removing the cost doesn't solve the problem and the game still freezes. This is becoming frustrating...
EDIT 2: I tried to add this:
- Code: Select all
<TRIGGERED_ABILITY replacement_effect="1">
<TRIGGER value="SPELL_PLAYED" simple_qualifier="controller">
return TriggerObject():GetCardType():Test(CARD_TYPE_CREATURE) and TriggerObject():GetSubType():Test(CREATURE_TYPE_ZOMBIE)
</TRIGGER>
<CONTINUOUS_ACTION layer="8">
if TriggerObject() ~= nil then
TriggerObject():GetCurrentCharacteristics():GrantAbility(0)
end
</CONTINUOUS_ACTION>
<DURATION>
return TriggerObject() == nil
</DURATION>
</TRIGGERED_ABILITY>
< 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 would you code Rooftop Storm?
by thefiremind » 15 Jul 2013, 20:26
Answering Persee's post that he decided to delete while I was writing: yeah, I ended up making something really close to your implementation.
One question: doesn't giving the ability to Gravecrawlers in your graveyard make them always playable no matter how many Zombies you control? I added a check that doesn't grant the ability to Gravecrawlers in my graveyard if I don't control any Zombie, but I haven't tried without that check.
One question: doesn't giving the ability to Gravecrawlers in your graveyard make them always playable no matter how many Zombies you control? I added a check that doesn't grant the ability to Gravecrawlers in my graveyard if I don't control any Zombie, but I haven't tried without that check.
< 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 would you code Rooftop Storm?
by Persee » 16 Jul 2013, 08:32
I delete my post because my code of Roottop Storm doesn't work with card like Lodestone Golem.
I try to find a solution.
However, thank you for your question, I will correct my code.
I try to find a solution.
However, thank you for your question, I will correct my code.
Re: How would you code Rooftop Storm?
by thefiremind » 16 Jul 2013, 09:02
Are you sure? It's something that the game manages automatically: the choice will still say "Pay " because it can't modify the string on runtime, but you'll need to pay if a Lodestone Golem is on the battlefield. Only if you removePersee wrote:I delete my post because my code of Roottop Storm doesn't work with card like Lodestone Golem.
- Code: Select all
<COST mana_cost="{0}" type="Mana" />
< 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 would you code Rooftop Storm?
by Persee » 16 Jul 2013, 09:13
You're right.
All we need to do is use the code of Omniscience.
It's a core card and I think it works with other cards like Thalia, Guardian of Thraben or Aura of Silence
But I can not try right now, I'm at work.
All we need to do is use the code of Omniscience.
- Code: Select all
<STATIC_ABILITY>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[You may cast nonland cards from your hand without paying their mana costs.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Vous pouvez lancer des cartes non-terrain depuis votre main sans payer leur coût de mana.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Puedes lanzar cartas que no sean de tierra de tu mano sin pagar sus costes de maná.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Du kannst Karten, die kein Land sind, aus deiner Hand wirken, ohne ihre Manakosten zu bezahlen.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Puoi lanciare carte non terra dalla tua mano senza pagare il loro costo di mana.]]></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[Você pode conjurar cards que não sejam terrenos da sua mão sem pagar seus custos de mana.]]></LOCALISED_TEXT>
<FILTER filter_id="1">
local filter = ClearFilter()
filter:SetZone(ZONE_STACK)
filter:Add(FE_CONTROLLER, OP_IS, EffectController())
filter:Add(FE_TYPE, OP_NOT, CARD_TYPE_LAND)
</FILTER>
<FILTER filter_id="0">
local filter = ClearFilter()
filter:SetZone(ZONE_HAND, EffectController())
filter:Add(FE_TYPE, OP_NOT, CARD_TYPE_LAND)
</FILTER>
<CONTINUOUS_ACTION layer="8" filter_id="0">
if FilteredCard() ~= nil then
local characteristics = FilteredCard():GetCurrentCharacteristics()
characteristics:GrantAbility(0)
end
</CONTINUOUS_ACTION>
<CONTINUOUS_ACTION layer="8" filter_id="1">
if FilteredCard() ~= nil then
local characteristics = FilteredCard():GetCurrentCharacteristics()
characteristics:GrantAbility(0)
end
</CONTINUOUS_ACTION>
</STATIC_ABILITY>
<UTILITY_ABILITY resource_id="0" qualifier="Alternate">
<ABILITY_TEXT tag="CARD_QUERY_DJINN_OF_WISHED_CAST_CARD_WITH_PYING_ITS_MANA_COST" />
</UTILITY_ABILITY>
It's a core card and I think it works with other cards like Thalia, Guardian of Thraben or Aura of Silence
But I can not try right now, I'm at work.
Re: How would you code Rooftop Storm?
by thefiremind » 16 Jul 2013, 10:04
I think you understood the exact opposite of what I was trying to say.
If you REMOVE this:
If you REMOVE this:
- Code: Select all
<COST mana_cost="{0}" type="Mana" />
< 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 would you code Rooftop Storm?
by Persee » 16 Jul 2013, 10:20
In the rules, there is no difference between them.
http://www.mtgthesource.com/forums/show ... ax-effects
http://www.mtgthesource.com/forums/show ... ax-effects
Re: How would you code Rooftop Storm?
by thefiremind » 16 Jul 2013, 11:11
I couldn't believe it so I searched for something else:Persee wrote:In the rules, there is no difference between them.
http://www.mtgthesource.com/forums/show ... ax-effects
http://forums.mtgsalvation.com/showthread.php?t=497676
Here there are some answers from official judges so I'm convinced now. But then I can't understand why they use different wordings for identical things... oh well, I'll keep my Rooftop Storm as it is, since both solutions are correct.
< 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 would you code Rooftop Storm?
by Persee » 16 Jul 2013, 12:17
I think I'll code it like that.
And it's not compatible with Yawgmoth's Will. But it would be easy to do.
edit : it's works
- Code: Select all
<STATIC_ABILITY>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[You may pay {0} rather than pay the mana cost for Zombie creature spells you cast.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Vous pouvez payer {0} à la place du coût de mana des sorts de créature Zombie que vous lancez.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Puedes pagar {0} en lugar de pagar el coste de maná de los hechizos de criatura Zombie que lanzas.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Du kannst {0} anstatt der Manakosten für Zombie-Kreaturenzauber bezahlen, die du wirkst.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Puoi pagare {0} invece di pagare il costo di mana per le magie creatura Zombie che lanci.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[あなたは、あなたが唱えるゾンビ・クリーチャー呪文のマナ・コストを支払うのではなく、{0}を支払ってもよい。]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[You may pay {0} rather than pay the mana cost for Zombie creature spells you cast.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Вы можете заплатить {0} вместо оплаты мана-стоимости разыгрываемых вами заклинаний существ-Зомби.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Você pode pagar {0} em vez de pagar o custo de mana das mágicas de criatura do tipo Zumbi que conjura.]]></LOCALISED_TEXT>
<FILTER filter_id="0">
local filter = ClearFilter()
filter:SetZone(ZONE_STACK)
filter:Add(FE_CONTROLLER, OP_IS, EffectController())
filter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_ZOMBIE )
filter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )
</FILTER>
<FILTER filter_id="1">
local filter = ClearFilter()
filter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_ZOMBIE )
filter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )
filter:SetZone( ZONE_HAND, EffectController() )
</FILTER>
<FILTER filter_id="2">
local filter = ClearFilter()
filter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_ZOMBIE )
filter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )
filter:Add( FE_CARD_NAME, OP_IS, "GRAVECRAWLER" )
filter:SetZone( ZONE_GRAVEYARD, EffectController() )
</FILTER>
<CONTINUOUS_ACTION layer="8" filter_id="0">
if FilteredCard() ~= nil then
local characteristics = FilteredCard():GetCurrentCharacteristics()
characteristics:GrantAbility(0)
end
</CONTINUOUS_ACTION>
<CONTINUOUS_ACTION layer="8" filter_id="1">
if FilteredCard() ~= nil then
local characteristics = FilteredCard():GetCurrentCharacteristics()
characteristics:GrantAbility(0)
end
</CONTINUOUS_ACTION>
<CONTINUOUS_ACTION layer="8" filter_id="2">
if FilteredCard() ~= nil then
local characteristics = FilteredCard():GetCurrentCharacteristics()
characteristics:GrantAbility(1)
end
</CONTINUOUS_ACTION>
</STATIC_ABILITY>
<UTILITY_ABILITY resource_id="0" qualifier="Alternate">
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[You may pay {0} rather than pay the mana cost for Zombie creature spells you cast.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Vous pouvez payer {0} à la place du coût de mana des sorts de créature Zombie que vous lancez.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Puedes pagar {0} en lugar de pagar el coste de maná de los hechizos de criatura Zombie que lanzas.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Du kannst {0} anstatt der Manakosten für Zombie-Kreaturenzauber bezahlen, die du wirkst.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Puoi pagare {0} invece di pagare il costo di mana per le magie creatura Zombie che lanci.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[あなたは、あなたが唱えるゾンビ・クリーチャー呪文のマナ・コストを支払うのではなく、{0}を支払ってもよい。]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[You may pay {0} rather than pay the mana cost for Zombie creature spells you cast.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Вы можете заплатить {0} вместо оплаты мана-стоимости разыгрываемых вами заклинаний существ-Зомби.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Você pode pagar {0} em vez de pagar o custo de mana das mágicas de criatura do tipo Zumbi que conjura.]]></LOCALISED_TEXT>
<AVAILABILITY>
return true
</AVAILABILITY>
<ABILITY_TEXT tag="ALTERNATE_COST_PAY_0" />
</UTILITY_ABILITY>
<UTILITY_ABILITY resource_id="1" qualifier="Alternate" active_zone="ZONE_GRAVEYARD">
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[You may pay {0} rather than pay the mana cost for Zombie creature spells you cast.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Vous pouvez payer {0} à la place du coût de mana des sorts de créature Zombie que vous lancez.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Puedes pagar {0} en lugar de pagar el coste de maná de los hechizos de criatura Zombie que lanzas.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Du kannst {0} anstatt der Manakosten für Zombie-Kreaturenzauber bezahlen, die du wirkst.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Puoi pagare {0} invece di pagare il costo di mana per le magie creatura Zombie che lanci.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[あなたは、あなたが唱えるゾンビ・クリーチャー呪文のマナ・コストを支払うのではなく、{0}を支払ってもよい。]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[You may pay {0} rather than pay the mana cost for Zombie creature spells you cast.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Вы можете заплатить {0} вместо оплаты мана-стоимости разыгрываемых вами заклинаний существ-Зомби.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Você pode pagar {0} em vez de pagar o custo de mana das mágicas de criatura do tipo Zumbi que conjura.]]></LOCALISED_TEXT>
<AVAILABILITY>
local filter = ClearFilter()
filter:Add(FE_CONTROLLER, OP_IS, EffectController() )
filter:Add(FE_SUBTYPE, OP_IS, CREATURE_TYPE_ZOMBIE )
if filter:CountStopAt(1) == 1 then
return true
else
return false
end
</AVAILABILITY>
<ABILITY_TEXT tag="ALTERNATE_COST_PAY_0" />
</UTILITY_ABILITY>
And it's not compatible with Yawgmoth's Will. But it would be easy to do.
edit : it's works
9 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 42 guests