Page 1 of 5

DotP Universal Generator

PostPosted: 04 Jul 2014, 09:54
by thefiremind
Thefiremind's DotP Universal Generator


CLARIFICATION FOR NEW USERS: This tool won't give you the full working card, unless you are searching for a "vanilla" card (no abilities). The code that makes the abilities work still needs to be added. That's what modders do... if there were a program that can automatically generate a fully working card, we would all build any deck in the blink of an eye, but that's not possible.


Executable Changelog:
  • Version 1.0.0.0: Initial version.

Plugins Changelog:
  • [DotP2014Output] Version 1.2: It now generates also Chinese text, so it's ready for DotP2015 as well.
  • [GathererInput] Version 1.4: It now handles flavor text from Gatherer again.
  • [GathererInput] Version 1.3, [MagiccardsInput] Version 1.2: Card title uses "graceful quotes", enhanced ability auto-splitting where the site's formatting fails.
  • [GathererInput] Version 1.2: It now understands both "Portuguese (Brazil)" and "Portuguese" in the language pages.
  • [DotP2014Output] Version 1.1: Fixed rarity attribute.
    [GathererInput] Version 1.1: Trimmed white spaces around flavor text.
    [MagiccardsInput] Version 1.1: Removed some debugging leftovers.
  • [All plugins] Version 1.0: Initial version.

What is this all about?
This is mostly a modders' community, so I thought: why not making a moddable card generator? And here it is! It supports plugins written in Python so that it can fetch information from different sites and produce XML files for different DotP versions.


How to install it
Download the ZIP file with the binaries and extract it to a folder of your choice, then download the ZIP file with the IronPython DLLs and extract it to the same folder. It requires .NET Framework 4.5.
In case someone wants to meddle with the source, note that the "python" directory isn't included in the ZIP file with the sources: you'll need to take it from the binaries. Moreover, if you don't install the IronPython extensions for your Visual Studio, you'll also need the 4 additional DLLs from the second ZIP file, which aren't referenced in the project because the IronPython extensions take care of that.


Basic usage
Run the executable and you'll face a window like this:
Image
The input plugin takes care of reading the card information from a site. I included one for Gatherer and one for magiccards.info, use the one you prefer (maybe if a card gets badly formatted text from one you can try with the other one rather than editing the XML file manually). You need to enter the name or the Multiverse ID of a card in the text box. Note that, if you enter a Multiverse ID with the magiccards plugin, it will need to ask Gatherer anyway because you can't search Multiverse IDs outside of Gatherer (this is relevant if Gatherer is down for maintenance).
The output plugin gets the information from the input plugin and generates a string with XML file contents. The program will ask you where to save the file, but that doesn't happen inside the plugin. You need to enter a personal prefix for your card IDs (or just uncheck the option, but I don't recommend it).
The so-called "other" plugin (sorry, couldn't think of a better name :oops:) is a way to allow a certain degree of expandability: it receives both the card information from the input plugin and the XML string from the output plugin, and it generates a string that will be shown in the upper-right box. I included a dummy plugin that just writes the Gatherer link for the card, but in the future I might code a plugin that writes a link to MagicVille in order to search for pictures (the only reason I haven't done this already is because MagicVille doesn't seem to allow exact terms search, which would make things so much easier).
So, once you selected the plugins and entered the required information, click on Run and wait for the program to do its... Magic. :lol: If something wrong happens, you'll probably see a red entry in the log (the lower-right box): if that's the case, answer to this topic and let me know what happened and what the red entry says (I think the errors are generated in the OS's language, so please provide a translation if it's not English or Italian [-o<).


Batch processing
First and foremost, thanks to Xander9009 for giving me the idea of implementing a batch processing mode!
In the Tools menu you can find a "Batch processing" command: it will allow you to let the program work on a list of cards automatically. First, open Notepad and make a list of terms (names or IDs) for the cards you want to generate, one term per line. Save the text file wherever you want. Now click on "Batch processing", select the text file you just saved, and a directory where you want the XML files to be saved. Batch started! Just wait for it to finish. Note that batch processing has some minor limitations due to me not having thought about implementing it from the start: it won't provide any error report, and the "other" plugin won't show anything (but it will be run anyway, so I suggest you to always choose the Gatherer one which does almost nothing, so the batch will take less time). On the bright side, I made it so that the program will spawn a thread for each card (up to a maximum of 8, you can change the value in the Settings.xml file that will be produced after the first run, if you want), so the batch processing will have a nice parallelism.


How to make a new plugin
I may write some more details in the future, but for now, just know that there are 3 mandatory functions to include: Info, Purpose and Get. Look at the existing plugins for examples.


Possible questions
  • Q: Why didn't you use Lua instead of Python? I just learned to code cards, do I have to learn yet another scripting language?
    A: Well, nobody forces you to mod this program... :wink: I chose Python because its extensions for Visual Studio seemed the most robust, and I don't regret the choice, because Python revealed itself very capable at manipulating strings, which is the most important thing here.
  • Q: What is the purpose of the "Test" commands in the Tools menu?
    A: If a plugin includes a Test function, using a Test command will run that function and redirect all the print outputs to the upper-right box (where the "other" plugin usually writes). They are useful if you want to test a plugin alone. If you don't plan to mod this program, you won't need them.
  • Q: Will you make output plugins for DotP2012 and 2013?
    A: Never say never... but I don't plan on making them right now. If someone else wants to make them, I'll be glad to add them. By the way, you can use the DotP2014 plugin for DotP2015 as well, nothing really important concerning my auto-generation has changed.
  • Q: Why isn't the intermediate Card object coded in Python as well?
    A: Because that would defeat the whole purpose of having compatible input and output plugins: if everyone started to make their own Card object, input and output plugins coded by different people might not be compatible.
  • Q: Why don't you generate the XML as a C# XmlDocument?
    A: Because it's easier to auto-generate abilities (where possible) if I make an XML string by stitching pieces together.
  • Q: Why haven't you coded <something> in a better performing way?
    A: I started to code in C# not really long ago, and I can say the same for Python, so if you know a better way to code <something>, please don't hesitate to show me!


Known bugs
  • I wouldn't call this a bug because it depends on the information source, anyway the program can't separate abilities that are written on the same line (it can sometimes, but only under very specific circumstances). And I'm not even talking about comma-separated keywords: separating those is out of question, I thought many times of a way to do that which works for all languages and does it exactly as it's supposed to, but with no result.
  • When making Auras, the "Enchant creature" part could be labeled as ACTIVATED_ABILITY. Since it just needs to be corrected manually, I consider this a very low priority bug and I won't fix it anytime soon. You can use Xander9009's plugin which has it fixed already.

Links
Choose the link you prefer. It appears that Chrome doesn't like Mega, but Firefox downloads it just fine (or you can use JDownloader).
Binaries:
Code: Select all
https://mega.nz/#!rK5k2a5b!BhGcoybK0bh-CSA2WaxyIOtvFEGgcNKcPo6ziCmCn0w
http://www81.zippyshare.com/v/Prz6BMFd/file.html
IronPython DLLs:
Code: Select all
https://mega.nz/#!7PoGXChD!HoeB9rSHCK51vq-ojHO2KPJOVrB8bYU9oj-_ZlRQE5w
http://www81.zippyshare.com/v/8XHtK7jf/file.html
Source:
Code: Select all
https://mega.nz/#!vGoUyYxT!Weju2kE7QSGuWSGQkS44pCvvyMEYD-jFkb_NesIBrCM
http://www44.zippyshare.com/v/TYeJIk66/file.html
I'm sorry for forcing you to download an additional ZIP with the DLLs, but it's easier for me to make updates without having to worry about including them with the binaries.


Other people's plugins
Feel free to post your own plugins by replying to this topic: I'll add a link for each one in this section.

Re: DotP Universal Generator

PostPosted: 04 Jul 2014, 12:57
by sumomole
flavour text is missing or incorrect, thefiremind's DotP2014 generator doesn't have this problem.
Akroan Mastiff | Open
Code: Select all
<?xml version="1.0"?>
<CARD_V2 ExportVersion="1">
  <FILENAME text="AKROAN_MASTIFF_100380370" />
  <CARDNAME text="AKROAN_MASTIFF" />
  <TITLE>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Akroan Mastiff]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Dogue akroen]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Mastín akroniense]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Akroischer Mastiff]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Mastino di Akros]]></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[Mastim Acrosano]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[阿喀洛斯獒犬]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[阿喀洛斯獒犬]]></LOCALISED_TEXT>
  </TITLE>
  <MULTIVERSEID value="100380370" />
  <ARTID value="100380370" />
  <ARTIST name="Zoltan Boros" />
  <CASTING_COST cost="{3}{W}" />
  <TYPE metaname="Creature" />
  <SUB_TYPE metaname="Hound" />
  <EXPANSION value="JOU" />
  <RARITY value="C" />
  <POWER value="2" />
  <TOUGHNESS value="2" />
  <ACTIVATED_ABILITY>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[{W}, {T}: Tap target creature.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[{W}, {T} : Engagez la créature ciblée.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[{W}, {T}: Gira la criatura objetivo.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[{W}, {T}: Tappe eine Kreatur deiner Wahl.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[{W}, {T}: TAPpa una creatura bersaglio.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[{W}, {T}:クリーチャー1体を対象とし、それをタップする。]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[{W}, {T}: 생물을 목표로 정한다. 그 생물을 탭한다.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[{W}, {T}: поверните целевое существо.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[{W}, {T}: Vire a criatura alvo.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[{W},{T}:横置目标生物。]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[{W},{T}:橫置目標生物。]]></LOCALISED_TEXT>
    <COST mana_cost="{W}" type="Mana" />
    <COST type="TapSelf" />
  </ACTIVATED_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>
Deathless Angel | Open
Code: Select all
<?xml version="1.0"?>
<CARD_V2 ExportVersion="1">
  <FILENAME text="DEATHLESS_ANGEL_100193629" />
  <CARDNAME text="DEATHLESS_ANGEL" />
  <TITLE>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Deathless Angel]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Ange faucheur de mort]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Ángel inmortal]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Unsterblicher Engel]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Angelo Immortale]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[不死の天使]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Deathless Angel]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Бессмертный Ангел]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Anjo Imortal]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[不亡天使]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[Deathless Angel]]></LOCALISED_TEXT>
  </TITLE>
  <MULTIVERSEID value="100193629" />
  <ARTID value="100193629" />
  <ARTIST name="Johann Bodin" />
  <CASTING_COST cost="{4}{W}{W}" />
  <FLAVOURTEXT>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[—The War Diaries
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[—Les journaux de la Guerre
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[—Los diarios de guerra
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[—Die Kriegstagebücher
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[—I Diari di Guerra
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[――「戦争日誌」
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[—The War Diaries
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[— Дневники войны
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[— Os Diários da Guerra
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[~《战场札记》
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[—The War Diaries
]]></LOCALISED_TEXT>
  </FLAVOURTEXT>
  <TYPE metaname="Creature" />
  <SUB_TYPE metaname="Angel" />
  <EXPANSION value="ROE" />
  <RARITY value="R" />
  <POWER value="5" />
  <TOUGHNESS value="7" />
  <STATIC_ABILITY>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Flying]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Vol]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Vuela.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Fliegend]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Volare]]></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[Voar]]></LOCALISED_TEXT>
    <INTRINSIC characteristic="CHARACTERISTIC_FLYING" />
  </STATIC_ABILITY>
  <ACTIVATED_ABILITY>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[{W}{W}: Target creature gains indestructible until end of turn.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[{W}{W} : La créature ciblée est indestructible ce tour-ci.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[{W}{W}: La criatura objetivo es indestructible este turno.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[{W}{W}: Eine Kreatur deiner Wahl ist in diesem Zug unzerstörbar.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[{W}{W}: Una creatura bersaglio è indistruttibile in questo turno.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[{W}{W}:クリーチャー1体を対象とする。このターン、それは破壊されない。]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[{W}{W}: Target creature gains indestructible until end of turn.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[{W}{W}: целевое существо не может быть уничтожено в этом ходу.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[{W}{W}: A criatura alvo é indestrutível nesse turno.]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[{W}{W}:目标生物本回合中不会毁坏。]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[{W}{W}: Target creature gains indestructible until end of turn.]]></LOCALISED_TEXT>
    <COST mana_cost="{W}{W}" type="Mana" />
  </ACTIVATED_ABILITY>
  <HELP title="MORE_INFO_BADGE_TITLE_10" body="MORE_INFO_BADGE_BODY_10" zone="ZONE_ANY" />
  <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>
EDIT: magiccardsinput will cause the software to crash.

Re: DotP Universal Generator

PostPosted: 04 Jul 2014, 13:50
by thefiremind
sumomole wrote:flavour text is missing or incorrect, thefiremind's DotP2014 generator doesn't have this problem.

EDIT: magiccardsinput will cause the software to crash.
Thanks for the input, some problems had slipped from my sight, but they were all in the plugins, so the executable hasn't changed. Actually, I haven't even updated the version number in the plugins, let's just pretend they were like this from the start. :lol:

Re: DotP Universal Generator

PostPosted: 04 Jul 2014, 19:54
by Xander9009
For a source of the MultiverseIDs outside of Gatherer, you could look into either mtgjson.com or api.mtgdb.info. The first one would probably be a bit more difficult, since you can only get a list of ALL cards in either a set or every set at once (and they're still separated by set within that json file). The second, however, returns a json of just that card and inherently supports searching by name. For the latter, this alone will set ID to 213806 if Name is set to Crush. It requires json and urllib2 to be be imported.
Code: Select all
ID =  json.loads( urllib2.urlopen('http://api.mtgdb.info/cards/'+Name).read())[0]['id']
Just if you wanted to put in a backup for when Gatherer is down. You can actually change ['id'] to another field like name or text (or remove it for the entire card in json format, but be careful with dynamic P/T like Rubblehulk). Only works with English names, though.

Anyway, this is nice. I imagine this will save me quite a bit of time. Thanks for the batch mode :) I tend to make cards for an entire deck at once, and this will make that process just that much less of a hassle :)

Re: DotP Universal Generator

PostPosted: 09 Jul 2014, 23:41
by Xander9009
Hey, FireMind, I think I found a small bug. I was making Gemstone Array when I noticed it, for the record. The Rarity is Using value instead of metaname. This prevent's Riiak's deck builder from filtering the cards because it can't parse the code blocks.
| Open
Code: Select all
<RARITY value="U" />
Should be
Code: Select all
<RARITY metaname="U" />
EDIT: I'm impatient, so for others, until TFM gets around to fixing it himself, just open up the python subfolder, open DotP2014Output.py with Notepad++ (or other text editor), find "rarity", and on the line
Code: Select all
sXml += SimpleNode('RARITY', 'value', sRarity)
change 'value' to 'metaname'.

Also, Gemstone Array is putting the flavortext on two lines. I'm not sure why. By that, I mean the flavortext looks like this:
| Open
Code: Select all
  <FLAVOURTEXT>
    <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Outside, it reflects the suns’ light. Inside, it harvests the suns’ power.
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Dehors, il reflète la lumière des soleils. Dedans, il absorbe leur puissance.
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Por fuera, refleja la luz de los soles. Por dentro, cosecha su poder.
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Nach außen reflektiert sie das Licht der Sonnen. Doch im Innern erntet sie deren Macht.
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[All’esterno riflette la luce dei soli. All’interno ne immagazzina il potere.
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[外側では太陽の光を反射し、内側では太陽の力を集める。
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Outside, it reflects the suns’ light. Inside, it harvests the suns’ power.
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Outside, it reflects the suns’ light. Inside, it harvests the suns’ power.
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Por fora, reflete a luz do sol. Por dentro, colhe o poder do sol.
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[外部映射太阳明光,内部储藏诸日能量。
]]></LOCALISED_TEXT>
    <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[Outside, it reflects the suns’ light. Inside, it harvests the suns’ power.
]]></LOCALISED_TEXT>
  </FLAVOURTEXT>
It didn't happen with Rubblehulk or Staff of Domination, but it did with Akroma, Angel of Wrath. So, it's not a constant bug, and unlike the value/metaname bug, it doesn't have any adverse effects, but I figured I'd point it out. I'm an idiot. Those two don't have flavortext. I just glanced at the cards and didn't see any ]]></LO... lines, so I assumed they'd worked correctly. They did work correctly, but only because they didn't have flavortext.
EDIT2: Fixed | Open
In the GathererInput.py, changing
Code: Select all
sFlavor += (StringUtils.StripTags(moMatch.group(1)) + '\n')
to
Code: Select all
sFlavor += (StringUtils.StripTags(moMatch.group(1)))
fixed the issue. I don't know if this will cause problems elsewhere.
No longer relevant. I was just asking questions about expanding the ability handling, but I figured out the answers. | Open
Finally, completely unrelated to the previous, I'm looking to expand some of the ability handling. I have two questions, though. The first is a general python question, you use
Code: Select all
for sPattern, sTemplate in dicSimpleTemplates.iteritems():
How does this work? Specifically, I mean how does work having two elements? "sPattern, sTemplate" If I had to guess, I'd say iteritems returns two values, and they're written to these two respectively, but I wasn't aware a function could return multiple values, so I'm not sure that's it. Am I way off?
Nevermind. I figured this out.

The other one was a bit more specific. how does the function GetAbilitiesCount() work? Does it basically check to see how many separate lines there are in the ability text so that you can add any abilities that appear alone on a line? My hope is that I can make cards like Abyssal Persecutor work. Basically, I'm planning to check each line of ability text, but then instead of trying to match only the entire line, I'm going to check it as a comma delimited string. If everything in that string is a recognized ability, then we can be sure the ability is auto-code-able. Otherwise, just drop in the ability text like normal. But this way, creatures with multiple simple abilities on one line will also be automatically completed. But before I get into that, I need to make sure this function is going to work the way I'm expecting. Nevermind, I found the answer to this in GathererInput. It works the way I expected.
EDIT2: Alright, I managed to get it working. To be 100% clear, I mean the plugin will correctly auto-code Assault Zeppelid even though it has multiple abilities on the same line. It will auto-code the first line of Abyssal Persecutor's abilities and then fill in the placeholder-text for his win-loss related ability. I tested it with "Akroma, Angel of Wrath", too. Without the "protection from black and from red" being defined, it left the ability as a general ability placeholder text (like it should have, because it didn't know what everything was). Once I defined that ability, it auto-coded the entire card. The only problem it has is that it doesn't leave them on the same line. Instead, each ability is given its own line. While it would probably be possible to keep them on the same line (and preferable, I know), it would mean a LOT more work I imagine. At least this way, cards with multiple abilities can be auto-coded. If I'm feeling ambitious, I might go back and try to make it combine everything into a single line and make them commaspace'ed. For now, I'm just happy it's working.

As a note directly to you, TFM, I only changed the ProcessAbilities() function*. I just stuck everything right after the first attempt to match it. If that fails, it'll see if the number of matches it finds when comma-delimited are the same number as the number of elements you get from treating it as comma-delimited. If it's the same, it assumes the next section will work and matches them all. I can't think of any situation where this would return a false positive, but if you can think of one, you'll have to let me know this won't work.

Question, is there a reason the "protection from [color]", "can't be countered" and similar abilities haven't been added? For the "can't be countered", I imagine it's related to the fact that it has the card's name in there, and that doesn't really work very well with the way it's currently searching for the abilities. However, I was thinking that for things like that, I could just replace the card's name with "[CARDNAME]" or something, and then search like normal. At the end, reverse that process. Also, do you care if I upload my modified version of your plugin? If not, then I'm going to look into making a MUCH more complex version. Though it's so unlikely to pan out that I'm not even going to explain it lol.

Re: DotP Universal Generator

PostPosted: 10 Jul 2014, 09:06
by thefiremind
Rarity and flavor problems solved.

Xander9009 wrote:you use
Code: Select all
for sPattern, sTemplate in dicSimpleTemplates.iteritems():
How does this work? Specifically, I mean how does work having two elements? "sPattern, sTemplate" If I had to guess, I'd say iteritems returns two values, and they're written to these two respectively, but I wasn't aware a function could return multiple values, so I'm not sure that's it.
In Python, a function can return multiple values and you can access them as they were an array (see how I return both the ability code and the HELP node in the same function). But in this case, what you have is a sort of map, or dictionary, or however you want to call a set of key-value couples, and the "for" iterates on both keys and values so that you can use both inside the loop.

Xander9009 wrote:how does the function GetAbilitiesCount() work?
That's a function from my C# Card object. Before going into that, let me explain how I store abilities in it. What we get from websites is always in the form of
  • Language 1:
    • Ability 1
    • Ability 2
  • Language 2:
    • Ability 1
    • Ability 2
but in our XML file we want
  • Ability 1:
    • Language 1
    • Language 2
  • Ability 2:
    • Language 1
    • Language 2
so I already store ability text using the latter format. GetAbilitiesCount() just returns the size of the list containing all the abilities.

Re: DotP Universal Generator

PostPosted: 10 Jul 2014, 09:28
by Xander9009
thefiremind wrote:see how I return both the ability code and the HELP node in the same function
Yeah, I actually managed to figure this one out specifically because of the exact thing you mentioned.

thefiremind wrote:That's a function from my C# Card object. Before going into that, let me explain how I store abilities in it. What we get from websites is always in the form of
[...]
so I already store ability text using the latter format. GetAbilitiesCount() just returns the size of the list containing all the abilities.
I see. When I was working on a generator, I never got around to working with other languages so I never thought about that. I did however figure out it was working the way I'd hoped. I tried it anyway and it worked, so I figured I was right, but it's good to have confirmation.

I should mention, I extensively edited my previous post (I didn't want to post multiple times without any responses, and I didn't notice your post, so I just edited that one). Basically, I changed it to reflect that I'd figured those two things out, but also I also I wanted to know if you'll mind if I upload a modified version of your DotP2014Output file. I added the ability to parse comma-delimited abilities.

EDIT: Oh, hey. Completely off-topic: did you once mention having problems with cards with both colored and colorless alternative costs that remove a card from your hand? Resounding Thunder is in 2015 apparently.

Re: DotP Universal Generator

PostPosted: 10 Jul 2014, 10:11
by thefiremind
Xander9009 wrote:I also I wanted to know if you'll mind if I upload a modified version of your DotP2014Output file. I added the ability to parse comma-delimited abilities.
That's great, please post it! :D

Xander9009 wrote:EDIT: Oh, hey. Completely off-topic: did you once mention having problems with cards with both colored and colorless alternative costs that remove a card from your hand? Resounding Thunder is in 2015 apparently.
The problem was with abilities that activate from hand, but don't remove the card from hand (like Forecast).

Re: DotP Universal Generator

PostPosted: 10 Jul 2014, 11:42
by Xander9009
Oh, ok. I remembered it backwards, apparently. Then I guess we'll have to wait and see if that appears somewhere.

Here's the file which will parse comma-delimited abilities. Like I mentioned before, they will NOT be on the same line like they're supposed to be.

Before I expand it more (like adding "protection from [color]") abilities, are there any abilities that you avoided adding because they would cause problems?

DotP2014OutputX99 Old Updates | Open
EDIT: V1.1 Abilities that appear on the same line but which could otherwise be fully coded are now properly coded. Each has its own line, however.

Edit: V1.2 Will now apply all protection abilities (thank you RiiakShiNal for providing the necessary code for all of these). Will also commaspace the abilities so they are on the same line like they should be, and will make them lowercase where necessary. If this messes up, please let me know.

Edit: V1.3 Corrected Swampwalk being given to creatures with Mountainwalk.

Edit: V1.4 Added counter related abilities such as Carnifex Demon.

Edit: V1.4CW - I made my V1.4 file work for the CW. It'll include the CW prefix where it should be, and it will include your username in the AUTHOR and EDITOR tags. It will also use the current date as it should appear. Please note that if you want to use this, you need to open the file in Notepad or Notepad++ and modify the UserName variable near the top with yours. I made this without remembering that sweetLu made something similar. Still, this one will include the expanded functionality of my 1.4 modified output.

EDIT: V1.5 Please see this post. Please note that the non-CW version does not handle tokens. Because tokens are only named in a standard way in the CW and NOT in the base game, it cannot do anything with them.

In addition to the above, both plugins can now add the AUTHOR, EDITORS, and DATE tags. They do handle it slightly differently, though. The Modified plugin is not meant for use with the CW, so if the UserName is left blank (default), then it does not add the tags. The CW plugin, however, is (obviously) meant for use with the CW, which requires these tags. So, if the UserName is left blank (also default), then it will default to "thefiremind, Xander9009", which shows that it has been automatically created by this tool with my modified plugin (just like I did when I made the 400+ cards a few months ago).

EDIT: V1.6 Removed the need for two separate versions. Now, there are two variables to set. If you want it to behave like the original version, just set CommunityWad near the top to "False" without the quotes (but make sure it's capitalized). Fixed a few bugs from 1.5, overhauled how many abilities are handled to be more in line with TFM's methods which were much better, added a few more ability templates, changed how mana abilities are handled, and maybe a couple other minor things I've forgotten. This is likely to be the last update in awhile barring bug fixes. I probably won't update it again until there are new keywords to add.

EDIT: V1.7 Changed token creation function to use CW_Tokens() instead of the vanilla MTG():PutTokensOntoBattlefield(). Please make sure you register the tokens. It'll only register the first one. For now, it's up to you to register any others that might exist as alternate art for that token.

Added Devoid, Ingest, Ally abilities akin to Chasm Guide, and a partially working Awaken base code.

Also, fixed MM abilities to properly set the filename attribute with "_MM_"

EDIT: V1.8 Added Awaken, Cohort, Devoid, Ingest, Rally, Surge, and Support, and support for Eldrazi Scion tokens.

Changed CW cards' ARTID to match CARDNAME like other CW cards.

EDIT: V1.9 Added: Investigate, Skulk, "Tap target (permanent, artifact, creature, enchantment, land)", "This creature gets +-X/+-X until end of turn."

Fixed: "Target creature gets +-X/+-X until end end of turn." "Target creature gets +-X/+-X and gains ... until end of turn." "Add one mana of any color to your mana pool."

EDIT: V1.10 Replaced variables directly named after functions to not have the same name.
Fixed triggered ability guessing, which I'd apparently messed up at some point.
Fixed token creation. Namely, fixed first strike (was converting to "FS" instead of "F"), double strike ("DS" -> "D"), and blue ("B" -> "U") tokens. Also added Fabricate, Crew, and "Whenever NAME crews a vehicle," trigger.

EDIT: V1.11 Changed Crew to use functions instead of extremely long code.
Added support for "Create" keyword based token creation.

Edit: v1.12 Added Embalm, Eternalize, and Afflict. Also corrected an issue where needing to register multiple token types would only register the first.


Edit: 1.13 Added loyalty support, including initial value and cost. Also removed MID from FILENAME.
DotP2014OutputX99 1.13.1 Added trigger fire code and characteristic code to embalm and eternalize.

----

New file: LocalInputX99 1.0 Explained here.

LocalInputX99 Old Updates | Open
LocalInputX99 - V1.1 Fixed loyalty ability being added when loyalty is blank. Allowed reminder text to be removed when trailing italicizing pipe is missing. Added check to reduce double spaces to single spaces.


LocalInputX99 - V1.2 Fixed issue with typeline not properly registering "-" the same as "—". Fixed spaces on the end of names not being removed.

LocalInputX99 - V1.2.1 Added MID support.

Old versions.

Re: DotP Universal Generator

PostPosted: 10 Jul 2014, 12:15
by thefiremind
Xander9009 wrote:Here's the file which will parse comma-delimited abilities. Like I mentioned before, they will NOT be on the same line like they're supposed to be.
Could you briefly explain how it works? I saw some "split(',')" but I'd like to understand how you avoid splitting all abilities that have commas in them (such as "At the beginning of your upkeep, if...").
Anyway, my "dream" would have been to make it produce abilities exactly as they should be (adding commaspace="1" when needed, and making the first letter lowercase in the languages where it should be lowercase after the comma). You know, I'm the kind of person that "does it well, or doesn't do it"... but it's nice that you keep enhancing your own branch: I'll keep a link on the first post that addresses people to your latest version.

Xander9009 wrote:Before I expand it more (like adding "protection from [color]") abilities, are there any abilities that you avoided adding because they would cause problems?
I just inserted the easiest abilities, without thinking about possible problems. Even the ones I already inserted could cause problems I don't know about yet, so feel free to experiment. :)

Re: DotP Universal Generator

PostPosted: 10 Jul 2014, 15:21
by Xander9009
thefiremind wrote:Could you briefly explain how it works? I saw some "split(',')" but I'd like to understand how you avoid splitting all abilities that have commas in them (such as "At the beginning of your upkeep, if...").
Anyway, my "dream" would have been to make it produce abilities exactly as they should be (adding commaspace="1" when needed, and making the first letter lowercase in the languages where it should be lowercase after the comma). You know, I'm the kind of person that "does it well, or doesn't do it"... but it's nice that you keep enhancing your own branch: I'll keep a link on the first post that addresses people to your latest version.
Actually, it does split all abilities, even the ones like "At the beginning of your upkeep,...". However, it'll split "At the the beginning of your upkeep, draw a card." into the two elements "At the beginning of your upkeep" and "draw a card." There are two elements. It then tries to match those with the ability list you already have in place, and counts how many matches it finds. It won't find either one. If the number of elements equals the number of matches, it'll produce the abilities. If the numbers are different (like in this case), it'll continue on as if nothing happened and the rest of your script does its magic. But even something like Angelic Skirmisher's "At the beginning of each combat, choose first strike, vigilance, or lifelink." would split up into "At the beginning of each combat", "choose first strike", "vigilance", "or lifelink." It'll match one, but there are four elements, so it treats the entire ability as unknown (as it should) and never even bothers with the coding. I just realized it could be made more efficient by breaking off early if it finds one that doesn't match. Once it finds one, there's no need to check the others.

And yeah, I wish it managed the commaspace thing, too. I wasn't actually bothered by the capitalization but it should be doable. Basically, if it find's that this works (if it codes all of the abilities), then go through the resulting string and strip out of the localized text, and then add in the localized text directly from the card using the code you already have in place for the that. I just wish I was more familiar with python. I'm not sure how exactly to do that. Oh well, I've been meaning to learn something about python for quite awhile. I started a week or so ago with another utility (loose file syncing for the community wad). Ended up not using the tool written in python, but it all worked, so at least I have some experience with it. Anyway, back on topic...

thefiremind wrote:I just inserted the easiest abilities, without thinking about possible problems. Even the ones I already inserted could cause problems I don't know about yet, so feel free to experiment. :)
Alright. Then, I'll go ahead and add in a few others. I'm planning to do all of the normal things first, Protection from [color], modular N, Graft N, and the like. That'll all have to come later, though. I'm off to bed.

Re: DotP Universal Generator

PostPosted: 10 Jul 2014, 18:40
by RiiakShiNal
I actually went through all of the simple protection abilities I could find on gatherer and made templates for a card building tool I use (not very user friendly yet hence why I never released it). This was a while back so there could be one or more new protection abilities that I've missed, but here are my templates (feel free to use/modify them if you want). Also note that I don't have full localized text for all of them (those I don't have it all for have {$LocalisedText$} in the template which for my tool means use whatever localized text you can find for that card).

Protection templates | Open
Code: Select all
<Ability Name="Protection from all colors">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from all colors]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre toutes les couleurs]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra todos los colores.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor allen Farben]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione da tutti i colori]]></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[Proteção contra todas as cores]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLACK )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLUE )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_GREEN )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_RED )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_WHITE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from artifacts">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from artifacts]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre les artefacts]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra artefactos.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Artefakten]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dagli artefatti]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[プロテクション(アーティファクト)]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Protection from artifacts]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Защита от артефактов]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Proteção contra artefatos]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_TYPE, OP_IS, CARD_TYPE_ARTIFACT )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from Beasts">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from Beasts]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre les bêtes]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra Bestias.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Bestien]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dalle Bestie]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[Protection from Beasts]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Protection from Beasts]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Protection from Beasts]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Proteção contra Bestas]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_BEAST )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from black">
   <HELP title="MORE_INFO_PROTECTION_BLACK_TITLE" body="MORE_INFO_PROTECTION_BLACK_BODY" zone="ZONE_BATTLEFIELD" zone_reverse="1" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from black]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le noir]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra negro.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Schwarz]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal nero]]></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[Proteção contra o preto]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[反黑保护]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[反黑保護]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_COLOUR, OP_IS, COLOUR_BLACK )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from black and from green">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from black and from green]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le noir, protection contre le vert]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra negro y contra verde.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Schwarz und vor Grün]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal nero, protezione dal verde]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[プロテクション(黒)、プロテクション(緑)]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[흑색으로부터 보호, protection from green]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Защита от черного, Защита от зеленого]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Proteção contra o preto, proteção contra o verde]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLACK )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_GREEN )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from black and from red">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from black and from red]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le noir, protection contre le rouge]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra negro y contra rojo.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Schwarz und vor Rot]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal nero, protezione dal rosso]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[プロテクション(黒)、プロテクション(赤)]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[흑색으로부터 보호, protection from red]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Защита от черного, Защита от красного]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Proteção contra o preto, proteção contra o vermelho]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLACK )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_RED )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from blue">
   <HELP title="MORE_INFO_PROTECTION_BLUE_TITLE" body="MORE_INFO_PROTECTION_BLUE_BODY" zone="ZONE_BATTLEFIELD" zone_reverse="1" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from blue]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le bleu]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra azul]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Blau]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal blu]]></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[Proteção contra o azul]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[反蓝保护]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[反藍保護]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_COLOUR, OP_IS, COLOUR_BLUE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from blue and from black">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from blue and from black]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le bleu, protection contre le noir]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra azul y contra negro.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Blau und vor Schwarz]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal blu, protezione dal nero]]></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[Proteção contra o azul, proteção contra o preto]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLACK )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLUE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from blue and from red">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLUE )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_RED )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from blue, from black, and from red">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from blue, from black, and from red]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le bleu, contre le noir et contre le rouge]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra azul, contra negro y contra rojo.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Blau, vor Schwarz und vor Rot]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal blu, dal nero e dal rosso.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[プロテクション(青)、プロテクション(黒)、プロテクション(赤)]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Protection from blue, from black, and from red]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Защита от синего, от черного и от красного]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Proteção contra o azul, o preto e o vermelho.]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLACK )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLUE )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_RED )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from clerics">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_CLERIC )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from converted mana cost 3 or greater">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_CMC, OP_GREATER_THAN_OR_EQUAL_TO, 3 )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from creatures">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from demons and from dragons">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[protection from Demons and from Dragons]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[protection contre les démons et protection contre les dragons]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[protección contra Demonios y contra Dragones.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Dämonen und vor Drachen]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[protezione da Demoni e da Draghi]]></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[proteção contra Demônios e contra Dragões]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[反恶魔保护,反龙保护]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[反惡魔保護,反龍保護]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_DEMON )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_DRAGON )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from dragons">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_DRAGON )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from Elves">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_ELF )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from enchantments">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_TYPE, OP_IS, CARD_TYPE_ENCHANTMENT )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from Goblins">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_GOBLIN )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from green">
   <HELP title="MORE_INFO_PROTECTION_GREEN_TITLE" body="MORE_INFO_PROTECTION_GREEN_BODY" zone="ZONE_BATTLEFIELD" zone_reverse="1" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from green]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le vert]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra verde.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Grün]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal verde]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[プロテクション(緑)]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Protection from green]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Защита от зеленого]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Proteção contra o verde]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[反绿保护]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[反綠保護]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_COLOUR, OP_IS, COLOUR_GREEN )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from instants">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from instants]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre les éphémères]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra instantáneos.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Spontanzaubern]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dagli istantanei]]></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[Proteção contra mágicas instantâneas]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_TYPE, OP_IS, CARD_TYPE_INSTANT )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from Kavu">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_KAVU )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from lands">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_TYPE, OP_IS, CARD_TYPE_LAND )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from legendary creatures">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_And()
            oSubFilter:Add( FE_SUPERTYPE, OP_IS, SUPERTYPE_LEGENDARY )
            oSubFilter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from non-Spirit creatures">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_And()
            oSubFilter:Add( FE_SUBTYPE, OP_NOT, CREATURE_TYPE_SPIRIT )
            oSubFilter:Add( FE_TYPE, OP_IS, CARD_TYPE_CREATURE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from red">
   <HELP title="MORE_INFO_PROTECTION_RED_TITLE" body="MORE_INFO_PROTECTION_RED_BODY" zone="ZONE_BATTLEFIELD" zone_reverse="1" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from red]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le rouge]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra rojo.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Rot]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal rosso]]></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[Proteção contra o vermelho]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[反红保护]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[反紅保護]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_COLOUR, OP_IS, COLOUR_RED )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from red and from green">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      {$LocalisedText$}
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_GREEN )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_RED )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from red and from white">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[protection from red and from white]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[protection contre le rouge et protection contre le blanc]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[protección contra rojo y contra blanco.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Rot und vor Weiß]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[protezione dal rosso e dal bianco]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[プロテクション(赤)]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[protection from red and from white]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Защита от красного и от белого]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[proteção contra o vermelho e contra o branco]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_RED )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_WHITE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from snow">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from snow]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le neigeux]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra nevado.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Verschneitem]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dalla neve]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="jp-JA"><![CDATA[プロテクション(氷雪)]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ko-KR"><![CDATA[Protection from snow]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="ru-RU"><![CDATA[Защита от снега]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="pt-BR"><![CDATA[Proteção contra neve]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_SUPERTYPE, OP_IS, SUPERTYPE_SNOW )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from Vampires">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from Vampires]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre les vampires]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra vampiros.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Vampiren]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dai Vampiri]]></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[Proteção contra Vampiros]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[反吸血鬼保护]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[反吸血鬼保護]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_VAMPIRE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from Vampires, from Werewolves, and from Zombies">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from Vampires, from Werewolves, and from Zombies]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre les vampires, contre les loups-garous et contre les zombies]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra Vampiros, Licántropos y Zombies.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Vampiren, Werwölfen und Zombies]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dai Vampiri, dai Mannari e dagli Zombie]]></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[Proteção contra Vampiros, Lobisomens e Zumbis.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[反吸血鬼保护, 反狼人保护, 反灵俑保护]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[反吸血鬼保護, 反狼人保護, 反殭屍保護]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_VAMPIRE )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_WEREWOLF )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_ZOMBIE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from white">
   <HELP title="MORE_INFO_PROTECTION_WHITE_TITLE" body="MORE_INFO_PROTECTION_WHITE_BODY" zone="ZONE_BATTLEFIELD" zone_reverse="1" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from white]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le blanc]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra blanco.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Weiß]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal bianco]]></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[Proteção contra o branco]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[反白保护]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[反白保護]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_COLOUR, OP_IS, COLOUR_WHITE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from white and from black">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from white and from black]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le blanc, protection contre le noir]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra blanco y contra negro.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Weiß und vor Schwarz]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal bianco, protezione dal nero]]></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[Proteção contra o branco, Proteção contra o preto]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLACK )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_WHITE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from white and from blue">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from white and from blue]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre le blanc, protection contre le bleu]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra blanco y contra azul.]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Weiß und vor Blau]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dal bianco, protezione dal blu]]></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[Proteção contra o branco, Proteção contra o azul]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            local oSubFilter = oFilter:AddSubFilter_Or()
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_BLUE )
            oSubFilter:Add( FE_SUBTYPE, OP_IS, COLOUR_WHITE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>
<Ability Name="Protection from Zombies">
   <HELP title="MORE_INFO_TITLE_PROTECTION" body="MORE_INFO_BODY_PROTECTION" zone="ZONE_ANY" />
   <STATIC_ABILITY commaspace="{$CommaSpace$}">
      <LOCALISED_TEXT LanguageCode="en-US"><![CDATA[Protection from Zombies]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="fr-FR"><![CDATA[Protection contre les zombies]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="es-ES"><![CDATA[Protección contra Zombies]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="de-DE"><![CDATA[Schutz vor Zombies]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="it-IT"><![CDATA[Protezione dagli Zombie]]></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[Proteção contra Zumbis]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-CN"><![CDATA[反灵俑保护]]></LOCALISED_TEXT>
      <LOCALISED_TEXT LanguageCode="zh-HK"><![CDATA[反殭屍保護]]></LOCALISED_TEXT>
      <CONTINUOUS_ACTION layer="0">
         if (EffectSource() ~= nil) then
            local oFilter = ClearFilter()
            oFilter:Add( FE_SUBTYPE, OP_IS, CREATURE_TYPE_ZOMBIE )
            EffectSource():Protection()
         end
      </CONTINUOUS_ACTION>
   </STATIC_ABILITY>
</Ability>

Re: DotP Universal Generator

PostPosted: 13 Jul 2014, 02:21
by Xander9009
Thanks Riiak. I've put in all of those protection abilities and filled in what localized text I could. You definitely saved me a LOT of time.

TFM, I ended up not removing all localized text and replacing it with the card's localized text because it seems more likely that the specific abilities will have more languages available. If a card has the ability, then all the languages available from translations from that card should be available, thus making more languages of the card available as a whole in DotP.

Instead, when it adds the second and subsequent abilities, it replaces <STATIC_ABILITY> with <STATIC_ABILITY commaspace="1">, and then it calls
Code: Select all
for sLetter, sReplacement in dicCapitalization.iteritems():
   for iIndexRef, sLanguageShort in enumerate(lstLanguageShort):
      sTemplate = sTemplate.replace(sLanguageShort + '"><![CDATA[' + sLetter, sLanguageShort + r""""><![CDATA[""" + sReplacement)

sLanguageShort contains English, Spanish, Portuguese, Italian, and French. dicCapitalization contains the capital letters and their corresponding lowercase versions. The final result is that they are properly commaspaced and are properly capitalized. Unfortunately, I don't know enough about the other languages to know if this will always work. I know it will for English (unless I'm forgetting an always capitalized ability). I know it should work for German (because German capitalizes all nouns, and the abilities are treated as nouns), but I don't know about the others. I don't feel like this is a really good solution, but it should mostly do the trick, if not always.

Anyway, I'll link to the new version in my last post.

Re: DotP Universal Generator

PostPosted: 24 Sep 2014, 22:28
by Xander9009
Hey FireMind, not sure what's going on, but Pact of the Titan gets quite messed up. Only two abilities are created, but it still tries to fill in all three abilities in the localized text. It might just be me (heck, it could even be my modifications), but it's worth checking.

Re: DotP Universal Generator

PostPosted: 24 Sep 2014, 22:45
by thefiremind
Xander9009 wrote:Hey FireMind, not sure what's going on, but Pact of the Titan gets quite messed up. Only two abilities are created, but it still tries to fill in all three abilities in the localized text. It might just be me (heck, it could even be my modifications), but it's worth checking.
All cards whose color(s) can't be deduced by the mana cost received an errata so that they don't have the "<cardname> is <color>" ability on their text anymore. The problem is that non-English languages don't receive errata on Gatherer, so the cards affected by the change have 1 more ability on top of the other ones in all languages but English. I couldn't think of a good solution, and the affected cards aren't that many, so I just ignored the problem.