Board index Programs with AI or Rules Enforcement Magic: The Gathering - Duels of the Planeswalkers Programming Talk
Ghostly Prison: that's a difficult card!
Moderator: CCGHQ Admins
Ghostly Prison: that's a difficult card!
by thefiremind » 11 Aug 2012, 16:34
I finally managed to make a working Ghostly Prison, after lots of tries. Here's the code:
I'm not 100% satisfied because the trigger at the beginning of combat would have been more correct as an END_OF_STEP trigger. I tried to make it like that, but the card started to give odd results because there wasn't enough time to process the new conditions before attackers were declared. Anyway I can't think of scenarios where being able to do something between the payment and the declaration of the attackers could disrupt the game, so I can live with the approximation.
About the AI: I think it understands quite well what's going on. From the few tests I made with the fully working card, it seems that it often gives more importance to playing spells rather than attacking when it has to deal with Ghostly Prison, but I saw it paying and attacking with a creature, so the test is positive.
If you think you can code Ghostly Prison in a simpler and/or cleaner way, or you just have a suggestion, please let me know.
- Code: Select all
<?xml version='1.0'?>
<CARD_V2>
<FILENAME text="GHOSTLY_PRISON_75328" />
<CARDNAME text="GHOSTLY_PRISON" />
<TITLE>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Ghostly Prison]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Prigione Spettrale]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Gespenstisches Gefängnis]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Prison fantomale]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Prisión fantasmagórica]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[亡霊の牢獄]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Ghostly Prison]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Ghostly Prison]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Prisão Fantasmagórica]]></LOCALISED_TEXT>
</TITLE>
<MULTIVERSEID value="75328" />
<ARTID value="A75328" />
<ARTIST name="Lars Grant-West" />
<CASTING_COST cost="{2}{W}" />
<FLAVOURTEXT>
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Destroyed in one of the first battles of the Kami War, the town of Reito still grieved.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Distrutta durante una delle prime battaglie della Guerra dei Kami, la città di Reito piange ancora.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Die Stadt Reito war immer noch am Trauern, obwohl sie schon in einer der ersten Schlachten des Kami-Krieges zerstört worden war.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Détruite lors d’une des premières batailles de la Guerre des kami, la ville de Reito pleurait encore.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Destruida en una de las primeras batallas de la guerra con los kami, la ciudad de Reito aún se lamenta.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[神の乱の最初の戦闘で破壊された霊都は、いまだに嘆きの中にある。]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Destroyed in one of the first battles of the Kami War, the town of Reito still grieved.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Destroyed in one of the first battles of the Kami War, the town of Reito still grieved.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Destruída em uma das primeiras batalhas da Guerra dos Kamis, a cidade de Reito ainda estava em luto.]]></LOCALISED_TEXT>
</FLAVOURTEXT>
<TYPE metaname="Enchantment" />
<EXPANSION value="CHK" />
<RARITY metaname="U" />
<TRIGGERED_ABILITY auto_skip="1">
<LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Creatures can’t attack you unless their controller pays {2} for each creature he or she controls that’s attacking you.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Le creature non possono attaccarti a meno che il loro controllore non paghi {2} per ogni creatura che controlla che ti sta attaccando.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Kreaturen können dich nicht angreifen, falls ihr Beherrscher nicht für jede dich angreifende Kreatur, die er kontrolliert, {2} bezahlt.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Les créatures ne peuvent pas vous attaquer à moins que leur contrôleur ne paie {2} pour chaque créature qu’il contrôle qui vous attaque.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Las criaturas no pueden atacarte a menos que su controlador pague {2} por cada criatura que controla que te está atacando.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[クリーチャーは、それのコントローラーが、そのプレイヤーがコントロールするあなたを攻撃しているクリーチャー1体につき{2}を支払わないかぎり、あなたを攻撃できない。]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Creatures can’t attack you unless their controller pays {2} for each creature he or she controls that’s attacking you.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Creatures can’t attack you unless their controller pays {2} for each creature he or she controls that’s attacking you.]]></LOCALISED_TEXT>
<LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[As criaturas não podem atacá-lo a menos que seu controlador pague {2} para cada criatura atacante.]]></LOCALISED_TEXT>
<TRIGGER value="BEGINNING_OF_STEP">
local player = TriggerPlayer()
local cost = 2
if MTG():GetStep() == STEP_BEGIN_COMBAT and
player:MyTurn() ~= 0 and
player:GetTeam() ~= EffectController():GetTeam() and
player:CanAfford("{"..cost.."}") == 1 then
local filter = Object():GetFilter()
filter:Clear()
filter:AddCardType( CARD_TYPE_CREATURE )
filter:SetZone( ZONE_IN_PLAY )
filter:SetController( player )
filter:NotTargetted()
if filter:CountStopAt(1) == 1 then
return true
end
end
return false
</TRIGGER>
<RESOLUTION_TIME_ACTION>
local player = TriggerPlayer()
local cost = 2
if player:CanAfford("{"..cost.."}") == 1 then
local filter = Object():GetFilter()
filter:Clear()
filter:AddCardType( CARD_TYPE_CREATURE )
filter:SetZone( ZONE_IN_PLAY )
filter:SetController( player )
filter:NotTargetted()
if filter:CountStopAt(1) == 1 then
local max_attackers = player:GetTotalMana() / cost
player:SetTargetCount( max_attackers )
for i=0,max_attackers-1 do
player:SetTargetPrompt( i, "CARD_QUERY_CHOOSE_CREATURE_GHOSTLY_PRISON" )
end
player:ChooseTargetsWithFlags( NO_VALIDATION, EffectDC():Make_Targets(0), QUERY_FLAG_CAN_BE_FINISHED_EARLY + QUERY_FLAG_CAN_BE_FINISHED_EARLY_FOR_AI_AS_WELL )
end
end
</RESOLUTION_TIME_ACTION>
<RESOLUTION_TIME_ACTION>
local player = TriggerPlayer()
local cost = 2
if player:CanAfford("{"..cost.."}") == 1 then
local filter = Object():GetFilter()
filter:Clear()
filter:AddCardType( CARD_TYPE_CREATURE )
filter:SetZone( ZONE_IN_PLAY )
filter:SetController( player )
filter:NotTargetted()
if filter:CountStopAt(1) == 1 and EffectDC() ~= nil and EffectDC():Get_Targets(0) ~= nil then
local max_attackers = player:GetTotalMana() / cost
local ptr_index = 0
local player_index = -1
local nsp = MTG():GetNumberOfStartingPlayers()
for i=0,nsp-1 do
if MTG():GetNthStartingPlayer(i) == player then
player_index = i
end
end
local player_chest = ObjectDC():Make_Chest(player_index)
for i=0,max_attackers-1 do
local creature = EffectDC():Get_Targets(0):Get_CardPtr(i)
if creature ~= nil then
player_chest:Set_CardPtr(ptr_index, creature)
if player:CanAfford("{"..cost.."}") == 1 then
player:TapLand("{"..cost.."}")
end
ptr_index = ptr_index + 1
end
end
ObjectDC():Set_Int(nsp+player_index, ptr_index)
end
end
</RESOLUTION_TIME_ACTION>
</TRIGGERED_ABILITY>
<TRIGGERED_ABILITY internal="1" pre_trigger="1">
<TRIGGER value="CANT_ATTACK_PLAYER_TEST">
if TriggerPlayer() == EffectController() and ObjectDC() ~= nil then
local player = TriggerObject():GetController()
local player_index = -1
local nsp = MTG():GetNumberOfStartingPlayers()
for i=0,nsp-1 do
if MTG():GetNthStartingPlayer(i) == player then
player_index = i
end
end
local ptr_index = ObjectDC():Get_Int(nsp+player_index)
if ptr_index > 0 then
local player_chest = ObjectDC():Get_Chest(player_index)
if player_chest ~= nil then
for i=0,ptr_index-1 do
if player_chest:Get_CardPtr(i) ~= nil and TriggerObject() == player_chest:Get_CardPtr(i) then
return false
end
end
end
end
return true
end
return false
</TRIGGER>
</TRIGGERED_ABILITY>
<TRIGGERED_ABILITY internal="1">
<TRIGGER value="BEGINNING_OF_STEP">
return MTG():GetStep() == STEP_END_OF_COMBAT and
TriggerPlayer():MyTurn() ~= 0 and
TriggerPlayer():GetTeam() ~= EffectController():GetTeam()
</TRIGGER>
<RESOLUTION_TIME_ACTION>
local player_index = -1
local nsp = MTG():GetNumberOfStartingPlayers()
for i=0,nsp-1 do
if MTG():GetNthStartingPlayer(i) == player then
player_index = i
end
end
local player_chest = ObjectDC():Get_Chest(player_index)
if player_chest ~= nil then
player_chest:Clear()
end
ObjectDC():Set_Int(nsp+player_index, 0)
</RESOLUTION_TIME_ACTION>
</TRIGGERED_ABILITY>
<AI_BASE_SCORE score="450" zone="ZONE_IN_PLAY" />
</CARD_V2>
I'm not 100% satisfied because the trigger at the beginning of combat would have been more correct as an END_OF_STEP trigger. I tried to make it like that, but the card started to give odd results because there wasn't enough time to process the new conditions before attackers were declared. Anyway I can't think of scenarios where being able to do something between the payment and the declaration of the attackers could disrupt the game, so I can live with the approximation.
About the AI: I think it understands quite well what's going on. From the few tests I made with the fully working card, it seems that it often gives more importance to playing spells rather than attacking when it has to deal with Ghostly Prison, but I saw it paying and attacking with a creature, so the test is positive.
If you think you can code Ghostly Prison in a simpler and/or cleaner way, or you just have a suggestion, please let me know.
< 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: Ghostly Prison: that's a difficult card!
by sadlyblue » 11 Aug 2012, 17:46
Great job. I always loved that card, and the blue version Propaganda. It's great for control...
Re: Ghostly Prison: that's a difficult card!
by nabeshin » 13 Aug 2012, 18:24
I made some options, all problem in that that AI would understand that occurs and correctly reacted, almost done Norn's Annex , but I am dissatisfied
Re: Ghostly Prison: that's a difficult card!
by spakattack » 17 May 2013, 00:39
I love this card, but the AI hardly ever attacks, even when they have enough mana. Sometimes they will pay the mana and attack, but most of the time they won't, even if they could directly attack me. Sometimes they will pay the mana and do nothing on the battle phase.
I have to do more testing, but maybe they didn't attack for some other reason. It just seems the AI doesn't understand the card completely, and won't always attack when they could(probably should of). I win almost every game when I get 1, 2, or more of these out because of the AI not attacking when they had enough mana (and sometimes when I have no creatures and they have like a 30/30 primalcrux, a dozen creatures/tokens or something like that.)
I'm just glad it's coded and exists, but it seems like there is something up with the AI dealing with it. I guess that's why there are other humans out there to play with. Though, sadly, I really don't know how to play with other people with custom wads.
I have to do more testing, but maybe they didn't attack for some other reason. It just seems the AI doesn't understand the card completely, and won't always attack when they could(probably should of). I win almost every game when I get 1, 2, or more of these out because of the AI not attacking when they had enough mana (and sometimes when I have no creatures and they have like a 30/30 primalcrux, a dozen creatures/tokens or something like that.)
I'm just glad it's coded and exists, but it seems like there is something up with the AI dealing with it. I guess that's why there are other humans out there to play with. Though, sadly, I really don't know how to play with other people with custom wads.
- spakattack
- Posts: 32
- Joined: 30 Apr 2013, 21:45
- Has thanked: 9 times
- Been thanked: 2 times
Re: Ghostly Prison: that's a difficult card!
by thefiremind » 17 May 2013, 09:16
Sorry to hear that... I tested it really fast, and I stopped when I saw the AI paying once. I couldn't imagine that it was a rare event. Anyway, I wouldn't know how to make the card better: as I said in the first post, if someone has a better idea, please don't hesitate to explain it.
< 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
5 posts
• Page 1 of 1
Who is online
Users browsing this forum: No registered users and 34 guests