mse version: 2.5.0
short name: Cockatrice
full name: Exporter v2.1
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 2024/10, 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:"&") #escape ampersands
+ replace@(match:"\"",replace:"\\"") #escape double quote
+ replace@(match:"\'",replace:"\\'") #escape single quote
+ replace@(match:"\<",replace:"\\<") #escape less than sign
#+ replace@(match:"\>",replace:"\\>") #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:""
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: "", 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 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: "",replace:"") + #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 \" + xml_escape(strip_card_name(entry)) + "\")}
#remove accidentily created empty XML blocks
remove_empty := replace@(match:" \<(reverse-)?related>\(reverse-)?related>", replace:"")
#convert the !token command field to 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: "",replace:"") + #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 \" + xml_escape(strip_card_name(entry)) + "\")}
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 "+"\" + "1" + "\" 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 "+"\"
+(
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:"()? —.*$", replace:"", card.type)))
)
+"\"
}
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 "+"\"
# Name
+"\n "+"\"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))+"\"
# Set
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color
+"\n "+"\"
+ card_color()
+"\"
# Mana Cost
+"\n "+"\"+card.casting_cost+"\"
# Converted Mana Cost
+"\n "+"\"+card.cmc+"\"
# Type
+"\n "+"\"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\"+xml_escape(card.pt)+"\")
+"\n "+"\"
# Tablerow
+"\n "+"\"
+(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")
+"\"
#CIPT
+ CIPT()
# Rules Text
+"\n "+"\"+xml_escape(card_rules_text())+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
}
write_token := {
"\n "+"\"
# Name
+"\n "+"\"+xml_escape(strip_card_name(card_name())+(if options.append_Set_Code_To_Tokens then " " + setcode else ""))+"\"
# Set
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color
+"\n "+"\"
+ card_color()
+"\"
# Type
+"\n "+"\"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\"+xml_escape(card.pt)+"\")
+"\n "+"\"
# Tablerow
+"\n "+"\"
+(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")
+"\"
#CIPT
+ CIPT()
# Rules Text
+"\n "+"\"+xml_escape(card_rules_text())+"\"
# Token
+ "\n "+"\1\"
# 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 "+"\"
}
write_flip := {
"\n "+"\"
# Name
+"\n "+"\"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))
#+" // "+strip_card_name(card.name_2)
+"\"
# Set
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color
+"\n "+"\"
+(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 "")
)
+"\"
# Mana Cost
+"\n "+"\"+card.casting_cost
+(if card.casting_cost_2 != "" then " // "+card.casting_cost_2)
+"\"
# Converted Mana Cost
+"\n "+"\"+card.cmc+"\"
# Type
+"\n "+"\"+xml_escape(replace(card.type, match:"—", replace:"-")+" // "+replace(card.type_2, match:"—", replace:"-"))+"\"
+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 "\")
+(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 "\")
+"\n "+"\"
# Tablerow
+"\n "+"\"
+(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")
+"\"
# Rules Text
+"\n "+"\"+xml_escape(card_rules_text()+"\n--- \n"+card_rules_text_2())+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
}
write_double := {
"\n "+"\"
# Name
+"\n "+"\"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))
#+" | ("+strip_card_name(card.name_2)+")"
+"\"
# Set
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color
+"\n "+"\"
+ card_color()
+"\"
# Mana Cost
+"\n "+"\"+card.casting_cost+"\"
# Converted Mana Cost
+"\n "+"\"+card.cmc+"\"
# Type
+"\n "+"\"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\"+xml_escape(card.pt)+"\")
+"\n "+"\"
# Tablerow
+"\n "+"\"
+(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")
+"\"
# Rules Text
+"\n "+"\"+xml_escape(card_rules_text()
+"\n---\n(Back): "+strip_card_name(card.name_2))+"\"
# Name of the related card
+"\n "+"\"+xml_escape(strip_card_name(card.name_2))+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
+"\n "+"\"
# Name II
+"\n "+"\"
#+"("+strip_card_name(card_name())+") | "
+xml_escape(strip_card_name(card.name_2))
+"\"
# Set II
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color II
+"\n "+"\"
+ card_color_2()
+"\"
# Mana Cost II
+"\n "+"\"+card.casting_cost_2+"\"
# Converted Mana Cost II
+"\n "+"\"+card.cmc+"\"
# Type II
+"\n "+"\"+xml_escape(replace(card.type_2, match:"—", replace:"-"))+"\"
# P/T II
+(if contains(card.type_2, match:"Creature") then "\n "+"\"+xml_escape(card.pt_2)+"\")
+"\n "+"\"
# Tablerow II
+"\n "+"\"
+(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")
+"\"
# Rules Text II
+"\n "+"\"+xml_escape(card_rules_text_2()
+"\n---\n(Front): "+strip_card_name(card_name()))+"\"
# Name of the related card
+"\n "+"\"+xml_escape(strip_card_name(card.name))+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
}
# Count the number of paragraphs to detect number of walker abilities.
paragraph_count := replace@(match:"\n", replace:"•")+
filter_text@(match:"•")
write_walker := {
"\n "+"\"
# Name
+"\n "+"\"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))+"\"
# Set
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color
+"\n "+"\"
+ card_color()
+"\"
# Mana Cost
+"\n "+"\"+card.casting_cost+"\"
# Converted Mana Cost
+"\n "+"\"+card.cmc+"\"
# Type
+"\n "+"\"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\"
+maintype()
# Loyalty
+"\n "+"\"+card.loyalty+"\"
+"\n "+"\"
# Tablerow
+"\n "+"\"+"1"+"\"
#CIPT
+ CIPT()
# Rules Text
+"\n "+"\"
+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)))
+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
}
write_double_walker := {
"\n "+"\"
# Name
+"\n "+"\"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))
#+" | ("+strip_card_name(card.name_2)+")"
+"\"
# Set
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color
+"\n "+"\"
+ card_color()
+"\"
# Mana Cost
+"\n "+"\"+card.casting_cost+"\"
# Converted Mana Cost
+"\n "+"\"+card.cmc+"\"
# Type
+"\n "+"\"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\"
+maintype()
# Loyalty
+(if contains(card.type, match:"Planeswalker") then "\n "+"\"+card.loyalty+"\")
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\"+xml_escape(card.pt)+"\")
+"\n "+"\"
# Tablerow
+"\n "+"\"
+(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")
+"\"
# Rules Text
+"\n "+"\"
+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))+"\"
# Name of the related card
+"\n "+"\"+xml_escape(strip_card_name(card.name_2))+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
+"\n "+"\"
# Name II
+"\n "+"\"
#+strip_card_name(card_name())+") | "
+xml_escape(strip_card_name(card.name_2))+"\"
# Set II
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color II
+"\n "+"\"
+ card_color_2()
+"\"
# Mana Cost II
+"\n "+"\"+card.casting_cost_2+"\"
# Converted Mana Cost II
+"\n "+"\"+card.cmc+"\"
# Type II
+"\n "+"\"+xml_escape(replace(card.type_2, match:"—", replace:"-"))+"\"
# Loyalty II
+(if contains(card.type_2, match:"Planeswalker") then "\n "+"\"+card.loyalty_2+"\")
# P/T II
+(if contains(card.type_2, match:"Creature") then "\n "+"\"+xml_escape(card.pt_2)+"\")
+"\n "+"\"
# Tablerow II
+"\n "+"\"
+(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")
+"\"
# Rules Text II
+"\n "+"\"
+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()))+"\"
# Name of the related card
+"\n "+"\"+xml_escape(strip_card_name(card.name))+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
}
write_sparker := {
"\n "+"\"
# Name
+"\n "+"\"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))
#+" | ("+strip_card_name(card.name_2)+")"
+"\"
# Set
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color
+"\n "+"\"
+ card_color()
+"\"
# Mana Cost
+"\n "+"\"+card.casting_cost+"\"
# Converted Mana Cost
+"\n "+"\"+card.cmc+"\"
# Type
+"\n "+"\"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\"+xml_escape(card.pt)+"\")
+"\n "+"\"
# Tablerow
+"\n "+"\"
+(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")
+"\"
# Rules Text
+"\n "+"\"+xml_escape(card_rules_text()
+"\n---\n(Back): "+strip_card_name(card.name_2))+"\"
# Name of the related card
+"\n "+"\"+xml_escape(strip_card_name(card.name_2))+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
+"\n "+"\"
# Name II
+"\n "+"\"
#+strip_card_name(card_name())+") | "
+xml_escape(strip_card_name(card.name_2))+"\"
# Set II
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color II
+"\n "+"\"
+ card_color_2()
+"\"
# Mana Cost II
+"\n "+"\"+card.casting_cost_2+"\"
# Converted Mana Cost II
+"\n "+"\"+card.cmc+"\"
# Type II
+"\n "+"\"+xml_escape(replace(card.type_2, match:"—", replace:"-"))+"\"
# Loyalty II
+(if contains(card.type_2, match:"Planeswalker") then "\n "+"\"+card.loyalty_2+"\")
# P/T II
+(if contains(card.type_2, match:"Creature") then "\n "+"\"+xml_escape(card.pt_2)+"\")
+"\n "+"\"
# Tablerow II
+"\n "+"\"
+(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")
+"\"
# Rules Text II
+"\n "+"\"
+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()))+"\"
# Name of the related card
+"\n "+"\"+xml_escape(strip_card_name(card.name))+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
}
write_sacrificer := {
"\n "+"\"
# Name
+"\n "+"\"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))
#+" | ("+strip_card_name(card.name_2)+")"
+"\"
# Set
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color
+"\n "+"\"
+ card_color()
+"\"
# Mana Cost
+"\n "+"\"+card.casting_cost+"\"
# Converted Mana Cost
+"\n "+"\"+card.cmc+"\"
# Type
+"\n "+"\"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\"
+maintype()
# Loyalty
+(if contains(card.type, match:"Planeswalker") then "\n "+"\"+card.loyalty+"\")
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\"+xml_escape(card.pt)+"\")
+"\n "+"\"
# Tablerow
+"\n "+"\"
+(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")
+"\"
# Rules Text
+"\n "+"\"
+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))+"\"
# Name of the related card
+"\n "+"\"+xml_escape(strip_card_name(card.name_2))+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
+"\n "+"\"
# Name II
+"\n "+"\"
#+"("+strip_card_name(card_name())+") | "
+xml_escape(strip_card_name(card.name_2))
+"\"
# Set II
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color II
+"\n "+"\"
+ card_color_2()
+"\"
# Mana Cost II
+"\n "+"\"+card.casting_cost_2+"\"
# Converted Mana Cost II
+"\n "+"\"+card.cmc+"\"
# Type II
+"\n "+"\"+xml_escape(replace(card.type_2, match:"—", replace:"-"))+"\"
# P/T II
+(if contains(card.type_2, match:"Creature") then "\n "+"\"+xml_escape(card.pt_2)+"\")
+"\n "+"\"
# Tablerow II
+"\n "+"\"
+(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")
+"\"
# Rules Text II
+"\n "+"\"+xml_escape(card_rules_text_2()
+"\n---\n(Front): "+strip_card_name(card_name()))+"\"
# Name of the related card
+"\n "+"\"+xml_escape(strip_card_name(card.name))+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
}
write_leveler := {
"\n "+"\"
# Name
+"\n "+"\"+xml_escape(options.append_String_To_Names+strip_card_name(card_name()))+"\"
# Set
+"\n "+"\"+setcode+"\"
+"\n "+"\"
# Color
+"\n "+"\"
+ card_color()
+"\"
# Mana Cost
+"\n "+"\"+card.casting_cost+"\"
# Converted Mana Cost
+"\n "+"\"+card.cmc+"\"
# Type
+"\n "+"\"+xml_escape(replace(card.type, match:"—", replace:"-"))+"\"
+maintype()
# P/T
+(if contains(card.type, match:"Creature") then "\n "+"\"+xml_escape(card.pt)+"\")
+"\n "+"\"
#CIPT
+ CIPT()
# Tablerow
+"\n "+"\"
+(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")
+"\"
# Rules Text
+"\n "+"\"
#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)
+"\"
+ (if filter_token(card.notes) != "" then remove_empty(convert_token(filter_token(card.notes))))
+"\n "+"\"
}
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 :=
{
sts := card.stylesheet
if sts == nil then sts := set.stylesheet
if length(sts.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("\n\n \n"+write_all_tokens+"\n\n \n"))
#other cards
to_string("\n\n \n \n "+setcode+"\n "+xml_escape(set.title)+"\n "+xml_escape(options.cockatrice_Set_Type)+"\n \n \n \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 \n")