﻿############################################################## Localization

include file: language

############################################################## Sorting mana symbols

# correctly sort a mana symbol (no guild mana)
mana_sort       := sort_text@(order: "XYZI[0123456789]DHSC(WUBRG)")
# correctly sort wedge mana
mana_sort_wedge := sort_text@(order: "XYZI[0123456789]DHSC(WBGUR)")
# correctly sort guild mana
mana_sort_guild := sort_text@(order: "[XYZI01234567890DHSCWUBRG/|]") +
		replace@(
			# No lookbehind :(
			#match: "(?<!/)(./.|././.|./././.|.[|])(?!/)",
			match: "./.|././.|./././.|.[|]",
			in_context: "(^|[^/])<match>($|[^/])",
			replace: {sort_text(order:"in_place((WUBRG)")}
		)
mana_has_guild := match@(match: "[/|]") # Is there guild or half mana in the input?
mana_is_wedge := { contains(set.mana_cost_sorting, match: "wedge") and ( number_of_items(in: sort_text(order:"<WUBRG>", card.casting_cost), filter: "<WUBRG>") == 3 ) }
# A mana cost can contain both normal and guild mana
mana_filter := to_upper + {
	if contains(set.mana_cost_sorting, match: "unsorted") then input
	else if mana_has_guild() then mana_sort_guild()
	else if mana_is_wedge() then mana_sort_wedge()
	else                     mana_sort()
}
# Like mana filter, only also allow tap symbols:
tap_filter := sort_text@(order: "<TQ>")
mana_filter_t := replace@(               # Remove [] used for forcing mana symbols
			match: "[\\[\\]]",
			replace: ""
		) + { tap_filter() + mana_filter() }


############################################################## Determine card color

# Names of colors
color_name := {
	if      input == "W" then "white"
	else if input == "U" then "blue"
	else if input == "B" then "black"
	else if input == "R" then "red"
	else if input == "G" then "green"
	else                     ""
}
color_names_1 := { color_name(colors.0) }
color_names_2 := { color_name(colors.0) + ", " + color_name(colors.1) }
color_names_3 := { color_name(colors.0) + ", " + color_name(colors.1) + ", " + color_name(colors.2) }
color_names_4 := { color_name(colors.0) + ", " + color_name(colors.1) + ", " + color_name(colors.2) + ", " + color_name(colors.3) }
color_names_5 := { color_name(colors.0) + ", " + color_name(colors.1) + ", " + color_name(colors.2) + ", " + color_name(colors.3) + ", " + color_name(colors.4) }
# color based on mana cost, input = a mana cost
color_filter  := sort_text@(order: "<WUBRG>")
color_filterH := sort_text@(order: "</>")
mana_to_color := {
	count  := number_of_items(in: colors)
	if hybrid == "" and contains(type, match:"Artifact") then
		# not a hybrid, but artifact
		if      count == 0 then  "artifact"
		else if count == 1 then  color_names_1() + ", artifact"
		else if set.set_info.use_gradient_multicolor == "no"  then "artifact, multicolor" # stop here
		else if count == 2 then  color_names_2() + ", artifact, multicolor"
		else if set.set_info.use_gradient_multicolor != "yes" then "artifact, multicolor" # stop here
		else if count == 3 then  color_names_3() + ", artifact, multicolor"
		else if count == 4 then  color_names_4() + ", artifact, multicolor"
		else if count == 5 then  color_names_5() + ", artifact, multicolor"
		else                     "artifact, multicolor"
	else if hybrid == "" then
		# not a hybrid, not artifact
		if      count == 0 then  "colorless"
		else if count == 1 then  color_names_1()
		else if set.set_info.use_gradient_multicolor == "no"  then "multicolor" # stop here
		else if count == 2 then  color_names_2() + ", multicolor"
		else if set.set_info.use_gradient_multicolor != "yes" then "multicolor" # stop here
		else if count == 3 then  color_names_3() + ", multicolor"
		else if count == 4 then  color_names_4() + ", multicolor"
		else if count == 5 then  color_names_5() + ", multicolor"
		else                     "multicolor"
	else if contains(type, match:"Artifact") then
		# hybrid, but artifact
		if count == 0 then "artifact"
		else if count == 1 then color_names_1() + ", artifact"
		else if count == 2 then  color_names_2() + ", artifact"
		else                     "artifact, multicolor"
	else
		# hybrid, not artifact
		if count == 0 then "colorless"
		else if count == 1 then color_names_1()
		else if count == 2 then  color_names_2() + ", hybrid"
		else                     "multicolor"
}

# color based on land text box, input = textbox contents
color_text_filter :=
	# remove activation costs
	replace@(
		match: "<sym[^>]*>[^<]+</sym[^>]*>"
		in_context: "(?ix) (\\n|^)[^:]*<match>(,|:) | (pays?|additional|costs?)[ ]<match>",
		replace: ""
	) +
	# keep only mana
	filter_text@(match: "<sym[^>]*>([^<]+)") + color_filter;
# get the land frame for a "WUBRG"-style input.
land_multicolor := {
	count  := number_of_items(in: colors)
	if      count == 0 then "land"
	else if count == 1 then color_names_1() + ", land"
	else if count == 2 then color_names_2() + ", land"
	else                    "land, multicolor"
}
land_to_color := {
	# Based on watermark
	if      watermark == "mana symbol white" then "white, land"
	else if watermark == "mana symbol blue"  then "blue, land"
	else if watermark == "mana symbol black" then "black, land"
	else if watermark == "mana symbol red"   then "red, land"
	else if watermark == "mana symbol green" then "green, land"
	else land_multicolor(colors:color_text_filter(input: card.rule_text))
};

# Look for a CDA that defines colors
text_to_color := {
	# Note: running filter_text is quite slow, do a quick 'contains' check first
	if contains(match: card_name) then (
	  text := filter_text(match: "is (colorless|all colors|((blue|white|green|red|black)((,|,? and) (blue|white|green|red|black))*))", in_context: regex_escape(card_name)+"(</[-a-z]+>)* <match>\\.")
	  if text != "" then (
	    if contains(text, match: "all colors") then (
			colors := "WUBRG"
			if land == "land" then land_multicolor()
			else mana_to_color(hybrid: "")
	    ) else (
			colors := ""
			if contains(text, match: "white") then colors := colors + "W"
			if contains(text, match: "blue")  then colors := colors + "U"
			if contains(text, match: "black") then colors := colors + "B"
			if contains(text, match: "red")   then colors := colors + "R"
			if contains(text, match: "green") then colors := colors + "G"
			if land == "land" then land_multicolor()
			else mana_to_color(hybrid: "")
	    )
	  ) else (
		colors := ""
	  )
	) else (
		colors := ""
	)
};

# The color of a card
is_creature    := match@(match: "(?i)Creature")
is_tribal      := match@(match: "(?i)Tribal")
is_artifact    := match@(match: "(?i)Artifact")
is_land        := match@(match: "(?i)Land")
is_enchantment := match@(match: "(?i)Enchantment")
is_spell       := match@(match: "(?i)Instant|Sorcery")
card_color := {
	# usually the color of mana
	text_color := text_to_color(rules_text, land: is_land(type));
	if text_color == "" then (
		mana_color := mana_to_color(colors: color_filter(casting_cost), hybrid: color_filterH(casting_cost))
		if      mana_color == "colorless" and is_land    (type)  then land_to_color(watermark)
		else if mana_color == "colorless" and is_artifact(type)  then "artifact"
		else if mana_color == "colorless" and contains(card.shape, match:"flip") then default
		else mana_color
	)
	else text_color
};

# Number of colors in a card_color
card_color_color_count := count_chosen@(choices: "white,blue,black,red,green,artifact")
# Clean up color field
card_color_filter := {
	colors := card_color_color_count()
	if colors > 2 then
		input := remove_choice(choice: "overlay")
	if colors > 1 then (
		input := require_choice(choices: "multicolor, hybrid, land, artifact")
		input := exclusive_choice(choices: "multicolor, hybrid")
		input := require_exclusive_choice(choices: "horizontal, vertical, radial, overlay")
	) else
		input := remove_choice(choices: "radial, horizontal, vertical, overlay, hybrid, reversed")
	if chosen(choice:"overlay") then
		input := remove_choice(choice: "reversed")
	input
}

# needed by all style files anyway
include file: /magic-blends.mse-include/new-blends


############################################################## Card number

# Index for sorting, white cards are first, so white->A, blue->B, .. ,
# The code consists of 3 parts:
#   color,  shifted,   split
sort_index := {
	color_of_card() +
	(if contains(card.shape, match:"shifted") then "S" else " ") + # planeshifted cards come after normal ones
	(if contains(card.shape, match:"split")   then "S" else " ") + # split cards come after normal ones
	":"
}
# Process the name for sorting rules
sort_name :=
	# Remove "The", "A", and "And" at the beginning
	replace@(match: "^(The|An?) ", replace: "") +
	# Remove commas and apostrophes
	replace@(match: "(,|'|’)", replace: "") +
	# Remove bold and italic tags
	replace@(match: "(<b>|<i>|</b>|</i>)", replace: "") +
	# Make lowercase
	to_lower

is_multicolor := { chosen(choice: "multicolor") and input != "artifact, multicolor" }
is_null_cost  := { input == "" or input == "0" }
is_hybrid_cost := { contains(card.casting_cost, match: "W/") or contains(card.casting_cost, match: "U/") or contains(card.casting_cost, match: "B/") or contains(card.casting_cost, match: "R/") or contains(card.casting_cost, match: "G/") }
basic_land_sort := {
	if contains(card.name, match:"Plains")        then "MB"      # Plains
	else if contains(card.name, match:"Island")   then "MC"      # Islands
	else if contains(card.name, match:"Swamp")    then "MD"      # Swamps
	else if contains(card.name, match:"Mountain") then "ME"      # Mountains
	else if contains(card.name, match:"Forest")   then "MF"      # Forests
	else                                               "MA"      # other basic lands
}
hybrid_color_pair_sort := {
	colors := sort_text(casting_cost, order: "<WUBRG>")
	if not set.sort_hybrid_in_pairs then "HK"
	else if colors == "WU" then "HA"
	else if colors == "UB" then "HB"
	else if colors == "BR" then "HC"
	else if colors == "RG" then "HD"
	else if colors == "WG" then "HE"
	else if colors == "WB" then "HF"
	else if colors == "UR" then "HG"
	else if colors == "BG" then "HH"
	else if colors == "WR" then "HI"
	else if colors == "UG" then "HJ"
	else "HK"
}
multi_color_pair_sort := {
	colors := sort_text(casting_cost, order: "<WUBRG>")
	if not set.sort_multicolor_in_pairs then "GK"
	else if colors == "WU" then "GA"
	else if colors == "UB" then "GB"
	else if colors == "BR" then "GC"
	else if colors == "RG" then "GD"
	else if colors == "WG" then "GE"
	else if colors == "WB" then "GF"
	else if colors == "UR" then "GG"
	else if colors == "BG" then "GH"
	else if colors == "WR" then "GI"
	else if colors == "UG" then "GJ"
	else if contains(card.casting_cost, match:"/") then "GL"
	else "GK"
}
# A code for the color of the card
color_of_card := {
	card_color := card.card_color
	casting_cost := card.casting_cost
	type := card.super_type
	if contains(card.shape, match: "split") and
	   card_color != card.card_color_2 then "I"                              # Diff Color Splits
	else if chosen(choice: "land", card_color) then (                   # Lands
		if card.rarity != "basic land" then "L"                          # Nonbasic Land
		else basic_land_sort()                                           # Basic Land
	) else if is_null_cost(casting_cost) then (                         # Non-Land Cards with no or zero costs.
		if chosen(choice: "colorless", card_color) then "A"              # Clear Colorless
		else if chosen(choice: "hybrid", card_color)    then "HK"        # Hybrids
		else if is_multicolor(card_color)          then "GK"             # Multicolor
		else if chosen(choice:"white", card_color) then "B"              # White
		else if chosen(choice:"blue", card_color)  then "C"              # Blue
		else if chosen(choice:"black", card_color) then "D"              # Black
		else if chosen(choice:"red", card_color)   then "E"              # Red
		else if chosen(choice:"green", card_color) then "F"              # Green
		else                                            "J"              # Artifact
	) else (
		                                                            # Cards with costs.
		colors := sort_text(casting_cost, order: "<WUBRG>")
		if colors == "" and contains(type, match:"Artifact") then "J"    # Artifact
		else if colors == ""  then "A"                                   # Clear Colorless
		else if colors == "W" then "B"                                   # White
		else if colors == "U" then "C"                                   # Blue
		else if colors == "B" then "D"                                   # Black
		else if colors == "R" then "E"                                   # Red
		else if colors == "G" then "F"                                   # Green
		else if is_hybrid_cost() then hybrid_color_pair_sort()           # Hybrid (by pairs)
		else if contains(casting_cost, match:"/") and contains(type, match:"Artifact") then "I" # Hybrid Artifacts
		else                       multi_color_pair_sort()               # Multicolor (by pairs)
	)
}

rarity_sort := {
	if card.shape == "token" then "T1"
	else if card.shape == "emblem" then "T2"
	else if card.shape == "rulestip" then "T3"
	else if card.shape == "counter" then "T4"
	else if card.shape == "checklist" then "T5"
	else if is_masterpiece() then "T6"
	else if set.sort_special_rarity == "with the rest" or card.rarity != "special" then " "
	else "S"
}
set_filter := {
	# TODO: what about rulestips?
	if is_unsorted() then 
		{ is_unsorted() }
	if card.shape == "token" or card.shape == "emblem" then
		{ card.shape == "token" or card.shape == "emblem" }
	else if card.shape == "rulestip" then
		{ card.shape == "rulestip" }
	else if card.shape == "counter" then
		{ card.shape == "counter" }
	else if card.shape == "checklist" then
		{ card.shape == "checklist" }
	else if is_masterpiece() and card.shape != "token" and card.shape != "emblem" then
    		{ is_masterpiece() and card.shape != "token" and card.shape != "emblem" }
    	else if set.sort_special_rarity != "separate numbering" then
    		{ not is_unsorted() and card.shape != "token" and not is_masterpiece() and card.shape != "emblem" and card.shape != "rulestip" and card.shape != "counter" and card.shape != "checklist"}
    	else if card.rarity == "special" then
    		{ not is_unsorted() and card.shape != "token" and not is_masterpiece() and card.shape != "emblem" and card.shape != "rulestip" and card.shape != "counter" and card.shape != "checklist" and card.rarity == "special" }
    	else
    		{ not is_unsorted() and card.shape != "token" and not is_masterpiece() and card.shape != "emblem" and card.shape != "rulestip" and card.shape != "counter" and card.shape != "checklist" and card.rarity != "special" }
}

card_number := {
	position (
		of: card
		in: set
		order_by: { rarity_sort() + sort_index() + sort_name(card.name) }
		filter:   set_filter()
	) + 1
}
card_count := {
	number_of_items(in: set, filter: set_filter())
}

#Starting with M15, zero digits in card numbers should be shown up to three.
card_number_m15 := { (if card_number() < 100 then "0" else "") + (if card_number() < 10 then "0" else "") + card_number() }
card_count_m15 := { (if card_count() < 100 then "0" else "") + (if card_count() < 10 then "0" else "") + card_count() }

# used by pack scripts
is_token_card   := { card.shape == "token" or card.shape == "rulestip" or card.shape == "counter" or card.shape == "checklist" or card.shape == "emblem"}
is_shifted_card := { contains(card.shape, match:"shifted") }
is_masterpiece := { card.rarity == "masterpiece" }
is_nightbreak := { card.shape == "nightbreak" }


############################################################## Utilities for keywords

comma_count := filter_text@(match:",")
# Replace spaces by a spacer
separate_words := remove_tags + trim + replace@(match:" ", replace: {spacer})

# replaces — correctly
add := "" # default is nothing

# If the 'input' parameter is a mana costs, then adds 'add'
for_mana_costs := format_cost := {
	if input.separator_before == "—" and contains(input.param, match: " ") then (
		if comma_count(input.param) == "," then (
			if match(match: "^[DHSCTQXYZIWUBRG0-9/|]+,", input.param) then
				"{add}<param-cost>{combined_cost(input.param)}</param-cost>"
			else "<param-cost>{combined_cost(input.param)}</param-cost>"
		) else if contains(input.param, match: ",") then (
			if match(match: "^[DHSCTQXYZIWUBRG0-9/|]+,", input.param) then
				"{add}<param-cost>{long_cost(input.param)}</param-cost>"
			else "<param-cost>{long_nomana_cost(input.param)}</param-cost>"
		) else
			"<param-cost>{alternative_cost(input.param)}</param-cost>"
	) else
		"{add}<param-mana>{input.param}</param-mana>"
}

# Convert first character to lower case
alternative_cost := replace@(match:"^[A-Z]", replace: { to_lower() })
# Convert extra costs
long_cost := replace@(match:", [A-Z]", replace: { to_lower() } )
long_nomana_cost := replace@(match:"[A-Z]", replace: { to_lower() })
#
combined_cost := replace@(match:", [A-Z]", replace: { to_lower() })+
	replace@(match:",", replace:" and")+
	replace@(match:"^[DHSCTQXYZIWUBRG0-9/|]+", in_context: "(^|[[:space:]])<match>(?![a-z])", replace: "<sym-auto>&</sym-auto>")+
	replace@(match:"^[A-Z]", replace: { to_lower() })

long_dash := replace@(match:"-", replace:"—")

# Utilities for keywords

has_cc := { card.casting_cost != "" }

has_pt := { card.power != "" or card.toughness != "" }

contains_target := match@(match:"(?i)([^a-z]|^)target([^a-z]|$)")

is_spell := { contains(card.type, match:"Instant") or contains(card.type, match:"Sorcery") }

is_targeted := { contains_target(card.rule_text) }

color_to_mana := replace@(match: "white", replace: "[W]")+
	replace@(match: "blue", replace: "[U]")+
	replace@(match: "black", replace: "[B]")+
	replace@(match: "red", replace: "[R]")+
	replace@(match: "green", replace: "[G]")

############################################################## The text box

# Filters for the text box
# context in which mana symbols are found
mana_context :=
	"(?ix)				# case insensitive, ignore whitespace
	 (^|[[:space:]\"(“'])		# start of a word
	 (  <match>:			# G: something
	 |  <match>,			# G, tap: something
	 |  or[ ]<match>		# Add X, Y, or Z.
	 |  <match>[ ]to		# Add X, Y, or Z to your mana pool.
	 |  <match>[ ]was[ ]spent		# if G was spent to cast
	 |  <match>[ ]can[ ]be[ ]pay
	 |  (pays?|additional|costs?|the	# pay X. creatures cost 1 less. pay an additional G.
	    |adds?|pay(ed)?[ ](with|using)
	    )
	    ([ ]either)?			 # pay either X or Y
	    ([ ](<sym[^>]*>)?[DHSCTQXYZIEWUBRG0-9/|]+(</sym[^>]*>)?,)* # pay X, Y or Z
	    ([ ](<sym[^>]*>)?[DHSCTQXYZIEWUBRG0-9/|]+(</sym[^>]*>)?[ ](and|or|and/or))* # pay X or Y
	    [ ]<match>
	    ([,.)]|$				# (end of word)
	    |[ ][^ .,]*$			# still typing...
	    |[ ]( or | and | in | less | more | to ) # or next word is ...
	    )
	    )
	 |  <param-mana><match></param-mana>		# keyword argument that is declared as mana
	 |  <param-cost>[ ]*<match></param-cost>	# keyword argument that is declared as cost
	 |  <param-cost><match>,			# keyword argument that is declared as cost
	 ";


# truncates the name of legends
legend_filter := replace@(match:"(, | of | the ).*", replace: "" )

# these are considered a correct 'word' for spellchecking in the text box:
additional_text_words := match@(match:
	"(?ix)^(?:                         # match whole word
	  <atom-[^>]*>.*?</atom-[^>]*>     # cardnames and stuff
	| [+-]?[0-9X]+ / [+-]?[0-9X]+      # '3/3', '+X/+X'
	)$")

# the rule text filter
#  - adds mana symbols
#  - makes text in parentheses italic
text_filter :=
	# step 1 : remove all automatic tags
	remove_tag@(tag: "<sym-auto>") +
	remove_tag@(tag: "<i-auto>")   +
	remove_tag@(tag: "<b-auto>")   +
	remove_tag@(tag: "<error-spelling") +
	remove_tag@(tag: "<nospellcheck") +
	# step 2 : reminder text for keywords
	expand_keywords@(
		condition: {
			correct_case or (mode != "pseudo" and not used_placeholders)
		}
		default_expand: {
			chosen(choice:if correct_case then mode else "lower case", set.automatic_reminder_text)
		},
		combine: {
			keyword  := "<nospellcheck>{keyword}</nospellcheck>"
			reminder := process_english_hints(reminder)
			if mode == "pseudo" then "<i-auto>{keyword}</i-auto>"
			else keyword + if expand then "<atom-reminder-{mode}> ({reminder})</atom-reminder-{mode}>"
		}) +
	# step 2b : move action keywords' reminder text to the end of the line
	replace@(
		match: "(<atom-reminder-action>(?:(?!<kw-).)*</atom-reminder-action></kw[^>]*>)(((?!<atom-reminder| ?<kw-)[^\n(])+)",
		replace: "\\2\\1"
		) +
	# step 2c : remove duplicate reminder text
	replace@(
		match: "(<atom-reminder-[^>]*>[^)]+[)]</atom-reminder-[^>]*>)([^\n]+)\\1"
		replace: "\\2\\1"
		) +
	# step 3a : expand shortcut word CARDNAME
	replace@(
		match: "CARDNAME",
		in_context: "(^|[[:space:]]|\\()<match>", # TODO: Allow any punctuation before
		replace: "<atom-cardname></atom-cardname>"
		) +
	# step 3b : expand shortcut word LEGENDNAME
	replace@(
		match: "LEGENDNAME",
		in_context: "(^|[[:space:]]|\\()<match>", # TODO: Allow any punctuation before
		replace: "<atom-legname></atom-legname>"
		) +
	# step 3c : fill in atom fields
	tag_contents@(
		tag: "<atom-cardname>",
		contents: { "<nospellcheck>" + (if card_name=="" then "CARDNAME" else card_name) + "</nospellcheck>" }
		) +
	tag_contents@(
		tag: "<atom-legname>",
		contents: { "<nospellcheck>" + (if card_name=="" then "LEGENDNAME" else legend_filter(card_name)) + "</nospellcheck>" }
		) +
	# step 4 : explict non mana symbols
	replace@(
		match: "\\][DHSCTQXYZIWUBRG0-9/|]+\\[",
		replace: {"<nosym>" + mana_filter_t() + "</nosym>"} ) +
	# step 5 : add mana & tap symbols
	replace@(
		match: "\\b[DHSCTQXYZIWUBRG0-9/|]+\\b",
		in_context: mana_context,
		replace: {"<sym-auto>" + mana_filter_t() + "</sym-auto>"} ) +
	# step 5c : add explicit mana symbols
	replace@(
		match: "\\[[DHSCTQXYZIWUBRG0-9/|]+\\]",
		replace: {"<sym>" + mana_filter_t() + "</sym>"} ) +
	# step 6 : curly quotes
	(if set.curly_quotes then curly_quotes) +
	# step 7 : italicize text in parenthesis
	replace@(
	 	match: "[(]([^)\n]|[(][^)\n]*[)])*[)]?",
		in_context: "(^|[[:space:]])<match>|<atom-keyword><match></",
	 	replace: "<i-auto>&</i-auto>") +
	# step 8 : automatic capitalization, but not after "("
	replace@(
		match: "([ ]*: |—| — )" # preceded by this
		     + "([[:lower:]])" # match this
		     + "(?![)])",      # not followed by this
		replace: { _1 + to_upper(_2) }) +
	# step 9 : spellcheck
	{ if set.mark_errors then
		check_spelling(
			language: language().spellcheck_code,
			extra_dictionary: "/magic.mse-game/magic-words",
			extra_match: additional_text_words
		)
	  else input
	}


############################################################## Other boxes

# the flavor text filter
#  - makes all text italic
flavor_text_filter :=
	# step 1 : remove italic tags
	remove_tag@(tag: "<i-flavor>")   +
	# step 2 : surround by <i> tags
	{ "<i-flavor>" + input + "</i-flavor>" } +
	# curly quotes
	(if set.curly_quotes then curly_quotes) +
	# spellcheck
	{ if set.mark_errors
	  then check_spelling(language:language().spellcheck_code)
	  else input
	}

# Move the cursor past the separator in the p/t and type boxes
type_over_pt   := replace@(match:"/$", replace:"")
type_over_type := replace@(match:" ?[-:]$", replace:"")

super_type_filter := {
	input := remove_tag(tag: "<word-list-")
	input := type_over_type()
	tag := "word-list-type" # TODO: localize
	"<{tag}>{input}</{tag}>"
}

break_subtypes := split_text@(match: " +|<atom-sep>[^<]*</atom-sep>", include_empty:false)
sub_type_filter := {
	input := remove_tag(tag: "<word-list-")
	input := remove_tag(tag: "<soft")
	lang  := language()
	# What word list to use?
	list_type_rest := if      lang.is_creature(type)    then "class"
	                  else if lang.is_land(type)        then "land"
	                  else if lang.is_artifact(type)    then "artifact"
	                  else if lang.is_enchantment(type) then "enchantment"
	                  else if lang.is_spell(type)       then "spell"
	                  else if lang.is_planeswalker(type)       then "planeswalker"
					  else "";
	if list_type_rest != "" then (
		if lang.is_creature(type) or lang.is_tribal(type) then (
			list_type_first := "race"
		) else (
			list_type_first := list_type_rest
		);
		# wrap wordlist tag around each part
		parts := break_subtypes()
		(for each i:part in parts do
			if i == 0 then
				"<word-list-{list_type_first}>{part}</word-list-{list_type_first}>"
			else
				lang.subtype_separator + "<word-list-{list_type_rest}>{part}</word-list-{list_type_rest}>"
		) +
		(if length(parts) > 0 then
			# Add a new box at the end
			"<soft>{lang.subtype_separator}</soft><word-list-{list_type_rest}></word-list-{list_type_rest}>"
		 else
			"<word-list-{list_type_first}></word-list-{list_type_first}>"
		)
	) else input # do nothing
}

# all sub types, for word list
space_to_comma := replace@(match:" ", replace:",")
only_first     := replace@(match:" .*", replace:"")
only_next      := replace@(match:"^[^ ]* ?", replace:"")
all_sub_types := {
	for each card in set do
		if contains(card.super_type) then "," + space_to_comma(to_text(card.sub_type))
}
all_races := {
	for each card in set do
		if is_creature(card.super_type) or is_tribal(card.super_type) then
			"," + only_first(to_text(card.sub_type))
}
all_classes := {
	for each card in set do
		if contains(card.super_type, match:"Creature") then
			"," + space_to_comma(only_next(to_text(card.sub_type)))
}

# Determine a rarity code for M15 styles.
rarity_code := {
	if is_promo() then "P"
	else if is_masterpiece() then "S"
	else if contains(card.shape, match:"token") then "T"
	else if contains(card.shape, match:"emblem") then "E"
	else if card.rarity == "common" then "C"
	else if card.rarity == "uncommon" then "U"
	else if card.rarity == "rare" then "R"
	else if card.rarity == "mythic rare" then "M"
	else if card.rarity == "special" then "S"
	else if card.rarity == "basic land" then "L" 
	else "" 
};

# Determine if the card is a promo card.
is_promo := { "false" }

# Determine if the card is a rare.
is_rare := { card.rarity == "rare" or card.rarity == "mythic rare" or card.rarity == "masterpiece" }

# Shape of cards, can be changed in style files
card_shape := { "normal" }

typesymbol_for :=
	to_text +
	replace@(match: "(Legendary|Basic|Snow|World| )", replace: "") +
	{ if      input == "Creature"    then "creature"
	  else if input == "Sorcery"     then "sorcery"
	  else if input == "Instant"     then "instant"
	  else if input == "Artifact"    then "artifact"
	  else if input == "Enchantment" then "enchantment"
	  else if input == "Land"        then "land"
	  else if input == "Planeswalker" then "planeswalker"
	  else                                "multitype"
	}
typesymbol_type := { typesymbol_for(type) }

#Script to make magic-mana-future compatible w/ other templates
colorless_color := {
		if contains(card.card_color, match:"hybrid") or contains(card.card_color, match:"multicolor") then "c"
		else if card.card_color=="white" then "w"
		else if card.card_color=="blue" then "u"
		else if card.card_color=="black" then "b"
		else if card.card_color=="red" then "r"
		else if card.card_color=="green" then "g"
		else "c"
	}

#Indicators never appear if the indicator would be colorless, colorless land, or colorless artifact.
#Indicators do appear if the chosen frame doesn't match the default.
#Indicators do appear if the chosen color for the indicator doesn't match the default.

has_identity := { ( ( card.card_color != card_color(casting_cost: card.casting_cost, rules_text: card.rule_text, type: card.super_type, watermark: card.watermark, card_name: card.name, default: "colorless") ) or ( card.indicator != card_color(casting_cost: card.casting_cost, rules_text: card.rule_text, type: card.super_type, watermark: card.watermark, card_name: card.name, default: "colorless") ) ) and card.indicator != "colorless" and card.indicator != "artifact" and card.indicator != "land"}

has_identity_2 := { ( ( card.card_color_2 != card_color(casting_cost: card.casting_cost_2, rules_text: card.rule_text_2, type: card.super_type_2, watermark: card.watermark_2, card_name: card.name_2, default: "colorless") ) or ( card.indicator_2 != card_color(casting_cost: card.casting_cost_2, rules_text: card.rule_text_2, type: card.super_type_2, watermark: card.watermark_2, card_name: card.name_2, default: "colorless") ) ) and card.indicator_2 != "colorless" and card.indicator_2 != "artifact" and card.indicator_2 != "land"}

############################################################## Statistics utilities

# Converted mana cost
is_half_mana    := match@(match: "1/2|[|][WUBRGS]")
is_colored_mana := match@(match: "[WUBRG]")
only_numbers    := filter_text@(match: "^[0123456789]+")
cmc_split := break_text@(match: "(?ix) 1/2 | [|][WUBRG] | [0-9]+(?!/[WUBRGDHSCTQ2]) | [WUBRGDHS0-9](/[WUBRGDHS])\{0,4} ")
cmc := {to_number(
	for each sym in cmc_split(to_text()) do (
		numbers := only_numbers(sym)
		if is_half_mana(sym)  then 0.5
		else if numbers != "" then to_int(numbers)
		else                       1 # all other symbols are 1
	))
}

colored_mana := {to_number(
	for each sym in cmc_split(to_text()) do (
		numbers := only_numbers(sym)
		if is_colored_mana(sym) then
			if is_half_mana(sym) then 0.5 else 1
		else 0
	))
}

primary_card_color := {
	artifact := chosen(choice:"artifact") and not (chosen(choice:"white") or chosen(choice:"blue") or chosen(choice:"black") or chosen(choice:"red") or chosen(choice:"green"))
	land     := chosen(choice:"land")
	multi    := chosen(choice:"multicolor")
	hybrid   := chosen(choice:"hybrid")
	white    := chosen(choice:"white")
	blue     := chosen(choice:"blue")
	black    := chosen(choice:"black")
	red      := chosen(choice:"red")
	green    := chosen(choice:"green")
	if      land                                      then "land"
	else if multi                                     then "multicolor"
	else if hybrid                                    then "hybrid"
	else if artifact                                  then "artifact"
	else if white                                     then "white"
	else if blue                                      then "blue"
	else if black                                     then "black"
	else if red                                       then "red"
	else if green                                     then "green"
	else                                                   input
}
mainframe_stat_color := {
	artifact := chosen(choice:"artifact") and not (chosen(choice:"white") or chosen(choice:"blue") or chosen(choice:"black") or chosen(choice:"red") or chosen(choice:"green"))
	land     := chosen(choice:"land")
	multi    := chosen(choice:"multicolor")
	hybrid   := chosen(choice:"hybrid")
	white    := chosen(choice:"white")
	blue     := chosen(choice:"blue")
	black    := chosen(choice:"black")
	red      := chosen(choice:"red")
	green    := chosen(choice:"green")
	pink	 := chosen(choice:"pink")
	purple	 := chosen(choice:"purple")
	if      land                                      then "land"
	else if multi                                     then "multicolor"
	else if hybrid                                    then "hybrid"
	else if artifact                                  then "artifact"
	else if white                                     then "white"
	else if blue                                      then "blue"
	else if black                                     then "black"
	else if red                                       then "red"
	else if green                                     then "green"
	else if pink					  then "pink"
	else if purple					  then "purple"
	else                                                   input
}
is_mainframe := { false }
is_walker := { contains(card.super_type, match:"Planeswalker") }
mainframe_power := { card.power }
mainframe_toughness := { card.toughness }

word_count := break_text@(match:"[^[:space:]]+") + length
line_count := split_text@(match:"\n+",include_empty:false) + length

#Remove supertypes or types to look at parts of the super_type field by themselves.
remove_supertype := replace@(match: "(Legendary|Basic|Snow|World|Tribal|Token)", replace: "")+
	replace@(match: "[ ]+", in_context: "^<match>", replace: "")+
	replace@(match: "[ ]+", in_context: "<match>$", replace: "")
remove_type := replace@(match: "(Artifact|Creature|Enchantment|Instant|Land|Planeswalker|Sorcery)", replace: "")+
	replace@(match: "[ ]+", in_context: "^<match>", replace: "")+
	replace@(match: "[ ]+", in_context: "<match>$", replace: "")
node_script := { if card.shape == "double faced" then "transform day"  else "none" }
node_script_2 := {
	if card.mainframe_node == "transform day" then "transform night"
	else if card.mainframe_node == "transform night" then "transform day"
	else if card.mainframe_node == "transform moon" then "transform eldrazi"
	else if card.mainframe_node == "transform eldrazi" then "transform moon"
	else if card.mainframe_node == "transform sparker" then "transform aetherprint"
	else if card.mainframe_node == "transform aetherprint" then "transform sparker"
	else "none"	
}
card_new_color := {
	if card.card_color == "white" then "w"
	else if card.card_color == "blue" then "u"
	else if card.card_color == "black" then "b"
	else if card.card_color == "red" then "r"
	else if card.card_color == "green" then "g"
	else if contains(card.card_color, match:"artifact") then "a"
	else if contains(card.card_color, match:"multi") or contains(card.card_color, match:"hybrid") then "m"
	else "c"
}
spark_color := {
	if card.card_color == "white" then "w"
	else if card.card_color == "blue" then "u"
	else if card.card_color == "black" then "b"
	else if card.card_color == "red" then "r"
	else if card.card_color == "green" then "g"
	else if contains(card.card_color, match:"multi") or contains(card.card_color, match:"hybrid") then "m"
	else ""
}
card_spotlight := { "/magic-mainframe-watermarks.mse-include/spotlight/" + card_new_color() + "spotlight.png" }

ancestral_mana := { card.pt != "" and card.pt == "" }
exporter_check := { "no" }
custom_watermark_1 := { if set.custom_watermark_1 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_1 else "/magic-watermarks.mse-include/aetherprint3.png" }
custom_watermark_2 := { if set.custom_watermark_2 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_2 else "/magic-watermarks.mse-include/aetherprint3.png" }
custom_watermark_3 := { if set.custom_watermark_3 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_3 else "/magic-watermarks.mse-include/aetherprint3.png" }
custom_watermark_4 := { if set.custom_watermark_4 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_4 else "/magic-watermarks.mse-include/aetherprint3.png" }
custom_watermark_5 := { if set.custom_watermark_5 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_5 else "/magic-watermarks.mse-include/aetherprint3.png" }
is_unsorted := {"false"}