Files
magic-set-editor-fork/data/magic-cockatrice-v2.mse-export-template/export-template
cajun 9a7b7949e8 [wip] updating exporters for 2.5 (#75)
* Add Card Regions to DFCs
* Add Hashes
* Add crop_multi_image to help crop with card regions
* bugfix exporters and organize the list
* add dfc splitter support for Cockatrice and Lackey exporters
* fix sizing bugs on Planesculptors exporter
* update icons on exporters missing them
* update namecheck exporter and improve near checking

---------

Co-authored-by: cajun <12363371+CajunAvenger@users.noreply.github.com>
2024-09-24 09:52:17 -05:00

953 lines
42 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
mse version: 2.5.0
short name: Cockatrice
full name: Exporter v2.0
position hint: 100
icon: icon.png
version: 2024-09-23
installer group: magic/Export/cockatrice
depends on:
package: magic.mse-game
version: 2009-07-23
game: magic
create directory: true
file type: *.xml|*.xml|*.*|*.*
# By K'yoril, edited by Advent, Updated by Reuben Covington, Updated by Cajun, Updated by Zeu
# Updated to v4 xml by ebbit
# Based on code by Pichoro, Idle Muse, Innuendo and Seeonee
option field:
type: choice
name: info
choice: Updated 2023/02, guide: https://tinyurl.com/ctexportv2
option field:
type: text
name: cockatrice Set Type
description: The "set type" your set will appear as in Cockatrice. "Custom" should be the default.
default: Custom
option field:
type: choice
name: export Images
description: Export images along with the XML? Recommended for Cockatrice use. JPG is lower quality but lower file size.
choice: no
choice: JPG
choice: PNG
initial: no
option field:
type: boolean
name: tokens In Separate XML
description: Tokens are exported to a Separate file called "[Set Code] Tokens.xml"
initial: no
option field:
type: boolean
name: append Set Code To Tokens
description: Adds the set code to token names to differentiate them from tokens with the same name from other sets.
initial: no
option field:
type: text
name: append String To Names
description: Appended to the front of all card names and image names.
option field:
type: multiple choice
name: rarities to export
choice: common
choice: uncommon
choice: rare
choice: mythic rare
choice: basic land
choice: special
choice: token
choice: masterpiece
initial: common, uncommon, rare, mythic rare, basic land, special, token, masterpiece
option style:
rarities to export:
render style: checklist
direction: vertical
export Images:
render style: both
choice images:
no: {built_in_image("bool_no")}
JPG: {built_in_image("bool_yes")}
PNG: {built_in_image("bool_yes")}
script:
splitter_name := {false} ## experimental future thing for splitting dfc images
#determine if the card is a type that is a "token" i.e. it should be batched with tokens instead of with other cards
is_token := {contains(card.shape, match:"token") or contains(card.shape, match:"emblem") or contains(card.shape, match:"rulestip") }
is_double := {contains(card.shape, match:"double") }
file_type := {if options.export_Images == "PNG" then "png" else "jpg"}
#determine if the card is of a rarity that should be included
included_rarity := {
(is_token() and chosen(options.rarities_to_export, choice:"token")) or chosen(options.rarities_to_export, choice:card.rarity)
}
included_rarity2 := {
(is_token() and options.include_Tokens)
or (card.rarity == "basic land" and options.include_Basic_Land)
or (card.rarity == "common" and options.include_Common)
or (card.rarity == "uncommon" and options.include_Uncommon)
or (card.rarity == "rare" and options.include_Rare)
or (card.rarity == "mythic rare" and options.include_Mythic)
or (card.rarity == "special" and options.include_Special)
}
#Strip bad punctuation from card names
strip_card_name :=
replace@(match: "",replace:"'") + #replace bad apostrophe with good apostrophe
replace@(match:":", replace:"")+ #remove colons
replace@(match:";", replace:"")+ #remove semicolons
replace@(match:"\n", replace:"")+ #remove linebreaks
replace@(match:"\\.", replace:"") #remove periods
# escape special xml characters
xml_escape := replace@(match:"&",replace:"&amp;") #escape ampersands
+ replace@(match:"\"",replace:"\\&quot;") #escape double quote
+ replace@(match:"\'",replace:"\\&apos;") #escape single quote
+ replace@(match:"\<",replace:"\\&lt;") #escape less than sign
#+ replace@(match:"\>",replace:"\\&gt;") #escape greater than sign, for some reason this upsets mse and they are technically not needed to escape
# escaped set code
setcode := xml_escape(set.set_code)
#functions for the !exportname command
exporter_name_filter := filter_text@(match:"!exporte?r?name [^\n\<]+")
exporter_name_grabber := replace@(match:"!exporte?r?name ", replace:"")
#determining what name should be used for the card
card_name := { if exporter_name_grabber(exporter_name_filter(card.notes)) != "" then exporter_name_grabber(exporter_name_filter(card.notes)) else card.name }
#surround mana symbols in curly brackets
format_mana := replace@(match:"(CHAOS|[1-9][0-9]+(?:\\/.)?|.\\/.\\/.|.\\/.|[+-]?[^.,: ])", replace:{"\{"+_1+"}"}, in_context:"<sym(-auto)?><match></sym")
#determining what rules text should be used for the card
card_rules_text := { format_mana(if card.special_text != "" then card.special_text else card.rule_text) }
card_rules_text_2 := { format_mana(if card.special_text_2 != "" then card.special_text_2 else card.rule_text_2) }
#helpers to find the correct count for this token relation, and generate the requisite XML
token_count_regex := "<([0-9]+|x)>"
filter_count := filter_text@(match: token_count_regex)
generate_count_XML := replace@(match:token_count_regex, replace:{" count=\"" + _1 + "\""})
add_related_count := {if filter_count(input) != "" then generate_count_XML(filter_count(input)) else ""}
#helpers to find if a auto-attachment is desired for this token relation, and generate the requisite XML
add_attachment := {if filter_text(match: "<attach>", input) != "" then " attach=\"attach\"" else ""}
#helpers to find if persistent is desired for this token relation, and generate the requisite XML
add_persistent := {if filter_text(match:"<(conjure|persistent)>", input) != "" then " persistent=\"persistent\"" else ""}
#helper functions for converted_related later
related_entry_regex := "(.+?[^[:space:]])(?:;|\n|$)"
#convert the !related command field to <reverse-related> XML blocks
convert_related :=
replace@(match: "!related ?\n?", replace:"")+ #blank out the related command itself
replace@(match: "\<",replace:"<") + #replace junk Start of Header characters with proper "less than sign"s
replace@(match: "",replace:"'") + #replace bad apostrophe with good apostrophe
replace@(match: "<X>",replace:"<x>") + #replace accidentily capital X with lowercase X
replace@(match:"!",replace: "") + #blank out the command ender
#for every other card name, surround it with reverse-related tags and put in relevant attributes
{for each entry in (break_text(match:related_entry_regex, input)) do ("\n \<reverse-related" + add_related_count(entry) + add_attachment(entry) + add_persistent(entry) + ">" + xml_escape(strip_card_name(entry)) + "\</reverse-related>")}
#remove accidentily created empty <reverse-related> XML blocks
remove_empty := replace@(match:" \<(reverse-)?related>\</(reverse-)?related>", replace:"")
#convert the !token command field to <related> XML blocks
convert_token :=
replace@(match: "!tokens? ?\n?", replace:"")+ #blank out the related command itself
replace@(match: "\<",replace:"<") + #replace junk Start of Header characters with proper "less than sign"s
replace@(match: "",replace:"'") + #replace bad apostrophe with good apostrophe
replace@(match: "<X>",replace:"<x>") + #replace accidentily capital X with lowercase X
replace@(match:"!",replace: "") + #blank out the command ender
#for every other card name, surround it with reverse-related tags and put in relevant attributes
{for each entry in (break_text(match:related_entry_regex, input)) do ("\n \<related" + add_related_count(entry) + add_attachment(entry) + add_persistent(entry) + ">" + xml_escape(strip_card_name(entry)) + "\</related>")}
filter_related := filter_text@(match:"!relate ?[^!]+!?")
filter_token := filter_text@(match:"!tokens? ?[^!]+!?")
#functions for the !tapped command
contains_tapped := contains@(match:"!tapped")
CIPT := {if contains_tapped(card.notes) then "\n "+"\<cipt>" + "1" + "\</cipt>" else ""}
# maintype, used in cockatrice's card type sorting,
# no longer automatically determined in v4 xml,
# first use the same heuristic used in "oracle" else do the same thing v3 xml did
# !maintype [type]! in the card notes overwrites this
filter_maintype := filter_text@(match:"!maintype ?[^!]+!?")
maintype :=
{
"\n "+"\<maintype>"
+(
if filter_maintype(card.notes) != "" then xml_escape(replace(match:"!$", replace:"", replace(match:"^!maintype ?", replace:"", filter_maintype(card.notes))))
else if contains(card.type, match:"Planeswalker") then "Planeswalker"
else if contains(card.type, match:"Creature") then "Creature"
else if contains(card.type, match:"Land") then "Land"
else if contains(card.type, match:"Sorcery") then "Sorcery"
else if contains(card.type, match:"Instant") then "Instant"
else if contains(card.type, match:"Artifact") then "Artifact"
else if contains(card.type, match:"Enchantment") then "Enchantment"
else xml_escape(replace(match:"^.* ", replace:"", replace(match:"(<sep-soft>)? —.*$", replace:"", card.type)))
)
+"\</maintype>"
}
card_color :=
{
if contains(card.type, match:"land") or contains(card.rule_text, match:"Devoid") then "" else
(
(if contains(card.card_color, match:"white") or contains(card.casting_cost, match:"W") then "W" else "")
+(if contains(card.card_color, match:"blue") or contains(card.casting_cost, match:"U") then "U" else "")
+(if contains(card.card_color, match:"black") or contains(card.casting_cost, match:"B") then "B" else "")
+(if contains(card.card_color, match:"red") or contains(card.casting_cost, match:"R") then "R" else "")
+(if contains(card.card_color, match:"green") or contains(card.casting_cost, match:"G") then "G" else "")
)
}
card_color_2 :=
{
if contains(card.type, match:"land") or contains(card.rule_text_2, match:"Devoid") then "" else
(
(if contains(card.card_color_2, match:"white") or contains(card.casting_cost_2, match:"W") then "W" else "")
+(if contains(card.card_color_2, match:"blue") or contains(card.casting_cost_2, match:"U") then "U" else "")
+(if contains(card.card_color_2, match:"black") or contains(card.casting_cost_2, match:"B") then "B" else "")
+(if contains(card.card_color_2, match:"red") or contains(card.casting_cost_2, match:"R") then "R" else "")
+(if contains(card.card_color_2, match:"green") or contains(card.casting_cost_2, match:"G") then "G" else "")
)
}
#write a normal card's XML text
write_normal := {
"\n "+"\<card>"
# Name
+"\n "+"\<name>"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))+"\</name>"
# Set
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ ">"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color
+"\n "+"\<colors>"
+ card_color()
+"\</colors>"
# Mana Cost
+"\n "+"\<manacost>"+card.casting_cost+"\</manacost>"
# Converted Mana Cost
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type
+"\n "+"\<type>"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\</type>"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt)+"\</pt>")
+"\n "+"\</prop>"
# Tablerow
+"\n "+"\<tablerow>"
+(if contains(card.type, match:"Instant") or contains(card.type, match:"Sorcery") then "3"
else if contains(card.type, match:"Creature") then "2"
else if contains(card.type, match:"Land") then "0"
else "1")
+"\</tablerow>"
#CIPT
+ CIPT()
# Rules Text
+"\n "+"\<text>"+xml_escape(card_rules_text())+"\</text>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
}
write_token := {
"\n "+"\<card>"
# Name
+"\n "+"\<name>"+xml_escape(strip_card_name(card_name())+(if options.append_Set_Code_To_Tokens then " " + setcode else ""))+"\</name>"
# Set
+"\n "+"\<set>"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color
+"\n "+"\<colors>"
+ card_color()
+"\</colors>"
# Type
+"\n "+"\<type>"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\</type>"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt)+"\</pt>")
+"\n "+"\</prop>"
# Tablerow
+"\n "+"\<tablerow>"
+(if contains(card.type, match:"Instant") or contains(card.type, match:"Sorcery") then "3"
else if contains(card.type, match:"Creature") then "2"
else if contains(card.type, match:"Land") then "0"
else "1")
+"\</tablerow>"
#CIPT
+ CIPT()
# Rules Text
+"\n "+"\<text>"+xml_escape(card_rules_text())+"\</text>"
# Token
+ "\n "+"\<token>1\</token>"
# Reverse Related
#if there is a !related block in the cards notes, set up the reverse-related XML elements
+ (if filter_related(card.notes) != "" then remove_empty(convert_related(filter_related(card.notes))))
+"\n "+"\</card>"
}
write_flip := {
"\n "+"\<card>"
# Name
+"\n "+"\<name>"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))
#+" // "+strip_card_name(card.name_2)
+"\</name>"
# Set
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ ">"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color
+"\n "+"\<colors>"
+(if contains(card.shape, match:"flip") then
(if contains(card.card_color, match:"multicolor") or contains(card.card_color, match:"hybrid") then "M"
else if contains(card.card_color, match:"white") then "W"
else if contains(card.card_color, match:"blue") then "U"
else if contains(card.card_color, match:"black") then "B"
else if contains(card.card_color, match:"red") then "R"
else if contains(card.card_color, match:"green") then "G"
else "")
else if card.card_color != "" and card.card_color != "land" and card.card_color != "artifact" and card.card_color_2 != "" and card.card_color_2 != "land" and card.card_color_2 != "artifact"then
(if contains(card.card_color, match:"multicolor") or contains(card.card_color, match:"hybrid") or card.card_color != card.card_color_2 then "M"
else if contains(card.card_color, match:"white") and contains(card.card_color_2, match:"white") then "W"
else if contains(card.card_color, match:"blue") and contains(card.card_color_2, match:"blue") then "U"
else if contains(card.card_color, match:"black") and contains(card.card_color_2, match:"black") then "B"
else if contains(card.card_color, match:"red") and contains(card.card_color_2, match:"red") then "R"
else if contains(card.card_color, match:"green") and contains(card.card_color_2, match:"green") then "G"
else "")
else
(if contains(card.card_color, match:"multicolor") or contains(card.card_color, match:"hybrid") or contains(card.card_color_2, match:"multicolor") or contains(card.card_color_2, match:"hybrid") then "M"
else if contains(card.card_color, match:"white") or contains(card.card_color_2, match:"white") then "W"
else if contains(card.card_color, match:"blue") or contains(card.card_color_2, match:"blue") then "U"
else if contains(card.card_color, match:"black") or contains(card.card_color_2, match:"black") then "B"
else if contains(card.card_color, match:"red") or contains(card.card_color_2, match:"red") then "R"
else if contains(card.card_color, match:"green") or contains(card.card_color_2, match:"green") then "G"
else "")
)
+"\</colors>"
# Mana Cost
+"\n "+"\<manacost>"+card.casting_cost
+(if card.casting_cost_2 != "" then " // "+card.casting_cost_2)
+"\</manacost>"
# Converted Mana Cost
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type
+"\n "+"\<type>"+xml_escape(replace(card.type, match:"—", replace:"-")+" // "+replace(card.type_2, match:"—", replace:"-"))+"\</type>"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") or contains(card.type_2, match:"Creature") then "\n ")
+(if contains(card.type, match:"Creature") or contains(card.type_2, match:"Creature") then "\<pt>")
+(if contains(card.type, match:"Creature") then xml_escape(card.pt))
+(if contains(card.type, match:"Creature") and contains(card.type_2, match:"Creature") then " // ")
+(if contains(card.type_2, match:"Creature") then xml_escape(card.pt_2))
+(if contains(card.type, match:"Creature") or contains(card.type_2, match:"Creature") then "\</pt>")
+"\n "+"\</prop>"
# Tablerow
+"\n "+"\<tablerow>"
+(if contains(card.type, match:"Instant") or contains(card.type, match:"Sorcery") or contains(card.type_2, match:"Instant") or contains(card.type_2, match:"Sorcery") then "3"
else if contains(card.type, match:"Creature") or contains(card.type_2, match:"Creature") then "2"
else if contains(card.type, match:"Land") or contains(card.type_2, match:"Land") then "0"
else "1")
+"\</tablerow>"
# Rules Text
+"\n "+"\<text>"+xml_escape(card_rules_text()+"\n--- \n"+card_rules_text_2())+"\</text>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
}
write_double := {
"\n "+"\<card>"
# Name
+"\n "+"\<name>"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))
#+" | ("+strip_card_name(card.name_2)+")"
+"\</name>"
# Set
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ " splitterPath=\""+"/"+options.append_String_To_Names+strip_card_name(card_name())+"." + file_type() + "\" >"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color
+"\n "+"\<colors>"
+ card_color()
+"\</colors>"
# Mana Cost
+"\n "+"\<manacost>"+card.casting_cost+"\</manacost>"
# Converted Mana Cost
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type
+"\n "+"\<type>"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\</type>"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt)+"\</pt>")
+"\n "+"\</prop>"
# Tablerow
+"\n "+"\<tablerow>"
+(if contains(card.type, match:"Instant") or contains(card.type, match:"Sorcery") then "3"
else if contains(card.type, match:"Creature") then "2"
else if contains(card.type, match:"Land") then "0"
else "1")
+"\</tablerow>"
# Rules Text
+"\n "+"\<text>"+xml_escape(card_rules_text()
+"\n---\n(Back): "+strip_card_name(card.name_2))+"\</text>"
# Name of the related card
+"\n "+"\<related attach=\"transform\">"+xml_escape(strip_card_name(card.name_2))+"\</related>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
+"\n "+"\<card>"
# Name II
+"\n "+"\<name>"
#+"("+strip_card_name(card_name())+") | "
+xml_escape(strip_card_name(card.name_2))
+"\</name>"
# Set II
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ " splitterPath=\""+"/"+strip_card_name(card.name_2)+"." + file_type() + "\" >"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color II
+"\n "+"\<colors>"
+ card_color_2()
+"\</colors>"
# Mana Cost II
+"\n "+"\<manacost>"+card.casting_cost_2+"\</manacost>"
# Converted Mana Cost II
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type II
+"\n "+"\<type>"+xml_escape(replace(card.type_2, match:"—", replace:"-"))+"\</type>"
# P/T II
+(if contains(card.type_2, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt_2)+"\</pt>")
+"\n "+"\</prop>"
# Tablerow II
+"\n "+"\<tablerow>"
+(if contains(card.type_2, match:"Instant") or contains(card.type_2, match:"Sorcery") then "3"
else if contains(card.type_2, match:"Creature") then "2"
else if contains(card.type_2, match:"Land") then "0"
else "1")
+"\</tablerow>"
# Rules Text II
+"\n "+"\<text>"+xml_escape(card_rules_text_2()
+"\n---\n(Front): "+strip_card_name(card_name()))+"\</text>"
# Name of the related card
+"\n "+"\<related attach=\"transform\">"+xml_escape(strip_card_name(card.name))+"\</related>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
}
# Count the number of paragraphs to detect number of walker abilities.
paragraph_count := replace@(match:"\n", replace:"•")+
filter_text@(match:"•")
write_walker := {
"\n "+"\<card>"
# Name
+"\n "+"\<name>"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))+"\</name>"
# Set
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ ">"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color
+"\n "+"\<colors>"
+ card_color()
+"\</colors>"
# Mana Cost
+"\n "+"\<manacost>"+card.casting_cost+"\</manacost>"
# Converted Mana Cost
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type
+"\n "+"\<type>"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\</type>"
+maintype()
# Loyalty
+"\n "+"\<loyalty>"+card.loyalty+"\</loyalty>"
+"\n "+"\</prop>"
# Tablerow
+"\n "+"\<tablerow>"+"1"+"\</tablerow>"
#CIPT
+ CIPT()
# Rules Text
+"\n "+"\<text>"
+xml_escape((if card.special_text or else "" != "" then card.special_text else
card.loyalty_cost_1
+(if card.loyalty_cost_1 !="" then ": ")
+split_text(match:"\n", card.rule_text).0
+(if contains(paragraph_count(card.rule_text), match:"•") then "\n")
+card.loyalty_cost_2
+(if card.loyalty_cost_2 !="" then ": ")
+(if contains(paragraph_count(card.rule_text), match:"•") then split_text(match:"\n", card.rule_text).1)
+(if contains(paragraph_count(card.rule_text), match:"••") then "\n")
+card.loyalty_cost_3
+(if card.loyalty_cost_3 !="" then ": ")
+(if contains(paragraph_count(card.rule_text), match:"••") then split_text(match:"\n", card.rule_text).2)
+(if contains(paragraph_count(card.rule_text), match:"•••") then "\n")
+card.loyalty_cost_4
+(if card.loyalty_cost_4 !="" then ": ")
+(if contains(paragraph_count(card.rule_text), match:"•••") then split_text(match:"\n", card.rule_text).3)))
+"\</text>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
}
write_double_walker := {
"\n "+"\<card>"
# Name
+"\n "+"\<name>"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))
#+" | ("+strip_card_name(card.name_2)+")"
+"\</name>"
# Set
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ " splitterPath=\""+"/"+options.append_String_To_Names+strip_card_name(card_name())+"." + file_type() + "\" >"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color
+"\n "+"\<colors>"
+ card_color()
+"\</colors>"
# Mana Cost
+"\n "+"\<manacost>"+card.casting_cost+"\</manacost>"
# Converted Mana Cost
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type
+"\n "+"\<type>"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\</type>"
+maintype()
# Loyalty
+(if contains(card.type, match:"Planeswalker") then "\n "+"\<loyalty>"+card.loyalty+"\</loyalty>")
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt)+"\</pt>")
+"\n "+"\</prop>"
# Tablerow
+"\n "+"\<tablerow>"
+(if contains(card.type_2, match:"Instant") or contains(card.type_2, match:"Sorcery") then "3"
else if contains(card.type_2, match:"Creature") then "2"
else if contains(card.type_2, match:"Land") then "0"
else "1")
+"\</tablerow>"
# Rules Text
+"\n "+"\<text>"
+xml_escape((if card.special_text or else "" != "" then card.special_text else
card.loyalty_cost_1
+(if card.loyalty_cost_1 !="" then ": ")
+split_text(match:"\n", card.rule_text).0
+(if contains(paragraph_count(card.rule_text), match:"•") then "\n")
+card.loyalty_cost_2
+(if card.loyalty_cost_2 !="" then ": ")
+(if contains(paragraph_count(card.rule_text), match:"•") then split_text(match:"\n", card.rule_text).1)
+(if contains(paragraph_count(card.rule_text), match:"••") then "\n")
+card.loyalty_cost_3
+(if card.loyalty_cost_3 !="" then ": ")
+(if contains(paragraph_count(card.rule_text), match:"••") then split_text(match:"\n", card.rule_text).2)
+(if contains(paragraph_count(card.rule_text), match:"•••") then "\n"))
+"\n---\n(Back): "+strip_card_name(card.name_2))+"\</text>"
# Name of the related card
+"\n "+"\<related attach=\"transform\">"+xml_escape(strip_card_name(card.name_2))+"\</related>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
+"\n "+"\<card>"
# Name II
+"\n "+"\<name>"
#+strip_card_name(card_name())+") | "
+xml_escape(strip_card_name(card.name_2))+"\</name>"
# Set II
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ " splitterPath=\""+"/"+strip_card_name(card.name_2)+"." + file_type() + "\" >"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color II
+"\n "+"\<colors>"
+ card_color_2()
+"\</colors>"
# Mana Cost II
+"\n "+"\<manacost>"+card.casting_cost_2+"\</manacost>"
# Converted Mana Cost II
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type II
+"\n "+"\<type>"+xml_escape(replace(card.type_2, match:"—", replace:"-"))+"\</type>"
# Loyalty II
+(if contains(card.type_2, match:"Planeswalker") then "\n "+"\<loyalty>"+card.loyalty_2+"\</loyalty>")
# P/T II
+(if contains(card.type_2, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt_2)+"\</pt>")
+"\n "+"\</prop>"
# Tablerow II
+"\n "+"\<tablerow>"
+(if contains(card.type_2, match:"Instant") or contains(card.type_2, match:"Sorcery") then "3"
else if contains(card.type_2, match:"Creature") then "2"
else if contains(card.type_2, match:"Land") then "0"
else "1")
+"\</tablerow>"
# Rules Text II
+"\n "+"\<text>"
+xml_escape((if card.special_text_2 or else "" != "" then card.special_text_2 else
card.loyalty_cost_4
+(if card.loyalty_cost_4 !="" then ": ")
+split_text(match:"\n", card.rule_text_2).0
+(if contains(paragraph_count(card.rule_text_2), match:"•") then "\n")
+card.loyalty_cost_5
+(if card.loyalty_cost_5 !="" then ": ")
+(if contains(paragraph_count(card.rule_text_2), match:"•") then split_text(match:"\n", card.rule_text_2).1)
+(if contains(paragraph_count(card.rule_text_2), match:"••") then "\n")
+card.loyalty_cost_6
+(if card.loyalty_cost_6 !="" then ": ")
+(if contains(paragraph_count(card.rule_text_2), match:"••") then split_text(match:"\n", card.rule_text_2).2)
+(if contains(paragraph_count(card.rule_text_2), match:"•••") then "\n"))
+"\n---\n(Front): "+strip_card_name(card_name()))+"\</text>"
# Name of the related card
+"\n "+"\<related attach=\"transform\">"+xml_escape(strip_card_name(card.name))+"\</related>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
}
write_sparker := {
"\n "+"\<card>"
# Name
+"\n "+"\<name>"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))
#+" | ("+strip_card_name(card.name_2)+")"
+"\</name>"
# Set
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ " splitterPath=\""+"/"+options.append_String_To_Names+strip_card_name(card_name())+"." + file_type() + "\" >"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color
+"\n "+"\<colors>"
+ card_color()
+"\</colors>"
# Mana Cost
+"\n "+"\<manacost>"+card.casting_cost+"\</manacost>"
# Converted Mana Cost
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type
+"\n "+"\<type>"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\</type>"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt)+"\</pt>")
+"\n "+"\</prop>"
# Tablerow
+"\n "+"\<tablerow>"
+(if contains(card.type, match:"Instant") or contains(card.type, match:"Sorcery") then "3"
else if contains(card.type, match:"Creature") then "2"
else if contains(card.type, match:"Land") then "0"
else "1")
+"\</tablerow>"
# Rules Text
+"\n "+"\<text>"+xml_escape(card_rules_text()
+"\n---\n(Back): "+strip_card_name(card.name_2))+"\</text>"
# Name of the related card
+"\n "+"\<related attach=\"transform\">"+xml_escape(strip_card_name(card.name_2))+"\</related>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
+"\n "+"\<card>"
# Name II
+"\n "+"\<name>"
#+strip_card_name(card_name())+") | "
+xml_escape(strip_card_name(card.name_2))+"\</name>"
# Set II
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ " splitterPath=\""+"/"+strip_card_name(card.name_2)+"." + file_type() + "\" >"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color II
+"\n "+"\<colors>"
+ card_color_2()
+"\</colors>"
# Mana Cost II
+"\n "+"\<manacost>"+card.casting_cost_2+"\</manacost>"
# Converted Mana Cost II
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type II
+"\n "+"\<type>"+xml_escape(replace(card.type_2, match:"—", replace:"-"))+"\</type>"
# Loyalty II
+(if contains(card.type_2, match:"Planeswalker") then "\n "+"\<loyalty>"+card.loyalty_2+"\</loyalty>")
# P/T II
+(if contains(card.type_2, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt_2)+"\</pt>")
+"\n "+"\</prop>"
# Tablerow II
+"\n "+"\<tablerow>"
+(if contains(card.type_2, match:"Instant") or contains(card.type_2, match:"Sorcery") then "3"
else if contains(card.type_2, match:"Creature") then "2"
else if contains(card.type_2, match:"Land") then "0"
else "1")
+"\</tablerow>"
# Rules Text II
+"\n "+"\<text>"
+xml_escape((if card.special_text_2 or else "" != "" then card.special_text_2 else
card.loyalty_cost_4
+(if card.loyalty_cost_4 !="" then ": ")
+split_text(match:"\n", card.rule_text_2).0
+(if contains(paragraph_count(card.rule_text_2), match:"•") then "\n")
+card.loyalty_cost_5
+(if card.loyalty_cost_5 !="" then ": ")
+(if contains(paragraph_count(card.rule_text_2), match:"•") then split_text(match:"\n", card.rule_text_2).1)
+(if contains(paragraph_count(card.rule_text_2), match:"••") then "\n")
+card.loyalty_cost_6
+(if card.loyalty_cost_6 !="" then ": ")
+(if contains(paragraph_count(card.rule_text_2), match:"••") then split_text(match:"\n", card.rule_text_2).2)
+(if contains(paragraph_count(card.rule_text_2), match:"•••") then "\n"))
+"\n---\n(Front): "+strip_card_name(card_name()))+"\</text>"
# Name of the related card
+"\n "+"\<related attach=\"transform\">"+xml_escape(strip_card_name(card.name))+"\</related>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
}
write_sacrificer := {
"\n "+"\<card>"
# Name
+"\n "+"\<name>"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))
#+" | ("+strip_card_name(card.name_2)+")"
+"\</name>"
# Set
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ " splitterPath=\""+"/"+options.append_String_To_Names+strip_card_name(card_name())+"." + file_type() + "\" >"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color
+"\n "+"\<colors>"
+ card_color()
+"\</colors>"
# Mana Cost
+"\n "+"\<manacost>"+card.casting_cost+"\</manacost>"
# Converted Mana Cost
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type
+"\n "+"\<type>"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\</type>"
+maintype()
# Loyalty
+(if contains(card.type, match:"Planeswalker") then "\n "+"\<loyalty>"+card.loyalty+"\</loyalty>")
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt)+"\</pt>")
+"\n "+"\</prop>"
# Tablerow
+"\n "+"\<tablerow>"
+(if contains(card.type_2, match:"Instant") or contains(card.type_2, match:"Sorcery") then "3"
else if contains(card.type_2, match:"Creature") then "2"
else if contains(card.type_2, match:"Land") then "0"
else "1")
+"\</tablerow>"
# Rules Text
+"\n "+"\<text>"
+xml_escape((if card.special_text or else "" != "" then card.special_text else
card.loyalty_cost_1
+(if card.loyalty_cost_1 !="" then ": ")
+split_text(match:"\n", card.rule_text).0
+(if contains(paragraph_count(card.rule_text), match:"•") then "\n")
+card.loyalty_cost_2
+(if card.loyalty_cost_2 !="" then ": ")
+(if contains(paragraph_count(card.rule_text), match:"•") then split_text(match:"\n", card.rule_text).1)
+(if contains(paragraph_count(card.rule_text), match:"••") then "\n")
+card.loyalty_cost_3
+(if card.loyalty_cost_3 !="" then ": ")
+(if contains(paragraph_count(card.rule_text), match:"••") then split_text(match:"\n", card.rule_text).2)
+(if contains(paragraph_count(card.rule_text), match:"•••") then "\n"))
+"\n---\n(Back): "+strip_card_name(card.name_2))+"\</text>"
# Name of the related card
+"\n "+"\<related attach=\"transform\">"+xml_escape(strip_card_name(card.name_2))+"\</related>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
+"\n "+"\<card>"
# Name II
+"\n "+"\<name>"
#+"("+strip_card_name(card_name())+") | "
+xml_escape(strip_card_name(card.name_2))
+"\</name>"
# Set II
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ " splitterPath=\""+"/"+strip_card_name(card.name_2)+"." + file_type() + "\" >"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color II
+"\n "+"\<colors>"
+ card_color_2()
+"\</colors>"
# Mana Cost II
+"\n "+"\<manacost>"+card.casting_cost_2+"\</manacost>"
# Converted Mana Cost II
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type II
+"\n "+"\<type>"+xml_escape(replace(card.type_2, match:"—", replace:"-"))+"\</type>"
# P/T II
+(if contains(card.type_2, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt_2)+"\</pt>")
+"\n "+"\</prop>"
# Tablerow II
+"\n "+"\<tablerow>"
+(if contains(card.type_2, match:"Instant") or contains(card.type_2, match:"Sorcery") then "3"
else if contains(card.type_2, match:"Creature") then "2"
else if contains(card.type_2, match:"Land") then "0"
else "1")
+"\</tablerow>"
# Rules Text II
+"\n "+"\<text>"+xml_escape(card_rules_text_2()
+"\n---\n(Front): "+strip_card_name(card_name()))+"\</text>"
# Name of the related card
+"\n "+"\<related attach=\"transform\">"+xml_escape(strip_card_name(card.name))+"\</related>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
}
write_leveler := {
"\n "+"\<card>"
# Name
+"\n "+"\<name>"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))+"\</name>"
# Set
+"\n "+"\<set rarity="
+(if contains(card.rarity,match:"uncommon") then "\"uncommon\""
else if contains(card.rarity,match:"common") then "\"common\""
else if contains(card.rarity,match:"mythic") then "\"mythic\""
else if contains(card.rarity,match:"rare") then "\"rare\""
else "\"\"")
+ ">"+setcode+"\</set>"
+"\n "+"\<prop>"
# Color
+"\n "+"\<colors>"
+ card_color()
+"\</colors>"
# Mana Cost
+"\n "+"\<manacost>"+card.casting_cost+"\</manacost>"
# Converted Mana Cost
+"\n "+"\<cmc>"+card.cmc+"\</cmc>"
# Type
+"\n "+"\<type>"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\</type>"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\<pt>"+xml_escape(card.pt)+"\</pt>")
+"\n "+"\</prop>"
#CIPT
+ CIPT()
# Tablerow
+"\n "+"\<tablerow>"
+(if contains(card.type, match:"Instant") or contains(card.type, match:"Sorcery") then "3"
else if contains(card.type, match:"Creature") then "2"
else if contains(card.type, match:"Land") then "0"
else "1")
+"\</tablerow>"
# Rules Text
+"\n "+"\<text>"
#Level I
+xml_escape(card_rules_text()
# Level II
+"\nLEVEL " + card.level_1
+(if card.pt_2 != "" then "\n"+card.pt_2)
+"\n"+card.rule_text_2
# Level III
+"\nLEVEL " + card.level_2
+(if card.pt_3 != "" then "\n"+card.pt_3)
+"\n"+card.rule_text_3)
+"\</text>"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\</card>"
}
write_card := { if is_token() then ""
else if not(included_rarity()) then ""
else if contains(card.shape, match:"double") and contains(card.type, match:"Planeswalker") and contains(card.type_2, match:"Planeswalker") then write_double_walker()
else if contains(card.shape, match:"double") and card.loyalty_2 != "" then write_sparker()
else if contains(card.shape, match:"double") and card.loyalty != "" then write_sacrificer()
else if contains(card.shape, match:"double") then write_double()
else if card.name_2 != "" then write_flip()
else if card.loyalty != "" then write_walker()
else if contains(card.shape, match:"leveler") then write_leveler()
else write_normal()
}
#if the currently exported card is a token, write it as a token
write_token_if_token := { if is_token() then write_token() else ""}
#render image file
write_image :=
{
if length(card.stylesheet.card_regions) > 0 then write_multi_image()
else write_single_image()
}
format_file_name := {
options.append_String_To_Names
+ input
+ (if is_token() and options.append_Set_Code_To_Tokens then " " + set.set_code else "")
+ "." + file_type()
}
write_single_image := {
write_image_file(
card,
directory: set.set_code,
file: format_file_name(strip_card_name(card_name())),
width: (if contains(card.shape, match:"split") then 752 else 375),
height: 523
)
}
write_multi_image := {
crop_data := crop_multi_image(card:card)
for i from 0 to length(crop_data.keys)-1 do (
region_name := crop_data.keys[i][0]
region_image := crop_data.values[i][0]
face_name := if region_name == "front" or region_name == "minifront"
then strip_card_name(card_name())
else if region_name == "back" or region_name == "meldpair"
then strip_card_name(card.name_2)
else if region_name == "meld" or region_name == "meldback" or region_name == "thirdcard"
then strip_card_name(card.name_3)
else strip_card_name(card_name()) + "_" + region_name
write_image_file(
region_image,
directory: set.set_code,
file: format_file_name(face_name)
)
)
}
#if images are set to be rendered, render all images of rarities that have been selected
write_images := if options.export_Images != "no" then for each card in filter_list(cards,filter:{included_rarity(card:input)}) do write_image() else ""
write_cards := to_text(for each card in cards do write_card())
write_all_tokens := to_text(for each card in cards do write_token_if_token())
#Main export script
#tokens in Separate XML
if (chosen(options.rarities_to_export, choice:"token") and options.tokens_In_Separate_XML) then write_text_file(file:set.set_code + " Tokens" + ".xml", to_string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<cockatrice_carddatabase version=\"4\">\n <cards>\n"+write_all_tokens+"\n\n </cards>\n</cockatrice_carddatabase>"))
#other cards
to_string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<cockatrice_carddatabase version=\"4\">\n <sets>\n <set>\n <name>"+setcode+"</name>\n <longname>"+xml_escape(set.title)+"</longname>\n <settype>"+xml_escape(options.cockatrice_Set_Type)+"</settype>\n </set>\n </sets>\n <cards>\n"+write_cards+if (chosen(options.rarities_to_export, choice:"token") and not(options.tokens_In_Separate_XML)) then ("\n\n <!-->Tokens</-->\n"+write_all_tokens)+"\n\n </cards>\n</cockatrice_carddatabase>")