Xander9009 wrote:Ah, ok. I more or less understand it now. Regardless, I noticed it doesn't appear in the properly decompiled ones; it just returns the tables.
That's because those files aren't decompiled: I ran them through the Lua console and then retrieved just the table through the dumper I linked earlier. Different dumpers can give different results (the one I chose prefixes the table with "return" so that the file can be actually executed in the Lua console in order to retrieve the table again).
Xander9009 wrote:Just need to map the various XML tags to their LUA element name counterparts (the attributes are all identical I think, but I didn't verify).
That's the part that worries me more, since it's very easy to forget one. I should try and get the possible tags from the executable before starting, so that I can see them all together.
Xander9009 wrote:I did notice your decompiler changed the semi-colons to commas. I doubt it would have any effect in-game, but it's worth noting just in case.
I hope it doesn't have any effect.
Xander9009 wrote:One of those suggestions was to make a dummy T function, but I wasn't sure if that would even really do anything.
My function was
- Code: Select all
T = function(s) return s end
It couldn't be dummier than that, but it did its job.

Xander9009 wrote:Nothing more than a simple search and replace on a regex:
Find: data = (.*?),$
Replace with: data = T\($1\),
Replace all.
No that it would necessarily make them compile correctly, but just to add the T functions for viewing them...
For the existing cards I just wanted to look at the structure without worrying about T: we know it exists from the card I decompiled and it's enough.
EDIT: Something that would be incredibly useful: finding a way to "merge" all card tables together. Let me explain: input all the tables and have a single table in output that has all the possible sub-tables and attributes (their values wouldn't matter). We would be still missing sub-tables that aren't used in official cards, but those wouldn't be many.
It appears that there's a library for that. I need to try.

EDIT 2: Here's the result of merging. I got some errors about non-iterable things, but the output seems OK to me.
- All card tables merged | Open
- Code: Select all
return {
art_id = "160671",
artist = "Jason Rainville",
card_name = "ZULAPORT_CUTTHROAT",
casting_cost = "{1}{B}",
colour = "W",
expansion = "BFZ",
export_version = "1",
file_name = "ZULAPORT_CUTTHROAT_385353",
is_backside = "True",
landgroup = "1",
loyalty = "5",
multiverse_id = "385353",
power = "1",
rarity = "U",
set_id = "BFZ",
token = "True",
toughness = "1",
ai_counter_scores = {
ai_counter_score_0 = {
max_counters = "1",
score = "600",
type = "+1/+1",
},
},
ai_custom_scores = {
ai_custom_score_0 = {
code = "\t\t\t\tlocal filter = ClearFilter()\n\t\t\t\tfilter:Add(FE_SUB_TYPE, OP_IS, ARTIFACT_TYPE_EQUIPMENT)\n\t\t\t\tfilter:Add(FE_CONTROLLER, OP_IS, EffectController())\n\t\t\t\tif filter:CountStopAt(1) ~= 1 then\n\t\t\t\t\tEffectSource():AddScore(100)\n\t\t\t\tend\n\t\t\t",
},
},
ai_loyalty_ability_scores = {
ai_loyalty_ability_score_0 = {
cost = "1",
score = "400",
},
ai_loyalty_ability_score_1 = {
cost = "-2",
score = "1200",
},
ai_loyalty_ability_score_2 = {
cost = "-7",
score = "4600",
},
},
ai_simplified_targetings = {
ai_simplified_targeting_0 = {
compartment = "0",
hint = "HINT_ENEMY_ONLY",
},
},
archetypes = {
archetype_0 = {
type = "Monster",
},
},
combat_kill_scores = {
combat_kill_score_0 = {
code = "\t\t\t\tlocal linkedDC = LinkedDC()\n\t\t\t\tif linkedDC ~= nil then\n\t\t\t\t\tlocal linkedChest = linkedDC:Get_Chest(0)\n\t\t\t\t\tif linkedChest ~= nil then\n\t\t\t\t\t\tlocal stolenCard = linkedChest:Get_CardPtr(0)\n\t\t\t\t\t\tif stolenCard == nil then\n\t\t\t\t\t\t return 0\n\t\t\t\t\t\telse\n\t\t\t\t\t\t return ((stolenCard:CalcScore())*2)\n\t\t\t\t\t\tend\n\t\t\t\t\telse\n\t\t\t\t\t\treturn 0\n\t\t\t\t\tend\n\t\t\t\telse\n\t\t\t\t\treturn 0\n\t\t\t\tend\n\t\t\t",
linked_ability_group = "0",
},
},
costs = {
cost_0 = {
amount = "£Value£",
type = "Energy",
},
cost_1 = {
type = "TapSelf",
},
},
deckbuilding_activation_levels = {
deckbuilding_activation_level_0 = {
base_score = "1100",
},
deckbuilding_activation_level_1 = {
base_score = "0",
{
max_amount = "24",
min_amount = "12",
resource_subtype = "ALLY",
score_per_unit = "13",
},
{
max_amount = "12",
resource_subtype = "ALLY",
score_per_unit = "7",
},
},
},
deckbuilding_metadatas = {
deckbuilding_metadata_0 = {
defensive = "1",
},
},
deckbuilding_synergy_resources = {
deckbuilding_synergy_resource_0 = {
amount = "1",
resource_name = "Sacrifice",
},
},
derived_infos = {
derived_info_0 = {
code = "\t\t\t\tlocal filter = ClearFilter()\n\t\t\t\tlocal player = EffectController()\n\t\t\t\tfilter:SetZone( ZONE_GRAVEYARD, player )\n\t\t\t\tlocal subfilter = filter:AddSubFilter_Or()\n\t\t\t\t\tsubfilter:Add( FE_TYPE, OP_IS, CARD_TYPE_INSTANT )\n\t\t\t\t\tsubfilter:Add( FE_TYPE, OP_IS, CARD_TYPE_SORCERY )\n\t\t\t\treturn filter:Count()\n\t\t\t",
plural2_tag = "£DerivedInfoPlural2Tag£",
plural_tag = "£DerivedInfoPluralTag£",
tag = "£DerivedInfoTag£",
},
},
explain = {
is_removal = "false",
},
filters = {
filter_0 = {
code = "\t\t\t\tlocal player = EffectDC():Get_Targets(0):Get_PlayerPtr(0)\n\t\t\t\tif player ~= nil then\n\t\t\t\t\tlocal target_player = EffectDC():Get_Targets(0):Get_PlayerPtr(0)\n\t\t\t\t\t\n\t\t\t\t\tlocal filter = ClearFilter()\n\t\t\t\t\tfilter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )\n\t\t\t\t\tfilter:Add( FE_CONTROLLER, OP_IS, target_player )\n\t\t\t\telse\n\t\t\t\t\tlocal target_player = EffectDC():Get_Targets(0):Get_CardPtr(0):GetPlayer()\n\t\t\t\t\t\n\t\t\t\t\tlocal filter = ClearFilter()\n\t\t\t\t\tfilter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )\n\t\t\t\t\tfilter:Add( FE_CONTROLLER, OP_IS, target_player )\n\t\t\t\tend\n\t\t\t",
filter_id = "0",
},
},
flavour_text = {
text = {
{
data = "“Eldrazi? Ha! Try walking through Zulaport at night with your pockets full. Now |that’s |dangerous.”",
language_code = "en-US",
},
{
data = "« Les Eldrazi ? Quelle blague ! Essayez donc de traverser Zulaport de nuit avec les poches pleines. |Ça |c’est dangereux. »",
language_code = "fr-FR",
},
{
data = "“¿Eldrazi? ¡Ja! Prueba a caminar por Zulaport de noche con los bolsillos llenos. Eso |sí |es peligroso”.",
language_code = "es-ES",
},
{
data = "„Eldrazi? Ha! Versuch mal, nachts mit vollen Taschen durch Zulaport zu laufen. |Das |ist gefährlich!“",
language_code = "de-DE",
},
{
data = "“Eldrazi? Ah! Prova a camminare di notte per Zulaport con le tasche piene. Ecco, quello è pericoloso.”<i></i>",
language_code = "it-IT",
},
{
data = "「エルドラージ?どうってことねぇな。ポケット膨らまして夜中のズーラポートを歩いてみな。それが身の危険さ。」",
language_code = "jp-JA",
},
{
data = "\"엘드라지? 웃기는군! 지갑을 두둑이 채우고 한밤중에 줄라포트를 지나가 보라구. |그런 게 |위험한 거지.\"",
language_code = "ko-KR",
},
{
data = "«Эльдрази? Ха! Попробуй прогуляться вечером по Зулапорту с полными карманами. Вот это — |настоящая опасность|».",
language_code = "ru-RU",
},
{
data = "“Eldrazi? Que nada! Tente andar por Zulaport à noite com os bolsos cheios. Isso |sim |é perigoso.”",
language_code = "pt-BR",
},
{
data = "「奥札奇?呵呵!不妨腰缠万贯时在夜晚来筑拉波走一遭。这才叫危险。」",
language_code = "zh-CN",
},
{
data = "「奧札奇?呵呵!不妨腰纏萬貫時在夜晚來筑拉波走一遭。|這|才叫危險。」",
language_code = "zh-HK",
},
},
},
target_definitions = {
target_definition_0 = {
code = "\t\t\t\tlocal filter = ClearFilter()\n\t\t\t\tfilter:SetFilterType( FILTER_TYPE_PLAYERS )\n\t\t\t\tfilter:Add( FE_TEAM, OP_NOT, EffectController():GetTeam() )\n\t\t\t",
},
},
targets = {
target_0 = {
compartment = "0",
count = "1",
definition = "0",
tag = "£TargetString£",
},
},
title = {
text = {
{
data = "Zulaport Cutthroat",
language_code = "en-US",
},
{
data = "Surineur de Zulaport",
language_code = "fr-FR",
},
{
data = "Degollador de Zulaport",
language_code = "es-ES",
},
{
data = "Zulaport-Mordgeselle",
language_code = "de-DE",
},
{
data = "Tagliagole di Zulaport",
language_code = "it-IT",
},
{
data = "ズーラポートの殺(ころ)し屋(や)",
language_code = "jp-JA",
},
{
data = "줄라포트 살인귀",
language_code = "ko-KR",
},
{
data = "Головорез из Зулапорта",
language_code = "ru-RU",
},
{
data = "Degolador de Zulaport",
language_code = "pt-BR",
},
{
data = "筑拉波割喉客",
language_code = "zh-CN",
},
{
data = "筑拉波割喉客",
language_code = "zh-HK",
},
},
},
transformation = {
icon = "CMOON",
value = "HANWEIR_MILITIA_CAPTAIN_386629",
},
abilities = {
{
type = "triggered",
{
priority = "150",
actions = {
{
type = "resolution_time",
{
code = "\t\t\t\t\t\t\t\tif FilteredPlayer() ~= nil then \n\t\t\t\t\t\t\t\t\tFilteredPlayer():LoseLife( 1 )\n\t\t\t\t\t\t\t\tend\n\t\t\t\t\t\t\t",
filter_id = "0",
},
},
{
type = "resolution_time",
{
code = "\t\t\t\t\t\t\t\tEffectController():GainLife( 1 )\n\t\t\t\t\t\t\t",
},
},
},
filters = {
{
code = "\t\t\t\t\t\t\tlocal filter = ClearFilter()\n\t\t\t\t\t\t\tfilter:SetFilterType( FILTER_TYPE_PLAYERS )\n\t\t\t\t\t\t\tfilter:Add( FE_TEAM, OP_NOT, EffectController():GetTeam() )\n\t\t\t\t\t\t",
filter_id = "0",
},
},
text = {
{
data = "Whenever Zulaport Cutthroat or another creature you control dies, each opponent loses 1 life and you gain 1 life.",
language_code = "en-US",
},
{
data = "À chaque fois que le Surineur de Zulaport ou qu’une autre créature que vous contrôlez meurt, chaque adversaire perd 1 point de vie et vous gagnez 1 point de vie.",
language_code = "fr-FR",
},
{
data = "Siempre que el Degollador de Zulaport u otra criatura que controlas muera, cada oponente pierde 1 vida y tú ganas 1 vida.",
language_code = "es-ES",
},
{
data = "Immer wenn der Zulaport-Mordgeselle oder eine andere Kreatur, die du kontrollierst, stirbt, verliert jeder Gegner 1 Lebenspunkt, und du erhältst 1 Lebenspunkt dazu.",
language_code = "de-DE",
},
{
data = "Ogniqualvolta il Tagliagole di Zulaport o un’altra creatura che controlli muoiono, ogni avversario perde 1 punto vita e tu guadagni 1 punto vita.",
language_code = "it-IT",
},
{
data = "ズーラポートの殺し屋かあなたがコントロールする他のクリーチャーが1体死亡するたび、各対戦相手はそれぞれ1点のライフを失い、あなたは1点のライフを得る。",
language_code = "jp-JA",
},
{
data = "줄라포트 살인귀나 당신이 조종하는 다른 생물이 죽을 때마다, 각 상대는 생명 1점을 잃고 당신은 생명 1점을 얻는다.",
language_code = "ko-KR",
},
{
data = "Каждый раз, когда Головорез из Зулапорта или другое существо под вашим контролем умирает, каждый оппонент теряет 1 жизнь, а вы получаете 1 жизнь.",
language_code = "ru-RU",
},
{
data = "Toda vez que Degolador de Zulaport ou outra criatura que você controla morre, cada oponente perde 1 ponto de vida e você ganha 1 ponto de vida.",
language_code = "pt-BR",
},
{
data = "每当筑拉波割喉客或另一个由你操控的生物死去时,每位对手各失去1点生命且你获得1点生命。",
language_code = "zh-CN",
},
{
data = "每當筑拉波割喉客或另一個由你操控的生物死去時,每位對手各失去1點生命且你獲得1點生命。",
language_code = "zh-HK",
},
},
triggers = {
{
from_zone = "ZONE_BATTLEFIELD",
simple_qualifier = "self",
to_zone = "ZONE_GRAVEYARD",
value = "ZONECHANGE_BEGIN",
},
{
code = "\t\t\t\t\t\t\treturn ((TriggerObject() ~= EffectSource() and TriggerObject():GetCardType():Test( CARD_TYPE_CREATURE )) and (TriggerObject():GetPlayer() == EffectController()))\n\t\t\t\t\t\t",
from_zone = "ZONE_BATTLEFIELD",
simple_qualifier = "objectyoucontrol",
to_zone = "ZONE_GRAVEYARD",
value = "ZONECHANGE_BEGIN",
},
},
},
},
},
actions = {
{
type = "resolution_time",
{
code = "\t\t\t\t\tlocal answerDC = EffectDC():Get_Targets( 2 )\n\t\t\t\t\tlocal spellsToCast = answerDC:Count()\n\t\t\t\t\tlocal effectController = EffectController()\n\t\t\t\t\tif spellsToCast == nil then\n\t\t\t\t\t\treturn\n\t\t\t\t\tend\n\t\t\t\t\tfor i = (spellsToCast-1), 0, -1 do\n\t\t\t\t\t\tlocal card = answerDC:Get_CardPtr(i)\n\t\t\t\t\t\tif card ~= nil and effectController:CanCastSpellForFree( card ) then\n\t\t\t\t\t\t\teffectController:CastSpellForFree( card )\n\t\t\t\t\t\tend\n\t\t\t\t\tend\n\t\t\t\t",
},
},
{
type = "resolution_time",
{
code = "\t\t\t\t\tlocal targetPlayer = EffectDC():Get_Targets(0):Get_PlayerPtr(0)\n\t\t\t\t\tlocal answerDC = EffectDC():Make_Targets(2)\n\t\t\t\t\tlocal queryDC = EffectDC():Make_Chest(1)\n\t\t\t\t\tlocal cardsToSelect = 0\n\t\t\t\t\tlocal effectController = EffectController()\n\t\t\t\t\tif targetPlayer == nil then\n\t\t\t\t\t\treturn\n\t\t\t\t\tend\n\t\t\t\t\t-- Mill 7 cards and store them in queryDC. Deselect permanent cards.\n\t\t\t\t\tlocal lib_count = targetPlayer:Library_Count()\n\t\t\t\t\tif MTG():IsMainDuel() == false then -- Anti-Cheat script\n\t\t\t\t\t\tfor i = 0,(6) do\n\t\t\t\t\t\t\tlocal card = targetPlayer:Library_GetNth( math.random( 1, lib_count ) )\n\t\t\t\t\t\t\tif card ~= nil then\n\t\t\t\t\t\t\t\tqueryDC:Set_CardPtr(i, card)\n\t\t\t\t\t\t\t\tqueryDC:Protect_CardPtr(i)\n\t\t\t\t\t\t\t\tcard:PutInGraveyard()\n\t\t\t\t\t\t\t\tif card:GetCardType():Test( CARD_TYPE_SORCERY ) or card:GetCardType():Test( CARD_TYPE_INSTANT ) then\n\t\t\t\t\t\t\t\t\tif effectController:CanCastSpellForFree( card ) then\t\n\t\t\t\t\t\t\t\t\t\tcardsToSelect = cardsToSelect+1\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tqueryDC:QueryUnselect_CardPtr(i)\n\t\t\t\t\t\t\t\t\tend\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tqueryDC:QueryUnselect_CardPtr(i)\n\t\t\t\t\t\t\t\tend\n\t\t\t\t\t\t\tend\n\t\t\t\t\t\tend\n\t\t\t\t\telse\n\t\t\t\t\t\tfor i = 0, 6 do\n\t\t\t\t\t\t\tlocal card = targetPlayer:Library_GetNth(0)\n\t\t\t\t\t\t\tif card ~= nil then\n\t\t\t\t\t\t\t\tqueryDC:Set_CardPtr(i, card)\n\t\t\t\t\t\t\t\tqueryDC:Protect_CardPtr(i)\n\t\t\t\t\t\t\t\tcard:PutInGraveyard()\n\t\t\t\t\t\t\t\tif card:GetCardType():Test( CARD_TYPE_SORCERY ) or card:GetCardType():Test( CARD_TYPE_INSTANT ) then\n\t\t\t\t\t\t\t\t\tif effectController:CanCastSpellForFree( card ) then\t\n\t\t\t\t\t\t\t\t\t\tcardsToSelect = cardsToSelect+1\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tqueryDC:QueryUnselect_CardPtr(i)\n\t\t\t\t\t\t\t\t\tend\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tqueryDC:QueryUnselect_CardPtr(i)\n\t\t\t\t\t\t\t\tend\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tbreak\t\n\t\t\t\t\t\t\tend\n\t\t\t\t\t\tend\n\t\t\t\t\tend\n\t\t\t\t\t-- Spell Mastery check\n\t\t\t\t\tlocal filter = ClearFilter()\n\t\t\t\t\tfilter:SetZone(ZONE_GRAVEYARD, effectController)\n\t\t\t\t\tlocal subfilter = filter:AddSubFilter_Or()\n\t\t\t\t\t\tsubfilter:Add(FE_TYPE, OP_IS, CARD_TYPE_INSTANT)\n\t\t\t\t\t\tsubfilter:Add(FE_TYPE, OP_IS, CARD_TYPE_SORCERY)\n\t\t\t\t\tif (filter:CountStopAt( 2 ) == 2) then\n\t\t\t\t\t\tEffectDC():Set_Int( 3, 1 )\n\t\t\t\t\tend\n\t\t\t\t\t-- If Spell Mastery is fulfilled, the player selects 2 cards. If Spell Mastery is not fulfilled, the player selects up to one card.\n\t\t\t\t\tif (EffectDC():Get_Int(3) == 1) then\n\t\t\t\t\t\teffectController:SetItemCount( 2 )\n\t\t\t\t\t\tfor j = 0, 1 do \n\t\t\t\t\t\t\teffectController:SetItemPrompt( j, \"£QuerySpellMastery£\" )\n\t\t\t\t\t\tend\n\t\t\t\t\t\teffectController:ChooseItemsFromDC( queryDC, answerDC, QUERY_FLAG_MAY + QUERY_FLAG_ORDERED_SELECTION )\n\t\t\t\t\telse\n\t\t\t\t\t\teffectController:ChooseItemFromDC( \"£Query£\", queryDC, answerDC, QUERY_FLAG_MAY )\n\t\t\t\t\tend\n\t\t\t\t",
},
},
},
ai_availabilitys = {
{
type = "window",
window_step = "STEP_DECLARE_BLOCKERS",
},
{
response_target = "1",
type = "in_response",
},
{
response_source = "1",
type = "in_response",
},
},
ai_base_scores = {
{
score = "450",
zone = "ZONE_BATTLEFIELD",
},
},
more_info = {
{
body = "MORE_INFO_BODY_COHORT",
title = "MORE_INFO_TITLE_COHORT",
zone = "ZONE_ANY",
},
},
query_text = {
{
tag = "CARD_QUERY_CHOOSE_ALLY_YOU_CONTROL_TO_TAP",
text = {
{
data = "Choose an Ally you control to tap.",
language_code = "en-US",
},
{
data = "Choisissez un allié que vous contrôlez pour l'engager.",
language_code = "fr-FR",
},
{
data = "Elige un Aliado que controlas para girarlo.",
language_code = "es-ES",
},
{
data = "Bestimme einen Verbündeten, den du kontrollierst und der getappt werden soll.",
language_code = "de-DE",
},
{
data = "Scegli un Alleato che controlli da TAPpare.",
language_code = "it-IT",
},
{
data = "タップする、あなたがコントロールするアンタップ状態の同盟者を1体選んでください。",
language_code = "jp-JA",
},
{
data = "탭할 당신이 조종하는 동맹 한 개를 고르십시오.",
language_code = "ko-KR",
},
{
data = "Выберите Союзника под вашим контролем для поворота.",
language_code = "ru-RU",
},
{
data = "Escolha um Aliado que você controla para virar.",
language_code = "pt-BR",
},
{
data = "选择一个由你操控的伙伴,以将之横置。",
language_code = "zh-CN",
},
{
data = "選擇一個由你操控的伙伴,以將其橫置。",
language_code = "zh-HK",
},
},
},
{
tag = "CARD_QUERY_CHOOSE_OPPONENT_LOSE_2_LIFE",
text = {
{
data = "Choose an opponent to lose 2 life.",
language_code = "en-US",
},
{
data = "Choisissez un adversaire pour qu'il perde 2 points de vie.",
language_code = "fr-FR",
},
{
data = "Elige un oponente para que pierda 2 vidas.",
language_code = "es-ES",
},
{
data = "Bestimme einen Gegner, der 2 Lebenspunkte verlieren soll.",
language_code = "de-DE",
},
{
data = "Scegli un avversario che perde 2 punti vita.",
language_code = "it-IT",
},
{
data = "2点のライフを失う対戦相手を1人選んでください。",
language_code = "jp-JA",
},
{
data = "생명 2점을 잃을 상대를 고르십시오.",
language_code = "ko-KR",
},
{
data = "Выберите оппонента, который должен потерять 2 жизни.",
language_code = "ru-RU",
},
{
data = "Escolha um oponente para perder 2 pontos de vida.",
language_code = "pt-BR",
},
{
data = "选择一位对手,以让其失去2点生命。",
language_code = "zh-CN",
},
{
data = "選擇一個對手來使其失去2點生命。",
language_code = "zh-HK",
},
},
},
},
sfx = {
{
name = "COMBAT_SLASH_LARGE_ATTACK",
power_boundary_max = "-1",
power_boundary_min = "4",
},
{
name = "COMBAT_SLASH_SMALL_ATTACK",
power_boundary_max = "3",
power_boundary_min = "1",
},
},
sub_types = {
{
metaname = "Human",
order_deDE = "0",
order_esES = "1",
order_frFR = "0",
order_itIT = "2",
order_jpJA = "0",
order_koKR = "0",
order_ptBR = "0",
order_ruRU = "0",
order_zhCN = "0",
order_zhHK = "0",
},
{
metaname = "Rogue",
order_deDE = "1",
order_esES = "0",
order_frFR = "1",
order_itIT = "1",
order_jpJA = "1",
order_koKR = "1",
order_ptBR = "1",
order_ruRU = "1",
order_zhCN = "1",
order_zhHK = "1",
},
{
metaname = "Ally",
order_deDE = "2",
order_esES = "2",
order_frFR = "2",
order_itIT = "0",
order_jpJA = "2",
order_koKR = "2",
order_ptBR = "2",
order_ruRU = "2",
order_zhCN = "2",
order_zhHK = "2",
},
},
super_types = {
{
metaname = "Legendary",
},
},
token_registrations = {
{
reservation = "1",
type = "TOKEN_ELEMENTAL_2_2_G_389855",
},
},
types = {
{
metaname = "Creature",
},
},
}
-- vi: ft=lua
The outer "costs", "targets" and "derived_infos" seem spurious to me (besides not making sense there, I wouldn't understand what the "£"-enclosed strings refer to). Maybe they are the result of a bug in the converter Stainless used themselves. Anyway, in this table we have (almost) all the possible sub-tables and attributes.
EDIT 3: A heads-up on the conversion task: I finally found a working Lua 5.1 library for C# so I decided that, before trying to make the lol<->xml conversion, I want to be able to "translate" lol files into plain Lua scripts that (hopefully) can produce the exact same result as the compiled ones. Theoretically, I just have to add the module function call at the beginning, add the T's and maybe make the code more human-friendly (Lua supports multiline strings by enclosing them in double square brackets, [[...]] so I should be able to unescape \t and \n inside).
I was also wondering if this new format can open new possibilities. We can mess with the code that loads the whole card now. For example, knowing that the card module becomes a global variable, would it be possible to get the mana cost of a card directly rather than trying to guess it through custom functions? It might be!

EDIT 4: It appears that this library doesn't handle UTF-8 properly.

Back to the drawing board...
EDIT 5: I enhanced the old extraction script, you can download the results from the updated link in
my old post.
EDIT 6: I'm sorry for the delay, but I don't want to make just a converter for nothing. I think it's time to make a new tool, specific for Magic Duels, which will have an xml->lol converter (I probably won't add the backwards conversion, but we'll see) as feature. By the way, I just discovered the incredible "HTML
Agility Pack" library which would make the process of reading from Gatherer much more... "agile".
