Board index Programs with AI or Rules Enforcement Magic: The Gathering - Duels of the Planeswalkers Programming Talk
General DotP 2014 Coding Questions
Moderator: CCGHQ Admins
Re: General DotP 2014 Coding Questions
by thefiremind » 13 Oct 2013, 15:59
You worked on sunburst so you should already know it...GrovyleXShinyCelebi wrote:-How would you make an effect that triggers depending on whether you spent mana of a specific colour when paying for it (i.e. Ribbons of Night, which I know was an official card in Duels 2013 so it should be doable)
I never wondered why. I guess that the choices made by players aren't ready to be read until the next action begins.GrovyleXShinyCelebi wrote:-Why is it that you can't put a "ChooseItems( EffectDC():Make_Targets(1))" and "local target = EffectDC():Get_Targets(1) and EffectDC():Get_Targets(1):Get_CardPtr(i)" in the same RESOLUTION_TIME_ACTION block?
< 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: General DotP 2014 Coding Questions
by GrovyleXShinyCelebi » 19 Oct 2013, 16:11
Hey, I have a question.
Do you know what might be wrong with this Dispense Justice code?
Do you know what might be wrong with this Dispense Justice code?
- Code: Select all
<?xml version='1.0' encoding='UTF-8'?>
<CARD_V2 ExportVersion="1">
<FILENAME text="DISPENSE_JUSTICE_99209015" />
<CARDNAME text="DISPENSE_JUSTICE" />
<TITLE>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Dispense Justice]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Prononcer la justice]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Dispensar justicia]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Recht sprechen]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Dispensare Giustizia]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[正義の施行]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Dispense Justice]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Вершить Правосудие]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Fazer Justiça]]></LOCALISED_TEXT>
</TITLE>
<MULTIVERSEID value="209015" />
<ARTID value="131072" />
<ARTIST name="Austin Hsu" />
<CASTING_COST cost="{2}{W}" />
<FLAVOURTEXT>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[The Accorders never strike first, but they always strike back.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Les Accordeurs ne frappent jamais les premiers, mais ils ripostent toujours.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Los acordantes nunca golpean primero, pero siempre devuelven el golpe.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Die Harmonier schlagen nie zuerst zu, aber immer zurück.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[I Concordi non colpiscono mai per primi, ma restituiscono sempre il colpo.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[調和者隊は先制攻撃に出ることは無いが、確実に反撃する。]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[The Accorders never strike first, but they always strike back.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Согласители никогда не наносят первый удар, но всегда наносят ответный.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Os Concordantes nunca atacam primeiro, mas sempre revidam o ataque.]]></LOCALISED_TEXT>
</FLAVOURTEXT>
<TYPE metaname="Instant" />
<EXPANSION value="SOM" />
<RARITY metaname="U" />
<SPELL_ABILITY>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Target player sacrifices an attacking creature.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Le joueur ciblé sacrifie une créature attaquante.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[El jugador objetivo sacrifica una criatura atacante.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Ein Spieler deiner Wahl opfert eine angreifende Kreatur.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Un giocatore bersaglio sacrifica una creatura attaccante.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[プレイヤー1人を対象とする。そのプレイヤーは攻撃クリーチャーを1体生け贄に捧げる。]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Target player sacrifices an attacking creature.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Целевой игрок приносит в жертву атакующее существо.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[O jogador alvo sacrifica uma criatura atacante.]]></LOCALISED_TEXT>
<TARGET tag="CARD_QUERY_CHOOSE_PLAYER_TO_SACRIFICE_CREATURE" definition="0" compartment="0" count="1" />
<TARGET_DEFINITION id="0">
local filter = ClearFilter()
filter:SetFilterType( FILTER_TYPE_PLAYERS )
filter:Add( FE_LUA_CONDITION, 4, EffectController(), EffectDC() )
</TARGET_DEFINITION>
<FILTER_CONDITION id="4">
local player = FilteredPlayer()
if player ~= nil then
local filter = ClearFilter()
filter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )
filter:Add( FE_IS_ATTACKING, true )
filter:Add( FE_CONTROLLER, OP_IS, player )
local count = filter:Count()
if count > 0 then
return true
else
return false
end
else
return false
end
</FILTER_CONDITION>
<RESOLUTION_TIME_ACTION>
local filter = ClearFilter()
filter:Add( FE_TYPE, OP_IS, CARD_TYPE_ARTIFACT )
filter:Add( FE_CONTROLLER, OP_IS, EffectController() )
local count = filter:Count()
if count ~= nil then
EffectDC():Set_Int(5, count)
end
</RESOLUTION_TIME_ACTION>
<RESOLUTION_TIME_ACTION>
local target = EffectDC():Get_Targets(0):Get_PlayerPtr(0)
if target ~= nil then
local metalcraft = EffectDC():Get_Int(5)
if metalcraft > 2 then
local filter = ClearFilter()
filter:Add( FE_CONTROLLER, OP_IS, target )
filter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )
filter:Add( FE_IS_ATTACKING, true )
target:SetItemCount( 2 )
for i=0, (1) do
target:SetItemPrompt( i, "CARD_QUERY_CHOOSE_CREATURE_TO_SACRIFICE" )
end
target:ChooseItems( EffectDC():Make_Targets(2) )
else
local filter = ClearFilter()
filter:Add( FE_CONTROLLER, OP_IS, target )
filter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )
filter:Add( FE_IS_ATTACKING, true )
target:ChooseItem( "CARD_QUERY_CHOOSE_CREATURE_TO_SACRIFICE", EffectDC():Make_Targets(1) )
end
end
</RESOLUTION_TIME_ACTION>
<RESOLUTION_TIME_ACTION>
local target = EffectDC():Get_Targets(0):Get_PlayerPtr(0)
if target ~= nil then
local creature = EffectDC():Get_Targets(1) and EffectDC():Get_Targets(1):Get_CardPtr(0)
if creature ~= nil then
target:Sacrifice( creature )
end
end
</RESOLUTION_TIME_ACTION>
<RESOLUTION_TIME_ACTION>
local target = EffectDC():Get_Targets(0):Get_PlayerPtr(0)
if target ~= nil then
local objectivo = EffectDC():Get_Targets(2)
if objectivo ~= nil then
for i=0, (1) do
local creature = objectivo:Get_CardPtr(i)
if creature ~= nil then
target:Sacrifice( creature )
end
end
end
end
</RESOLUTION_TIME_ACTION>
<AI_SIMPLIFIED_TARGETING compartment="0" hint="HINT_ENEMY_ONLY" />
</SPELL_ABILITY>
<SPELL_ABILITY>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Metalcraft — That player sacrifices two attacking creatures instead if you control three or more artifacts.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Art des métaux — Ce joueur sacrifie deux créatures attaquantes à la place si vous contrôlez au moins trois artefacts.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Metalurgia — Ese jugador sacrifica dos criaturas atacantes en vez de eso si tú controlas tres o más artefactos.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Metallkunst — Falls du drei oder mehr Artefakte kontrollierst, opfert dieser Spieler stattdessen zwei angreifende Kreaturen.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Metallurgia — Quel giocatore sacrifica invece due creature attaccanti se controlli tre o più artefatti.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[金属術 ― あなたが3つ以上のアーティファクトをコントロールしている場合、代わりにそのプレイヤーは攻撃クリーチャーを2体生け贄に捧げる。]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Metalcraft — That player sacrifices two attacking creatures instead if you control three or more artifacts.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Работа по металлу — Тот игрок приносит в жертву два атакующих существа вместо этого, если вы контролируете не менее трех артефактов.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Maestria com Metais — Se você controlar três ou mais artefatos, em vez disso, aquele jogador sacrificará duas criaturas atacantes.]]></LOCALISED_TEXT>
</SPELL_ABILITY>
<AI_AVAILABILITY type="in_response" response_source="1" />
<AI_AVAILABILITY type="in_response" response_target="1" />
<AI_AVAILABILITY window_step="declare_attackers" window_turn="their_turn" type="window" />
<AI_AVAILABILITY window_step="declare_blockers" type="window" />
</CARD_V2>
(in Duels 2014)
Duels 2012: viewtopic.php?f=109&t=12152
Duels 2013: viewtopic.php?f=109&t=12481&p=137458#p137458
Duels 2012: viewtopic.php?f=109&t=12152
Duels 2013: viewtopic.php?f=109&t=12481&p=137458#p137458
-
GrovyleXShinyCelebi - Posts: 294
- Joined: 12 Jun 2013, 18:23
- Has thanked: 14 times
- Been thanked: 37 times
Re: General DotP 2014 Coding Questions
by thefiremind » 19 Oct 2013, 16:23
I can't see anything wrong and there's probably something I don't know or I'm missing, but the whole problem shouldn't exist: the card doesn't say "Target player that controls an attacking creature sacrifices an attacking creature"... I mean, you should be allowed to target a player that isn't attacking or even a player that controls no creatures at all. If that's the case, the spell will resolve doing nothing.
< 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: General DotP 2014 Coding Questions
by GrovyleXShinyCelebi » 19 Oct 2013, 17:57
The reason I put that filter condition was because I'm worried the AI will cast the spell arbitrarily and it'll just fizzle. I'm not exactly sure how smart the AI is at detecting "ChooseItems()" functions in RESOLUTION_TIME_ACTION. Though I guess I'll just have to take out the filter condition for now.thefiremind wrote:I can't see anything wrong and there's probably something I don't know or I'm missing, but the whole problem shouldn't exist: the card doesn't say "Target player that controls an attacking creature sacrifices an attacking creature"... I mean, you should be allowed to target a player that isn't attacking or even a player that controls no creatures at all. If that's the case, the spell will resolve doing nothing.
By the way, know how AI_AVAILABILITY blocks work? And do they work on anything that's not an instant or can be activated/cast at instant speed?
(in Duels 2014)
Duels 2012: viewtopic.php?f=109&t=12152
Duels 2013: viewtopic.php?f=109&t=12481&p=137458#p137458
Duels 2012: viewtopic.php?f=109&t=12152
Duels 2013: viewtopic.php?f=109&t=12481&p=137458#p137458
-
GrovyleXShinyCelebi - Posts: 294
- Joined: 12 Jun 2013, 18:23
- Has thanked: 14 times
- Been thanked: 37 times
Re: General DotP 2014 Coding Questions
by thefiremind » 19 Oct 2013, 21:35
In previous games I would have doubted, too, but DotP2014's AI is the best so far. Not to mention that the card would be totally wrong in some scenarios if you limit the legal targets more than necessary (you should be able to Swerve Dispense Justice to your opponent, for example, basically turning Swerve into a counterspell).GrovyleXShinyCelebi wrote:The reason I put that filter condition was because I'm worried the AI will cast the spell arbitrarily and it'll just fizzle. I'm not exactly sure how smart the AI is at detecting "ChooseItems()" functions in RESOLUTION_TIME_ACTION.
Trying to be short but exhaustive: if the AI is in a situation that is not defined in any of the AI_AVAILABILITY blocks of a spell/ability, it won't even think about casting/activating that spell/ability during that situation. I'm still not sure about the real meaning of response_source and response_target, what I think is that response_source means "you can respond this way if someone tries to do something on the ability's source" and response_target means "you can respond this way targetting card X if someone tries to do something on card X", but that's just my guess about them.GrovyleXShinyCelebi wrote:By the way, know how AI_AVAILABILITY blocks work? And do they work on anything that's not an instant or can be activated/cast at instant speed?
You can put AI_AVAILABILITY anywhere you like and it might be useful even inside non-instant spells or abilities: for example, the official cards don't do that, but Act of Treason and similar spells could be limited to main phase 1 since you get the full effect only if you cast it pre-combat... well, maybe official cards don't do that because if you cast Relentless Assault you end up having a pre-combat main phase 2, but I hope you get the point despite the poor example.
< 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: General DotP 2014 Coding Questions
by GrovyleXShinyCelebi » 20 Oct 2013, 03:47
Alright, I get it. It's just that I added AI_AVALIABILITY blocks in my Bloodthirst cards telling the AI only to cast them in main phase 2. The AI still casts them in main phase 1 :/ Know what might be happening?
Also, is the AI different in encounters than duels? My logic says no because the developers had to make special cards in the challenges just to get the AI to behave a certain way (ie Grave Titan forces all opponents to block if possible), but it seems the AI is smarter in encounters (in the Gruul encounter for instance the AI actually knows how to utilize Bloodthirst).
Also, is the AI different in encounters than duels? My logic says no because the developers had to make special cards in the challenges just to get the AI to behave a certain way (ie Grave Titan forces all opponents to block if possible), but it seems the AI is smarter in encounters (in the Gruul encounter for instance the AI actually knows how to utilize Bloodthirst).
(in Duels 2014)
Duels 2012: viewtopic.php?f=109&t=12152
Duels 2013: viewtopic.php?f=109&t=12481&p=137458#p137458
Duels 2012: viewtopic.php?f=109&t=12152
Duels 2013: viewtopic.php?f=109&t=12481&p=137458#p137458
-
GrovyleXShinyCelebi - Posts: 294
- Joined: 12 Jun 2013, 18:23
- Has thanked: 14 times
- Been thanked: 37 times
Re: General DotP 2014 Coding Questions
by thefiremind » 20 Oct 2013, 08:38
Where did you put the AI_AVAILABILITY block? Since you are interested in the spell itself, it should be outside any ability, like on instants. If you did that right, then maybe I was wrong and AI_AVAILABILITY is ignored on creatures without flash. But since the AI is capable of ignoring the simplified targetting on beneficial spells if the situation requires to cast them on opponents' cards, maybe it's the same for AI_AVAILABILITY.GrovyleXShinyCelebi wrote:Alright, I get it. It's just that I added AI_AVALIABILITY blocks in my Bloodthirst cards telling the AI only to cast them in main phase 2. The AI still casts them in main phase 1 :/ Know what might be happening?
The restraints on challenge cards are meant to be sure that the AI always does the same things no matter what you do. The AI isn't smarter in encounters (as far as I know), but the situation is always optimal since the deck order is always the same: if I have a Goblin Fireslinger I obviously activate bloodthirst whenever I can, but if I don't, I might need to cast a creature without bothering about bloodthirst just to protect myself, and I think that the AI decides the same way. Try to make a custom deck with lots of "pingers" (Goblin Fireslinger, Prodigal Pyromancer, etc.) and lots of bloodthirst creatures, and see if the AI plays properly.GrovyleXShinyCelebi wrote:Also, is the AI different in encounters than duels? My logic says no because the developers had to make special cards in the challenges just to get the AI to behave a certain way (ie Grave Titan forces all opponents to block if possible), but it seems the AI is smarter in encounters (in the Gruul encounter for instance the AI actually knows how to utilize Bloodthirst).
< 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: General DotP 2014 Coding Questions
by Jspapp » 22 Oct 2013, 21:41
How long will LinkedDC():Protect_CardPtr(0) keep track of a card? It seems to lose the pointer if the card changes zone through any means other than the effect source.
Re: General DotP 2014 Coding Questions
by thefiremind » 22 Oct 2013, 22:36
In general, protecting a card pointer saves it for 1 zone change, but I'm not sure if I understood your scenario... let's make an example: inside the LinkedDC of card A, you save a pointer to card B and protect it. Then:Jspapp wrote:How long will LinkedDC():Protect_CardPtr(0) keep track of a card? It seems to lose the pointer if the card changes zone through any means other than the effect source.
- If card B changes zone but card A doesn't, the pointer will be saved.
- If both cards change zone, LinkedDC will be reset because of card A changing zone, so the pointer won't get saved, but it's not due to the protection not working.
< 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: General DotP 2014 Coding Questions
by Jspapp » 22 Oct 2013, 23:04
I'm working on an implementation of EDH and want to be able to track the commander wherever it goes. I'm trying to keep all of the logic on one card, but I think I can do the same thing by granting abilities, unless there's any way to keep a more permanent card pointer reference.thefiremind wrote:In general, protecting a card pointer saves it for 1 zone change, but I'm not sure if I understood your scenario... let's make an example: inside the LinkedDC of card A, you save a pointer to card B and protect it. Then:Jspapp wrote:How long will LinkedDC():Protect_CardPtr(0) keep track of a card? It seems to lose the pointer if the card changes zone through any means other than the effect source.Depending on what you need to do, you might need to store your data into a player's data chest or the duel's data chest.
- If card B changes zone but card A doesn't, the pointer will be saved.
- If both cards change zone, LinkedDC will be reset because of card A changing zone, so the pointer won't get saved, but it's not due to the protection not working.
EDIT: Actually, I'm using this for now as a workaround since Protect_CardPtr() only protects through one zonechange:
- Code: Select all
<TRIGGERED_ABILITY internal="1" linked_ability_group="1">
<TRIGGER value="ZONECHANGE_END">
local commander = LinkedDC():Get_CardPtr(0)
return TriggerObject() == commander
</TRIGGER>
<RESOLUTION_TIME_ACTION>
LinkedDC():Protect_CardPtr(0)
</RESOLUTION_TIME_ACTION>
<AUTO_SKIP always="1" />
</TRIGGERED_ABILITY>
Re: General DotP 2014 Coding Questions
by thefiremind » 23 Oct 2013, 08:51
The internal tag is DotP2013 syntax, you want replacement_effect instead of internal, which will make the AUTO_SKIP block unneeded.Jspapp wrote:
- Code: Select all
<TRIGGERED_ABILITY internal="1" linked_ability_group="1">
<TRIGGER value="ZONECHANGE_END">
local commander = LinkedDC():Get_CardPtr(0)
return TriggerObject() == commander
</TRIGGER>
<RESOLUTION_TIME_ACTION>
LinkedDC():Protect_CardPtr(0)
</RESOLUTION_TIME_ACTION>
<AUTO_SKIP always="1" />
</TRIGGERED_ABILITY>
Also, isn't it too late if you protect the card pointer at the end of the zone change? I would make the trigger like this:
- Code: Select all
<TRIGGERED_ABILITY replacement_effect="1" linked_ability_group="1">
<TRIGGER value="ZONECHANGE_BEGIN">
local commander = LinkedDC():Get_CardPtr(0)
if TriggerObject() == commander then
LinkedDC():Protect_CardPtr(0)
end
return false
</TRIGGER>
</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: General DotP 2014 Coding Questions
by GrovyleXShinyCelebi » 25 Oct 2013, 19:51
Hey, I have a question.
What arguments does MTG():SetTargetAnswerer() need? Because I just set this as my TARGET script for Pandemonium and when an opponent drops a creature onto the battlefield it refuses to allow them to target!
What arguments does MTG():SetTargetAnswerer() need? Because I just set this as my TARGET script for Pandemonium and when an opponent drops a creature onto the battlefield it refuses to allow them to target!
- Code: Select all
<TARGET tag="CARD_QUERY_CHOOSE_DEAL_CREATURES_POWER_DAMAGE" definition="0" compartment="0" count="1" >
if TriggerObject() ~= nil then
MTG():SetTargetAnswerer( TriggerObject():GetController() )
return
end
</TARGET>
(in Duels 2014)
Duels 2012: viewtopic.php?f=109&t=12152
Duels 2013: viewtopic.php?f=109&t=12481&p=137458#p137458
Duels 2012: viewtopic.php?f=109&t=12152
Duels 2013: viewtopic.php?f=109&t=12481&p=137458#p137458
-
GrovyleXShinyCelebi - Posts: 294
- Joined: 12 Jun 2013, 18:23
- Has thanked: 14 times
- Been thanked: 37 times
Re: General DotP 2014 Coding Questions
by thefiremind » 25 Oct 2013, 21:26
By looking at Evangelize, I'd say it needs nothing but the player. Try to remove everything except the SetTargetAnswerer line.GrovyleXShinyCelebi wrote:What arguments does MTG():SetTargetAnswerer() need? Because I just set this as my TARGET script for Pandemonium and when an opponent drops a creature onto the battlefield it refuses to allow them to target!
< 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: General DotP 2014 Coding Questions
by MC Brodie » 26 Oct 2013, 03:07
Well I got the absurd idea of trying to make somewhat working version of Momir Basic. I know we can't create copies of cards not in the specific deck playing in the duel. But I decided to make a deck with 40 lands and 59 different creatures (1 for the Momir Vanguard), exile all the creatures in the beginning, then use the exile zone as the creature pool for the Momir Vanguard. Low and behold, it (sort of) worked!!!! I had to make some limitations like no creatures with a cmc < 3 and if you pay 8 or more for Momir, you get any available creature with a cmc >= 8.
Even though I came up with a working version, I have a few questions but mostly on how to improve the AI. I've noticed a couple of things while testing.
For the likes like me that don't want to download a file to read the cards, here is what I came up with for a beta version of the Momir Vig, Simic Visionary Avatar:
Even though I came up with a working version, I have a few questions but mostly on how to improve the AI. I've noticed a couple of things while testing.
- I've been using a 100 card deck in my tests so far and haven't had a problem. Is there a way to increase the deck size? That would be nice because it would increase the potential card pool. Though, I know in the unmodded version of the game you are limited to 100 cards.
- The AI seems finicky on how it uses Momir Vig. Sometimes it will play a land then activate, then other times it will activate then play a land. In my initial testing I noticed this but I had 4 different cards in my pool (1 cmc, 2 cmc, 3 cmc and 4 cmc). I figured the AI was smart and knew not to activate for 4 mana because the 3 cmc creature would save it and the 4 cmc creature was basically a dud. Though when I tested the deck I attached below, I got mixed results. Is the AI smart enough to know which cmc it should pay for the Momir activation? I can probably figure this out wiht some more testing myself but I'd like to get someone else's opinion.
- This is sort of a dull question but I'm just looking for improvement. A 2-player game went by somewhat smoothly. The AI didn't take too long to make decisions and for the most part knew when to activate Momir (i.e., didn't activate for X=1 or X=2). Though, when I tested it in a 4-player game, the AI seemed to awhile to make decisions. I'm not sure if that is just characteristic of a 4-player game or if that is due to my lakc of coding knowledge. So now to my question . Is there a way I can improve my Momir code so that the AI can handle it more smoothly?
- I'm struggling with how to implement a Vanguard card. This version just uses an "Enchantment" modeled after the TFMs Leyline of Deity. I was thinking of attempting some code that would have an invisible token grant the code to the first basic land that comes into play. Then if that basic land is destroyed or somehow loses its abilities, the invisible token would grant the Momir ability to a different land. So, any thoughts on the best way I could implement this?
- The more appropriate way to implement Momir Basic is probably to convert every creature card to a token, then list about 7000 token registrations onto Momir (of course I could be overlooking somethign that would make this a worse idea than what it already is). Though that seems like a real pain, it doesn't look like there is much of a difference between a creature XML and a token XML. From a simple person (i.e. me), it would be possible to write a program that would take a creature XML file then change the text in the <FILENAME../> and <MULTIVERSEID../> blocks and add <TOKEN/> to the code. If that is possible, any help to point me in the right direction would be appreciated. Even if it isn't the best idea, it would be a good learning experience for someone like me whose only real programming experience is DotP.
For the likes like me that don't want to download a file to read the cards, here is what I came up with for a beta version of the Momir Vig, Simic Visionary Avatar:
- Momir Vanguard | Open
- Code: Select all
<?xml version='1.0' encoding='UTF-8'?>
<CARD_V2 ExportVersion="1">
<FILENAME text="MOMIR_VIG_SIMIC_VISIONARY_AVATAR_238182271" />
<CARDNAME text="MOMIR_VIG_SIMIC_VISIONARY_AVATAR" />
<TITLE>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Momir Vig, Simic Visionary Avatar]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Momir Vig, Simic Visionary Avatar]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Momir Vig, Simic Visionary Avatar]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Momir Vig, Simic Visionary Avatar]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Momir Vig, Simic Visionary Avatar]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[Momir Vig, Simic Visionary Avatar]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Momir Vig, Simic Visionary Avatar]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Momir Vig, Simic Visionary Avatar]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Momir Vig, Simic Visionary Avatar]]></LOCALISED_TEXT>
</TITLE>
<MULTIVERSEID value="238182271" />
<ARTID value="238182271" />
<ARTIST name="UDON" />
<CASTING_COST cost="" />
<TYPE metaname="Enchantment" />
<EXPANSION value="VAN" />
<RARITY metaname="S" />
<STATIC_ABILITY>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Hand Modifier: +0 , Life Modifier: +4]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Hand Modifier: +0 , Life Modifier: +4]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Hand Modifier: +0 , Life Modifier: +4]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Hand Modifier: +0 , Life Modifier: +4]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Hand Modifier: +0 , Life Modifier: +4]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[Hand Modifier: +0 , Life Modifier: +4]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Hand Modifier: +0 , Life Modifier: +4]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Hand Modifier: +0 , Life Modifier: +4]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Hand Modifier: +0 , Life Modifier: +4]]></LOCALISED_TEXT>
</STATIC_ABILITY>
<ACTIVATED_ABILITY resource_id="0">
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[{X}, Discard a card: Put a token onto the battlefield that’s a copy of a creature card with converted mana cost X chosen at random. Activate this ability only any time you could cast a sorcery and only once each turn.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[{X}, Discard a card: Put a token onto the battlefield that’s a copy of a creature card with converted mana cost X chosen at random. Activate this ability only any time you could cast a sorcery and only once each turn.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[{X}, Discard a card: Put a token onto the battlefield that’s a copy of a creature card with converted mana cost X chosen at random. Activate this ability only any time you could cast a sorcery and only once each turn.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[{X}, Discard a card: Put a token onto the battlefield that’s a copy of a creature card with converted mana cost X chosen at random. Activate this ability only any time you could cast a sorcery and only once each turn.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[{X}, Discard a card: Put a token onto the battlefield that’s a copy of a creature card with converted mana cost X chosen at random. Activate this ability only any time you could cast a sorcery and only once each turn.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[{X}, Discard a card: Put a token onto the battlefield that’s a copy of a creature card with converted mana cost X chosen at random. Activate this ability only any time you could cast a sorcery and only once each turn.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[{X}, Discard a card: Put a token onto the battlefield that’s a copy of a creature card with converted mana cost X chosen at random. Activate this ability only any time you could cast a sorcery and only once each turn.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[{X}, Discard a card: Put a token onto the battlefield that’s a copy of a creature card with converted mana cost X chosen at random. Activate this ability only any time you could cast a sorcery and only once each turn.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[{X}, Discard a card: Put a token onto the battlefield that’s a copy of a creature card with converted mana cost X chosen at random. Activate this ability only any time you could cast a sorcery and only once each turn.]]></LOCALISED_TEXT>
<AVAILABILITY sorcery_time="1" per_turn_limit="1" />
<COST mana_cost="{X}" type="Mana" />
<COST type="Discard" definition="0" compartment="1" query_tag="CARD_QUERY_CHOOSE_CARD_TO_DISCARD" item_count="1" />
<COST_DEFINITION id="0">
local filter = ClearFilter()
filter:SetZone( ZONE_HAND, EffectController() )
</COST_DEFINITION>
<RESOLUTION_TIME_ACTION>
local cmc = GetEffectX()
local filter = ClearFilter()
filter:SetZone(ZONE_EXILE)
filter:Add(FE_TYPE, OP_IS, CARD_TYPE_CREATURE)
if cmc < 8 then
filter:Add(FE_CMC, OP_IS, cmc )
else
filter:Add(FE_CMC, OP_GREATER_THAN_OR_EQUAL_TO, 8 )
end
filter:EvaluateObjects()
local oCopy = filter:GetRandomEvaluatedObject()
if oCopy ~= nil then
MTG():PutTokenCopiesOntoBattlefield( oCopy, 1, EffectController() )
end
</RESOLUTION_TIME_ACTION>
<AI_AVAILABILITY window_step="main_1" window_turn="my_turn" type="window" />
<AI_AVAILABILITY window_step="main_2" window_turn="my_turn" type="window" />
</ACTIVATED_ABILITY>
<TRIGGERED_ABILITY active_zone="ZONE_ANY">
<TRIGGER value="BEGINNING_OF_STEP">
return MTG():GetStep() == STEP_UPKEEP and MTG():GetTurnNumber() == 0
</TRIGGER>
<FILTER filter_id="1">
local filter = ClearFilter()
filter:SetZone( ZONE_ANYWHERE, EffectController() )
filter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )
</FILTER>
<RESOLUTION_TIME_ACTION>
if EffectSource() ~= nil then
EffectSource():PutOntoBattlefield( EffectController() )
end
</RESOLUTION_TIME_ACTION>
<RESOLUTION_TIME_ACTION filter_id="1">
if FilteredCard() ~= nil then
FilteredCard():Exile()
end
</RESOLUTION_TIME_ACTION>
<RESOLUTION_TIME_ACTION>
local player = EffectController()
if player ~= nil then
local to_draw = 7 - player:Hand_Count()
if to_draw > 0 then
player:DrawCards(to_draw)
end
player:GainLife(4)
end
</RESOLUTION_TIME_ACTION>
<AUTO_SKIP always="1" />
</TRIGGERED_ABILITY>
<STATIC_ABILITY>
<INTRINSIC characteristic="CHARACTERISTIC_SHROUD" />
<INTRINSIC characteristic="CHARACTERISTIC_INDESTRUCTIBLE" />
<CONTINUOUS_ACTION layer="6">
if EffectSource() ~= nil then
for i=0,1-1 do
EffectSource():GetCurrentCharacteristics():GrantAbility(i)
end
end
</CONTINUOUS_ACTION>
</STATIC_ABILITY>
<TRIGGERED_ABILITY>
<TRIGGER value="ZONECHANGE_BEGIN" simple_qualifier="self" to_zone="ZONE_GRAVEYARD" from_zone="ZONE_BATTLEFIELD" />
<RESOLUTION_TIME_ACTION>
if TriggerObject() ~= nil then
TriggerObject():PutOntoBattlefield( TriggerObject():GetOwner() )
end
</RESOLUTION_TIME_ACTION>
</TRIGGERED_ABILITY>
<HELP title="MORE_INFO_MOMIR_BASIC_LIMITED_TITLE" body="MORE_INFO_MOMIR_BASIC_LIMITED_BODY" zone="ZONE_ANY" />
<HELP title="MORE_INFO_VANGUARD_TITLE" body="MORE_INFO_VANGUARD_BODY" zone="ZONE_ANY" />
<AI_BASE_SCORE score="-5000" zone="ZONE_BATTLEFIELD" />
</CARD_V2>
- Attachments
-
- Magic 2014 - MOMIR.rar
- (397.38 KiB) Downloaded 324 times
-----------------------------------------------------------------------
Song of the Day: 46 and 2 (cover)
Song of the Day: 46 and 2 (cover)
Re: General DotP 2014 Coding Questions
by RiiakShiNal » 26 Oct 2013, 15:12
You actually don't have to convert cards to tokens as it is possible to put a card that is not a token onto the battlefield as a token. I do this with my Manual Mana. My Mana tokens do not have the <TOKEN/> block and I am still able to put them onto the battlefield using MTG():PutTokensOntoBattlefield().MC Brodie wrote:The more appropriate way to implement Momir Basic is probably to convert every creature card to a token, then list about 7000 token registrations onto Momir (of course I could be overlooking somethign that would make this a worse idea than what it already is). Though that seems like a real pain, it doesn't look like there is much of a difference between a creature XML and a token XML. From a simple person (i.e. me), it would be possible to write a program that would take a creature XML file then change the text in the <FILENAME../> and <MULTIVERSEID../> blocks and add <TOKEN/> to the code. If that is possible, any help to point me in the right direction would be appreciated. Even if it isn't the best idea, it would be a good learning experience for someone like me whose only real programming experience is DotP.
Though if you actually want to write a program to read in a card XML and make changes like that then it is quite possible; how exactly you go about it will depend on which language you are going to write it in. For example in C# you can read in a card's XML by simply using this:
- Code: Select all
using System;
using System.Text;
using System.Xml;
public XmlDocument LoadCard(string strFilename)
{
XmlDocument xdCard = new XmlDocument();
xdDoc.Load(strFilename);
return xdCard;
}
- Code: Select all
public void AddTokenBlock(XmlDocument xdCard, XmlNode xnCard)
{
xnCard.AppendChild(xdCard.CreateElement("TOKEN"));
}
- Code: Select all
public XmlNode GetCardV2Node(XmlDocument xdCard)
{
return xdCard["CARD_V2"];
}
The attributes of the FILENAME and MULTIVERSEID blocks can also be changed quite simply by first finding those nodes, then locating the attribute to change on those node (should be very easy because they each only have one attribute) and then just assign the new value.
Once you have finished making changes then you can simply save out the modified XML using:
- Code: Select all
public void SaveCard(XmlDocument xdCard, string strFilename)
{
xdCard.Save(strFilename);
}
For more detailed examples on how to parse the Card XML you can look at the source code of my Deck Builder (all card information is parsed in CardInfo.cs, though some of the actual XML parsing is in XmlTools.cs). Though in the Deck Builder I am parsing out the information to then easily display and use rather than to change and re-output.
Just getting started: Xander9009's DotP 2014 Community Wad
Need a deck builder: DotP 2014 Deck Builder
Problems Modding: DotP 2014 Frequent Modding Mistakes
Need a deck builder: DotP 2014 Deck Builder
Problems Modding: DotP 2014 Frequent Modding Mistakes
- RiiakShiNal
- Programmer
- Posts: 2185
- Joined: 16 May 2011, 21:37
- Has thanked: 75 times
- Been thanked: 497 times
Who is online
Users browsing this forum: No registered users and 8 guests