############################################################## Localization include file: language # needed by all style files anyway include file: /magic-blends.mse-include/new-blends include file: statistics_script ############################################################## version check version_date := {"2023-02-21"} ############################################################## Sorting mana symbols # correctly sort a mana symbol (no guild mana) mana_sort := sort_text@(order: "\\?XYZI[0123456789]VLHSFCAIE(WUBRG)") # correctly sort wedge mana mana_sort_wedge := sort_text@(order: "\\?XYZI[0123456789]VLHSFCAIE(WBGUR)") mana_unsort := sort_text@(order:"[/\\?XYZI0123456789VLHSCAIEWUBRG]") # correctly sort guild mana mana_sort_guild := sort_text@(order: "[\\?XYZI01234567890VLHSFCAIEWUBRG/|]") + replace@( # No lookbehind :( #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 := { chosen(set.mana_cost_sorting, choice: "tarkir wedge sorting") and ( number_of_items(in: sort_text(order:"", input), filter: "") == 3 ) } mana_has_wedge := { mana_is_wedge() and (sort_text(order:"", input) == "WUR" or sort_text(order:"", input) == "WBR" or sort_text(order:"", input) == "WBG" or sort_text(order:"", input) == "UBG" or sort_text(order:"", input) == "URG")} # convert card.card_color to WUBRG card_color_to_letters := { color_string := trim_colors(input) out_string := (if contains(color_string, match:"white") then "W" else "")+(if contains(color_string, match:"blue") then "U" else "")+(if contains(color_string, match:"black") then "B" else "")+(if contains(color_string, match:"red") then "R" else "")+(if contains(color_string, match:"green") then "G" else "") out_string } card_is_wedge := { color_string := card_color_to_letters(input) if color_string == "WUR" or color_string == "WBR" or color_string == "WBG" or color_string == "UBG" or color_string == "URG" then true else false } list_colors := { list := trim_colors(input) cc := length(comma_count(list)) if cc == 1 then list := replace(list, match:", ", replace:" and ") if cc > 1 then list := replace(list, match:", ", replace:", and ", in_context:"[^ ]+$") list } # A mana cost can contain both normal and guild mana mana_filter := to_upper + { if chosen(set.mana_cost_sorting, choice: "unsorted") then mana_unsort() else if mana_has_guild() then mana_sort_guild() else if mana_has_wedge(input) then mana_sort_wedge(input) else mana_sort() } # Like mana filter, only also allow tap symbols: tap_reduction := replace@(match:"T+", replace:"T")+ replace@(match:"Q+", replace:"Q") ticket_filter := ticket_isolate := filter_text@(match:"(TK)+") tap_filter := replace@(match:"(TK)+", replace:"")+ sort_text@(order: "") mana_filter_t := replace@( # Remove [] used for forcing mana symbols match: "[\\[\\]]", replace: "" ) + { tap_reduction(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 "" } mana_name := { if input == "white" then "W" else if input == "blue" then "U" else if input == "black" then "B" else if input == "red" then "R" else if input == "green" then "G" else "C" } 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: "") 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: "]*>[^<]+]*>" in_context: "(?ix) (\\n|^)[^:]*(,|:) | (pays?|additional|costs?)[ ]", replace: "" ) + # keep only mana filter_text@(match: "]*>([^<]+)") + 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: rules)) }@(rules: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 + " is") 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)+"()* \\.") if text != "" then ( if contains(text, match: "all colors") then ( colors := "WUBRG" if land == "true" 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 == "true" then land_multicolor() else mana_to_color(hybrid: "") ) ) else "" ) else "" } is_creature := match@(match: "(?i)Creature") is_creaturish := match@(match: "(?i)(Creature|Vehicle)") 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_aura := match@(match: "(?i)Aura") is_spell := match@(match: "(?i)Instant|Sorcery") is_sorcery := match@(match: "(?i)Sorcery") is_instant := match@(match: "(?i)Instant") is_planeswalker := match@(match: "(?i)Planeswalker") is_legendary := match@(match: "(?i)Legendary") match_vehicle := contains@(match:"Vehicle") match_snow := contains@(match:"Snow") # The color of a card 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, rules:rules_text) 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 }; ##todo check nil has_two_names := {contains(card.shape, match:"split") or contains(card.shape, match:"adventure") or contains(card.shape, match:"flip") or contains(card.shape, match:"double faced") or contains(card.shape, match:"aftermath")} # 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 } ############################################################## Card number # exportname exporter_name_filter := filter_text@(match:"!exporte?r?name [^\n!]+") exporter_name_grabber := replace@(match:"!exporte?r?name ", replace:"") export_name := { exporter_name_grabber(exporter_name_filter(card.notes))} # 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 "An" at the beginning replace@(match: "^(The|An?) ", replace: "") + # Remove commas and apostrophes replace@(match: "(,|'|’)", replace: "") + # Remove bold and italic tags replace@(match: "(|||)", 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: "") 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: "") 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: "") 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" } card_partition := {"A"} over_partition := { my_pos := number_partition() mn_pos := if set.last_main_partition == "" then "M" else to_upper(substring(set.last_main_partition, end:1)) posis := [my_pos, mn_pos] higher := sort_list(posis).0 my_pos != higher } number_partition := { to_upper(substring(card_partition(), end:1)) } set_filter := { # TODO: what about rulestips? if is_unsorted() then { is_unsorted() } else 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 over_partition() and 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 over_partition() and 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 over_partition() and 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_offset := {pull_comma_array(set.card_number_offsets, cell:0, end:false, default:0)} set_number_offset := {pull_comma_array(set.card_number_offsets, cell:1, end:false, default:0)} card_number := { position ( of: card in: set order_by: { number_partition() + rarity_sort() + sort_index() + sort_name(card.name) + sort_name(export_name())} filter: set_filter() ) + 1 + to_number(card_number_offset()) } card_count := { number_of_items(in: set, filter: set_filter()) + to_number(set_number_offset()) } #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() } #Starting with MOM, zero digits in card numbers should be shown up to four card_number_mom := { (if card_number() < 1000 then "0" else "") + (if card_number() < 100 then "0" else "") + (if card_number() < 10 then "0" else "") + card_number() } card_number_script_core := { if is_unsorted() or not set.automatic_card_numbers then combined_editor(field1: card.custom_card_number, separator: " " + rarity_code() + " ", field2: card.card_code_text) else if set.card_number_style == "0001" then forward_editor(prefix: rarity_code() + " " + card_number_mom() + " ", field: card.card_code_text) else if set.card_number_style == "001/099" then forward_editor(prefix: card_number_m15() + (if over_partition() then "" else "/" + card_count_m15()) + " " + rarity_code() + " ", field: card.card_code_text) else if set.card_number_style == "001" then forward_editor(prefix: card_number_m15() + " " + rarity_code() + " ", field: card.card_code_text) else if set.card_number_style == "1/99" then forward_editor(prefix: card_number() + (if over_partition() then "" else "/" + card_count()) + " " + rarity_code() + " ", field: card.card_code_text) else forward_editor(prefix: card_number() + " " + rarity_code() + " ", field: card.card_code_text) } # 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 trim_reminder_x := replace@(match: ". X can’t be 0.", replace: "") # If the 'input' parameter is a mana costs, then adds 'add' for_mana_costs := { if input.separator_before == "—" and contains(input.param, match: " ") then ( ##multi word if comma_count(input.param) == "," then ( ##two part if match(match: "^[VLHSCAIETKQ\\?XYZIWUBRG0-9/|]+,", input.param) then ##starts with mana "{add}{alternative_cost(input.param, trim:combined_cost, s:action)}" ##"add" mana else "{alternative_cost(input.param, trim:combined_cost, s:action)}{non}" ## else cost "non" ) else if contains(input.param, match: ",") then ( ##three+ parts if match(match: "^[VLHSCAIETKQ\\?XYZIWUBRG0-9/|]+,", input.param) then ##starts with mana "{add}{alternative_cost(input.param, trim:long_cost, s:action)}" ##"add" mana with long formatting else "{alternative_cost(input.param, trim:long_nomana_cost, s:action)}{non}" ## else cost "non" with long formatting ) else "{alternative_cost(input.param, s:action, trim:lower_first)}{non}" ##one, nonmana, part ) else if match(match: "^[VLHSCAIETKQ\\?XYZIWUBRG0-9/|]+$", input.param) then ##one word "{add}{input.param}" ##mana else "{alternative_cost(input.param, trim:combined_cost, s:action)}{non}" ##nonmana }@(non:" in addition to any other costs", action:false) # Convert extra costs long_cost := replace@(match:", [A-Z]", replace: { to_lower() } ) long_nomana_cost := replace@(match:"[A-Z]", replace: { to_lower() }) # Convert first character to lower case lower_first := replace@(match:"^[A-Z]", replace: { to_lower() }) combined_cost := replace@(match:", [A-Z]", replace: { to_lower() })+ replace@(match:",", replace:" and")+ replace@(match:"^[VLHSCETKQ\\?XYZIWUBRG0-9/|]+", in_context: "(^|[[:space:]])(?![a-z])", replace: "&")+ replace@(match:"^[A-Z]", replace: { to_lower() }) alternative_cost := { input := trim(input) if s then input := actionize(input) input }@(trim: lower_first, s:false, trim:{input}) actionize := replace@(match:"(activate|ante|cast|choose|create|destroy|discard|double|draw|exchange|exile|fight|mill|play|put|regenerate|return|reveal|sacrifice|shuffle|tap|untap|transform|vote|exert|pay)(?=($| |,|\\.))", replace:"\\1s") +replace@(match:"(attach)", replace:"\\1es") +replace@(match:"scry", replace:"scries") +replace@(match:"your", replace:"their") # protection_code := { output := if match(input, match:"(artifacts|creatures|enchantments|instants|lands|planeswalkers|sorceries|tribals|planes|schemes|emblems|conspiracies|^[A-Z]|^[^ ]* named)") then replace(input, match:"and from", replace:"or", in_context:" ") else if match(input, match:"^(converted|mana|power|toughness)") then "anything with " + replace(input, match:"and from", replace:"or", in_context:" ") else if contains(input, match:"the chosen player") then "anything " + replace(input, match:"the chosen", replace:"controlled by that") else if contains(input, match:"the chosen") then "anything with " + replace(input, match:"the chosen", replace:"that") else if contains(input, match:"all colors") then "anything " + replace(input, match:"all colors", replace:"that's white, blue, black, red, or green") else if match(input, match:"^you$") then "anything you control" else if match(input, match:"^its owner$") then "anything its owner controls" else if match(input, match:"^(each of )?your opponents$") then "anything " + replace(input, match:"(each of )?your opponents", replace:"controlled by those players") else if match(input, match:"(the|a) [^\n]* of your choice") then "anything " + replace(input, match:"(the|a) ([^\n]*) of your choice", replace:"of that \\2") else if input == "colorless" then "anything colorless" else "anything " + replace(english_singular(input), match:"and from", replace:"or", in_context:" ") output := " targeted, dealt damage, enchanted, equipped by " + output if match(output, match:"(artifacts|creatures|instants|lands|planeswalkers|sorceries|tribals|planes|schemes|emblems|conspiracies|by [A-Z])") and not match(output, match:"(enchantmentsAura|Curse)") then output := replace(output, match:", enchanted", replace:"") else output := output if match(output, match:"(enchantments|creatures|instants|lands|planeswalkers|sorceries|tribals|planes|schemes|emblems|conspiracies|by [A-Z])") and not match(output, match:"(artifacts|Equipment)") then output := replace(output, match:" equipped", replace:"") else output := output if match(output, match:"equipped by") then output := replace(output, match:"equipped by", replace:"or equipped by") else if match(output, match:"enchanted, by") then output := replace(output, match:"enchanted, by", replace:"or enchanted by") else if match(output, match:"dealt damage, by") then output := replace(output, match:"dealt damage, by", replace:"or dealt damage by") else "" if match(output, match:"^ targeted, or dealt damage by") then output := replace(output, match:"^ targeted, or dealt damage by", replace:" targeted or dealt damage by") if match(output, match:"anything [A-Z]") then output := replace(output, match:"anything ", replace:"") if match(output, match:"or les") then output := replace(output, match:"or les$", replace:"or less") if match(output, match:"(anything )?everything") then output := replace(output, match:"(anything )?everything", replace:"anything") output := (if self_pro_check(card.text) then "You can't be" else if is_spell(card.type) then "It can't be blocked," else if is_creaturish(card.type) then "This creature can't be blocked," else "This permanent can't be") + output output } self_pro_check := match@(match:"You ha(ve|s) protection") craft_code := { [ "en": { ## beginning rem := param2.value + ", Exile this artifact, Exile "; ## check if a number is given count := filter_text(param1.value, match:"^(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|thirty|forty|fifty|sixty|seventy|eighty|ninety|[0-9]+)(-(one|two|three|four|five|six|seven|eight|nine))? (or more)?"); ## replace trailing space count := trim(count) ## check how many commas are given commas := filter_text(param1.value, match:","); ## check if this starts with a vowel vowel := match(param1.value, match:"^[aeiouAEIOU]"); ## if we have a comma separated list, use the number of elements as the count ## this doesn't support like, Craft with two Islands and two Mountains ## you've done that to yourself if commas != "" then count := english_number(length(commas)+1); ## unused style (craft with three) #### param1 == "three" count == "three" ## counting style (craft with one or more); (craft with six artifacts) #### param1 == "one or more" count == "one"; param1 == "six artifacts" count == "six" ## singular style (craft with creature) #### param1 == "creature" count == "" if count == param1.value then ( ## Exile three other... rem := rem + param1.value + " other permanents you control and/or cards from your graveyard: " ) else if count != "" then ( ## Exile one or more from among... ## Exile the six from among... rem := rem + (if count == "one or more" then param1.value else "the " + count) + " from among other permanents you control and/or cards in your graveyard: " ) else ( ## Exile another creature you control or... rem := rem + "another " + param1.value + " you control or " + (if vowel then "an " else "a ") + param1.value + " card from your graveyard: " ) ## ending and return rem := rem + "Return this card transformed under its owner's control. Craft only as a sorcery." rem }, "de": { ## beginning rem := param2.value + ", schnicke dieses Artefakt ins Exil, schicke "; ## check if a number is given count := filter_text(param1.value, match:"^(zwanzig|dreiβig|vierzig|fünfzig|sechzig|siebzig|achtzig|neunzig|eine[mr]|eins?|zwei|drei|vier|fünf|sechs?|sieben|sieb|acht|neun|zehn|elf|zwölf|[0-9]+)(und)?(zehn|zwanzig|dreiβig|vierzig|fünfzig|sechzig|siebzig|achtzig|neunzig)?( oder mehr(eren)?)? ?"); ## save the thing we're exiling target := trim(replace(param1.value, match:count, replace:"")) alt_target := if length(target) > 15 then "Permanente" else target ## format count count := replace(count, match:"eine[mr]", replace:"eins") count := trim(count) ## check how many commas are given commas := filter_text(param1.value, match:","); ## check if this starts with a vowel vowel := match(target, match:"^[aäeiouüAÄEIOUÜ]"); ## if we have a comma separated list, use the number of elements as the count ## this doesn't support eg Craft with two Islands and two Mountains ## you've done that to yourself if commas != "" then ( count := german_number(length(commas)+2); alt_target := "Permanente" ) ## unused style (craft with three) #### param1 == "three" count == "three" ## counting style (craft with one or more); (craft with six artifacts) #### param1 == "one or more" count == "one"; param1 == "six artifacts" count == "six" ## singular style (craft with creature) #### param1 == "creature" count == "" if count == param1.value then ( ## Exile three other... rem := rem + param1.value + " weiteren Permanente, die du kontrollierst und/oder Karten aus deinem Friedhof ins Exil: " ) else if count != "eins" then ( ## with one or more... ## with four or more ## with two+... rem := rem + ( if count == "eins oder mehreren" then "ein oder mehrere weitere " else if contains(count, match:"oder") then "die " + count + " weireren " else "die " + count + " oder mehr weiteren " ## todo this should list the denumbered param1.value instead ) + alt_target + (if vowel then ", das du" else ", die du") + " kontrollierst und/oder Karten aus deinem Friedhof ins Exil: " ) else ( ## with einem Artefakt ## with einem Kreatur rem := rem + (if target == "Artefakt" then "ein weiteres " else "ein ") + target + ", " + (if vowel then "das du" else "die du") + " kontrollierst, oder " + (if vowel then "eines " else "eine ") + target + (if target == "Kreatur" then "en-karte" else "-karte") +" aus deinem Friedhof ins Exile: " ) ## ending and return rem := rem + "Bringe diese Karte transformiert unter der Kontrolle ihres Besitzers ins Spiel zurück. Spiele Anfertigung wie eine Herexi." rem } ][lang_setting("code") or else "en"]() } 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]|^)targets?([^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]") digital_map := [ "zero": 0, "one": 1, "once": 1, "a": 1, "an": 1, "two": 2, "twice": 2, "three": 3, "thrice": 3, "four": 4, "five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10, "eleven": 11, "twelve": 12, "thirteen": 13, "fourteen": 14, "fifteen": 15, "sixteen": 16, "seventeen": 17, "eighteen": 18, "nineteen": 19, "twenty": 20, "thirty": 30, "forty": 40, "fifty": 50, "sixty": 60, "seventy": 70, "eighty": 80, "ninety": 90 ] iterate_fix := remove_tags +replace@(match: "^\\.", replace:"") +replace@(match: "^,", replace:"") +replace@(match: "^[ ]", replace:"") +replace@(match:" times", replace:"") iterate_digits := { trimmed := iterate_fix(input) if trimmed == "" then 1 else digital_map[trimmed] or else trimmed } digital_number := { input := replace(input, match:"up to ", replace:"") result := input two_part := filter_text(input, match:"(twenty|thirty|forty|fifty|sixty|seventy|eighty|ninety)") one_part := filter_text(input, match:"(zero|a|an|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen)\\b") if two_part != "" and one_part != "" then result := (digital_map[two_part] + digital_map[one_part]) or else input else if two_part != "" then result := digital_map[two_part] or else input else if one_part != "" then result := digital_map[input] or else input result } reverse_elements := {for element from 1 to length(input) do input[length(input) - element] + " "} ######################## Level Margins #### these will be determined by the style affecting the margins and otherwise be 0 margin_left := {0} margin_right := {0} margin_top := {0} remove_margins := replace@( match: "", replace:"" ) ##remove 0 margins and margins with no text cull_margins := replace@(match:"", replace:"")+ replace@(match:"", replace:"") #### this gives a big array so we can grab_margins["lv1"] etc anywhere grab_margins := {[ lv1: [margin_left("lv1"), margin_right("lv1"), margin_top("lv1")], lv2: [margin_left("lv2"), margin_right("lv2"), margin_top("lv2")], lv3: [margin_left("lv3"), margin_right("lv3"), margin_top("lv3")], lv4: [margin_left("lv4"), margin_right("lv4"), margin_top("lv4")], lv5: [margin_left("lv5"), margin_right("lv5"), margin_top("lv5")], lv6: [margin_left("lv6"), margin_right("lv6"), margin_top("lv6")], lv7: [margin_left("lv7"), margin_right("lv7"), margin_top("lv7")], lv8: [margin_left("lv8"), margin_right("lv8"), margin_top("lv8")], text: [margin_left("text"), margin_right("text"), margin_top("text")], text2: [margin_left("text2"), margin_right("text2"), margin_top("text2")], text3: [margin_left("text3"), margin_right("text3"), margin_top("text3")], text4: [margin_left("text4"), margin_right("text4"), margin_top("text4")], text5: [margin_left("text5"), margin_right("text5"), margin_top("text5")], text6: [margin_left("text6"), margin_right("text6"), margin_top("text6")], unknown: [0,0,0] ]} #### then with apply_margins(field, name:fieldname), add the margins into the text apply_margins := { margin_data := grab_margins()[name] or else [0,0,0] cull_margins("" + remove_margins(input) + "") } is_modal := contains@(match:"
  • ") bump_text := { blocks := split_text(input, match:"\n"); new_text := blocks[0]; for x from 1 to length(blocks)-1 do new_text := new_text + "\n" + bumper(blocks[x]) new_text } bumper := { #if this text isn't modal, at a 5 px margin if is_modal(input) then input else cull_margins("" + remove_margins(input) + "") } inserts_values := { split_text(set.inserts+";;;;;;;;;", match:";") } ############################################################## 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 ( : # G: something | , # G, tap: something | or[ ] # Add X, Y, or Z. | [ ]to[ ]your # Add X, Y, or Z to your mana pool. | you[ ]get[ ] # You get E, you get TK | [ ]was[ ]spent # if G was spent to cast | [ ]can[ ]be[ ]paid | (pays?|additional|costs?|the|adds?|pay(ed)?[ ](with|using)) # pay X. creatures cost 1 less. pay an additional G. ([ ]either)? # pay either X or Y ([ ](]*>)?[-+=]?[VLHSCETKQ\\?XYZIEWUBRG0-9/|]+(]*>)?,)* # pay X, Y or Z ([ ](]*>)?[-+=]?[VLHSCETKQ\\?XYZIEWUBRG0-9/|]+(]*>)?[ ](and|or|and/or))* # pay X or Y [ ] ( [,.)\"”]|$ # (end of word) | [ ][^ .,]*$ # still typing... | [ ]( or | and | in | less | more | to ) # or next word is ... ) ) | # keyword argument that is declared as mana | [ ]* # keyword argument that is declared as cost | , # keyword argument that is declared as cost "; mana_un_context := "(mana values? |converted mana costs? | life)" # truncates the name of legends legend_filter := replace@(match:"(, | of | the | \"| “).*", replace: "" ) # does this frame support Alchemy Rebalanced name symbol? alch_compatible := {false} # these are considered a correct 'word' for spellchecking in the text box: additional_text_words := match@(match: "(?ix)^(?: # match whole word ]*>.*?]*> # cardnames and stuff | [+-]?[0-9X]+ / [+-]?[0-9X]+ # '3/3', '+X/+X' )$") # the rule text filter # - adds mana symbols # - makes text in parentheses italic equip_filter := replace@(match:"This creature", replace:"It") +replace@(match:"this creature", replace:"it") this_or_that := { this := "this" that := "that" type := input if input == "type" then type := to_lower(main_type(card.type)) else if is_creaturish(card.type) then type := "creature" if type == "" then type := "permanent" if upper then ( this := "This" that := "That" ) if(type == "land" and not is_land(card.type)) then type := "permanent" this_that := this if ((input == "creature" and not is_creaturish(card.type)) or is_spell(card.type)) then this_that := that this_that + " " + type }@(upper:false) softline_ripper := replace@(match:"", replace:"") auto_correct := replace@(match:" it’s (controller|owner|power|toughness|converted|other)", replace:" its \\1") +replace@(match:"Then, if" replace:"Then if") +replace@(match:"([Ff]irst|[Dd]ouble) Strike" replace:"\\1 strike") +replace@(match:"Splice (Ont|unt|int)" replace:"Splice ont") +replace@(match:"(ecomes?) the Monarch" replace:"\\1 the monarch") +replace@(match:"does (combat|[X0-9]+) damage" replace:"deals \\1 damage") +replace@( match: "(gains |gain |have |has )" # preceded by this + "()" # inside a kw + "([A-Z])" # match this replace: { _1 + _2 + to_lower(_3)}) auto_errata := replace@(match:"converted mana cost", replace:"mana value") +replace@(match:"(?i)(Totem armor|Totembeistand|Armadura tótem|totémique|Armatura totem|Armadura de totem|族霊鎧|替身甲)", replace:{errata_map[_1] or else _1}) +replace@(match:"hen shuffle your library", replace:"hen shuffle") +replace@(match:"this (?:ability )?(?:only )?(?:any ?time you could cast|as) a", in_context: "(Activate|Play) n? (instant|sorcery)", replace:"only as a") errata_map := [ "Totem armor": "Umbra armor", "Totem Armor": "Umbra armor", "totem armor": "umbra armor", "Totembeistand": "Schattenbeistand", "totembeistand": "schattenbeistand", "Armadura tótem": "Armadura umbra", "armadura tótem": "armadura umbra", "Armure totémique": "Armure d’ombre", "armure totémique": "armure d’ombre", "Armatura totem": "Armatura essenza", "armatura totem": "armatura essenza", "族霊鎧": "陰影鎧", "替身甲": "本影甲", "Armadura de totem": "Armadura de sombra", "armadura de totem": "armadura de sombra" ] ex_test := { expand_keywords( input, condition: { correct_case or (mode != "pseudo" and not used_placeholders) } default_expand: { chosen(choice:if correct_case or mode == "action" then mode else "lower case", set.automatic_reminder_text) and chosen(choice:mode, set.automatic_reminder_text) }, combine: { keyword := "{keyword}" reminder := process_english_hints(if has_pt() then reminder else equip_filter(reminder)) if mode == "pseudo" then "{keyword}" else keyword + if expand then " ({reminder})" else "" }, margin_code: margin_code ) } text_filter := # step 1 : remove all automatic tags remove_tag@(tag: "") + remove_tag@(tag: "") + remove_tag@(tag: "") + remove_tag@(tag: "") + remove_tag@(tag: "") + remove_tag@(tag: "", replace:"BOLDAROUND" )+ replace@( match:"", replace:"ITALAROUND" )+ replace@( match:"", replace:"SYMAROUND" )+ # 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 or mode == "action" then mode else "lower case", set.automatic_reminder_text) and chosen(choice:mode, set.automatic_reminder_text) }, combine: { keyword := "{keyword}" reminder := process_english_hints(reminder) if mode == "pseudo" then "{keyword}" else keyword + if expand then " ({reminder})" else "" }) + # step 2ba : apply face_code replace@( match: "face_(.*?)_end", replace: {face_code(_1)} )+ # step 2b : move action keywords' reminder text to the end of the line replace@( match: "(]+> (?:(?!]+>]*>)([^\n]*)", #######removed "| ?]+> (?:(?!]+>]*>)([^\n]*?)(]+> (?:(?!]+>]*>)([^\n]*)", replace: "\\2\\4\\3\\1" ) + # step 2c : allow a sentence after lowercase reminder text for equips etc. #replace@( # match: "(]+>[a-z][^<]+)((?:(?!]*>)([^\n]+)$", # replace: "\\1\\3\\2" # ) + # step 2d : remove duplicate reminder text replace@( match: "(]*>[^)]+[)]]*>)([^\n]+)\\1" replace: "\\2\\1" ) + # step 2e : combine reminder texts replace@( match: "[)](]+>]>]+> )[(]" replace: "\\1" ) + # step 2f : temp fix for formatting buttons replace@( match:"BOLDAROUND", replace:"" )+ replace@( match:"ITALAROUND", replace:"" )+ replace@( match:"SYMAROUND", replace:"" )+ replace@( match:"-\n-" replace:"\n" )+ # step 3a : expand shortcut word CARDNAME replace@( match: "CARDNAME>?", in_context: "(^|[[:space:]]|\\(|,|\\.|:|“|\"|'|‘|-|—|/|​)", # TODO: Allow any punctuation before replace: "" ) + # step 3b : expand shortcut word LEGENDNAME replace@( match: "LEGENDNAME>?", in_context: "(^|[[:space:]]|\\(|,|\\.|:|“|\"|'|‘|/|​)", # TODO: Allow any punctuation before replace: "" ) + # step 3c : fill in atom fields tag_contents@( tag: "", contents: { "" + (if card_name=="" then "CARDNAME" else strip_card_codes(card_name)) + "" } ) + tag_contents@( tag: "", contents: { "" + (if card_name=="" then "LEGENDNAME" else legend_filter(strip_card_codes(card_name))) + "" } ) + replace@( match: "INS([1-9])", in_context: "(^|[[:space:]]|\\(|,|\\.|:|“|\"|'|‘|/|​)", replace: "" ) + { out := input for x from 1 to 9 do out := tag_contents(out, tag: "", contents: { "" + (if inserts_values()[x-1] == "" then "INS"+x else inserts_values()[x-1]) + "" } ) out } + # step 4 : explict non mana symbols replace@( match: "\\][-+=]?[VLHSCETQ\\?XYZIWUBRG0-9/|]+\\[", replace: {"" + mana_filter_t() + ""} ) + # step 5 : add mana & tap symbols replace@( match: "([+=-][XYZ0-9/|]+)", in_context: mana_context, replace: {"" + _1 + ""} ) + replace@( match: "\\b((TK)+)(T)?\\b", in_context: mana_context, replace: {"" + _1 + "" + _3}) + replace@( match: "\\b[VLHSCETQ\\?XYZIWUBRG0-9/|]+\\b", in_context: mana_context, replace: {"" + mana_filter_t() + ""} ) + # step 5b : remove false positive mana & tap symbols replace@( match: "([VLHSCETQ\\?XYZIWUBRG0-9/|]+)", in_context: mana_un_context, replace: "\\1" ) + # step 5c : add explicit mana symbols replace@( match: "\\[[-+=]?[VLHSCETQE\\?XYZIWUBRG0-9/|]+\\]", replace: {"" + mana_filter_t() + ""} ) + # step 6 : curly quotes {if set.curly_quotes then curly_quotes(input) else input} + # step 7 : italicize text in parenthesis replace@( match: "[(]([^)\n]|[(][^)\n]*[)])*[)]?", in_context: "(^|[[:space:]])|&") + # step 7b : indent bullets replace@( match: "^(• )([^•]+)", replace: {"
  • " + _1 + "" + _2 + "
  • "} )+ # step 7c : clean up modals { if is_modal(input) then bump_text(softline_ripper(input)) else input }+ # 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.auto_correct then auto_correct(input) else input } + { if set.auto_errata then auto_errata(input) else input } + { if language().code == "ja" or language().code == "zht" or language().code == "zhs" then input else if set.mark_errors then check_spelling( language: language().spellcheck_code, extra_dictionary: "/magic.mse-game/dictionary/magic-words", extra_match: additional_text_words ) else input } modal_lines := replace@(match:"", replace:"") +replace@(match:"(.+)", replace:"\\1") modal_text_filter := text_filter + modal_lines ############################################################## Other boxes # the flavor text filter # - makes all text italic flavor_text_filter := # step 1 : remove italic tags remove_tag@(tag: "") + # step 2 : surround by tags { "" + input + "" } + # curly quotes {if set.curly_quotes then curly_quotes(input) else input} + # 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: "{input}" } split_at_spaces := split_text@(match: " +") remove_leading_spaces := replace@(match: "^ +", replace: "") sub_type_filter := { subtype_separator := lang_setting("subtype_separator") code := lang_setting("code") input := replace(input, match: "" + subtype_separator + "", replace: "") input := remove_tag(input, tag: "" + sub_type + "" else "" + sub_type + "" ) else ( ### Check for single word sub types split := split_at_spaces(input) input := if length(split) > 1 then replace(input, match: "^" + regex_escape(split.0), replace: "") else "" if i == 0 then "" + split.0 + "" else "" + split.0 + ""))) ) ### Add separators between types, keep additional spaces if there are more than one sub_types := replace(sub_types, match: "(]*>)( *)(" else sub_types + "" + subtype_separator + "" ) else input ### Do nothing if we don't know the type } # 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 lang_setting(setting)(card.super_type) then "," + space_to_comma(to_text(card.sub_type)) else "" } all_races := { for each card in set do if lang_setting("is_creature")(card.super_type) or lang_setting("is_kindred")(card.super_type) then "," + only_first(to_text(card.sub_type)) else "" } all_classes := { for each card in set do if lang_setting("is_creature")(card.super_type) then "," + space_to_comma(only_next(to_text(card.sub_type))) else "" } # Determine a rarity code for M15 styles. rarity_code := { if not set.rarity_codes then "" else 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_half_generic := match@(match: "1/2") is_colored_mana := match@(match: "[WUBRG]") only_numbers := filter_text@(match: "^[0123456789]+") cmc_split := break_text@(match: "(?ix) 1/2 | [|][WUBRGC] | TK | [0-9](/[WUBRGCVLHSCETQ2]) | [0-9]+(?!/[WUBRGCVLHSCETQ2]) | [WUBRGCVLHS0-9](/[WUBRGCVLHS])\{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 )) } mana_value := cmc write_wubrg := { (if match(input, match:"white") then "W" else "")+ (if match(input, match:"blue") then "U" else "")+ (if match(input, match:"black") then "B" else "")+ (if match(input, match:"red") then "R" else "")+ (if match(input, match:"green") then "G" else "") } 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 )) } generic_mana := {to_number( for each sym in cmc_split(to_text()) do ( numbers := only_numbers(sym) if is_half_generic(sym) then 0.5 else if numbers != "" then to_int(numbers) else 0 # all other symbols are 1 )) } 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") multi_color := count_chosen(choices:"white, blue, black, red, green") if land then "land" else if multi then "multicolor" else if multi_color == 2 and chosen(choice:"artifact") then "hybrid" ##hybrid artifacts would show as their first color 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") } is_legend := { true } mainframe_walker := {false} mainframe_walker_text_script := {combined_editor(field1: card.level_1_text, separator1: "\n", field2: card.level_2_text, separator2: "\n", field3: card.level_3_text)} mainframe_walkerb := {false} mainframe_walker_text_scriptb := {combined_editor(field1: card.level_5_text, separator1: "\n", field2: card.level_6_text, separator2: "\n", field3: card.level_7_text)} alt_text := {false} alt_text_script := {false} alt_textb := {false} alt_text_scriptb := {false} 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: "^", replace: "")+ replace@(match: "[ ]+", in_context: "$", replace: "") remove_type := replace@(match: "(Artifact|Creature|Enchantment|Instant|Land|Planeswalker|Sorcery)", replace: "")+ replace@(match: "[ ]+", in_context: "^", replace: "")+ replace@(match: "[ ]+", in_context: "$", replace: "") node_script := { if card.shape == "double faced" then "transform day" 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 "" } ancestral_mana := { card.pt != "" and card.pt == "" } is_unsorted := {"false"} special_text := { "" } special_text2 := { "" } exporter_name_filter := filter_text@(match:"!exporte?r?name [^\n!(]+") exporter_name_grabber := replace@(match:"!exporte?r?name ", replace:"") clean_name := remove_tags + replace@(match:"(\n| +$|^ +)", replace:"") + replace@(match:"’", replace:"'") card_name := { test_name := exporter_name_grabber(exporter_name_filter(card.notes)) if test_name == "" then test_name := card.name clean_name(test_name) } dfc_splitter_name := { back_name := card.name_2 full_name := card_name() if back_name != "" then full_name := full_name + "_" + clean_name(back_name) full_name } exporter_num_filter := filter_text@(match:"!num [^\n!]+") exporter_num_grabber := replace@(match:"!num ", replace:"") trim_zeroes := replace@(match: "^00?", replace: "")+ replace@(match: "a?/[0-9b]+", replace: "") corrected_card_number := { if exporter_num_grabber(exporter_num_filter(card.notes)) != "" then exporter_num_grabber(exporter_num_filter(card.notes)) else if card.custom_card_number != "" then trim_zeroes(card.custom_card_number) else card_number() } comma_count := filter_text@(match:",") round_up := {to_int(0.99999999999998+input)} round_near := {to_int(0.5+input)} to_title := replace@(match:"(^| )([A-z])([^ ]*)", replace:{_1+ to_upper(_2) + to_lower(_3)}) to_sentence := replace@(match:"(^|\n)([A-z])([^\n]*)", replace:{_1+ to_upper(_2) + to_lower(_3)}) join_arrays := { a1 + for x from 0 to length(a2)-1 do [a2[x]] } join_list := { string := "" if length(input) == 2 then spacer := " " if length(input) == 1 then closing := "" for x from 0 to length(input)-1 do string := string + (if x == length(input)-1 then closing else "") + input[x] + (if x == length(input)-1 then "" else spacer) string }@(spacer:", ", closing:"and ") join := { if i >= length(input) then "" else if i == length(input)-1 then input[i] else input[i]+sep+join(input, i: i+1, sep: sep) }@(i: 0, sep:"") # workaround cause position() is broken for text arrays contains_element := { if input == [] then false else length(filter_list(input, filter:{input == element})) > 0 } ar_position := { pos := -1 for x from 0 to length(in)-1 do ( if in[x] == of then pos := x; ) pos } unique_elements := { e1 := [] e2 := [] e1 := e1 + for x from 0 to length(of)-1 do if ar_position(of:of[x], in:from) == -1 then [of[x]] } includes := {ar_position(of:input in:array) != -1} pull_comma_array := { array := split_text(input, match:divider) length := length(comma_count(input)) ending := to_number(end) if (cell >= (length + (1-ending))) then default else if array[cell] == "" or array[cell] == nil or array[cell] == "-" then default else array[cell] }@(default:0, end: 1, divider:",", cell:0) ##todo check nil #### standard is pull_comma_array("X,Y,Z,", cell: 0) #### returns "X" #### ending true for coordinates (requires a final divider to ensure element is complete) #### ending false for moving (doesn't require divider, moving 1 then 11 is fine) #### divider is "," by default, can change #### can also add default to return in case of errors ##a workaround for the crop offset function that doesn't appear to work ##slice_chop(input:image, height:(final height), width:(final width), distance:(length from bottom to top of final image)) slice_crop := { img := flip_vertical(input) img := crop(img, height:distance, width:width, offset_x:0, offset_y:0) img := flip_vertical(img) img if(height != 0 and height != distance) then img := crop(img, height:height, width:width, offset_x:0, offset_y:0) img }@(height:0) #juryrig fix for level defaults. janky because MSE hates {true} transfer_levels := {true} transfer_levels_2 := {true} a_saga := {false} saga_reminder := { "As this Saga enters and after your draw step, add a lore counter. Sacrifice after III." } b_saga := {false} saga_reminderb := { "As this Saga enters and after your draw step, add a lore counter. Sacrifice after III." } ############################################################## Watermark Updates card_spotlight := { "/magic-mainframe-watermarks.mse-include/spotlight/" + card_new_color() + "spotlight.png" } custom_watermark_1 := { if set.custom_watermark_1 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_1 else "/magic-watermarks.mse-include/planeswalker.png" } custom_watermark_2 := { if set.custom_watermark_2 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_2 else "/magic-watermarks.mse-include/planeswalker.png" } custom_watermark_3 := { if set.custom_watermark_3 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_3 else "/magic-watermarks.mse-include/planeswalker.png" } custom_watermark_4 := { if set.custom_watermark_4 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_4 else "/magic-watermarks.mse-include/planeswalker.png" } custom_watermark_5 := { if set.custom_watermark_5 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_5 else "/magic-watermarks.mse-include/planeswalker.png" } custom_watermark_6 := { if set.custom_watermark_6 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_6 else "/magic-watermarks.mse-include/planeswalker.png" } custom_watermark_7 := { if set.custom_watermark_7 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_7 else "/magic-watermarks.mse-include/planeswalker.png" } custom_watermark_8 := { if set.custom_watermark_8 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_8 else "/magic-watermarks.mse-include/planeswalker.png" } custom_watermark_9 := { if set.custom_watermark_9 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_9 else "/magic-watermarks.mse-include/planeswalker.png" } custom_watermark_10 := { if set.custom_watermark_10 != "" then "/magic-watermarks.mse-include/" + set.custom_watermark_10 else "/magic-watermarks.mse-include/planeswalker.png" } custom_watermark_a := {"/magic-watermarks.mse-include/planeswalker.png"} custom_watermark_b := {"/magic-watermarks.mse-include/planeswalker.png"} ############################################################## Flavor Bar Equation chop_top := {0} chop_bot := {0} bar_offset := {0} offset_lines := {0} chop_top2 := {0} chop_bot2 := {0} bar_offset2 := {0} offset_lines2 := {0} ##### Set chop_top(), chop_bot(), bar_offset(), and offset_lines to 0 to reduce replacements in chopping frames ##### Full equations to use in chopping templates below ##### chop_top := {if styling.chop_top == "" then 0 else if comma_count(styling.chop_top) == "," or comma_count(styling.chop_top) == ",," then split_text(match:",", styling.chop_top).0 else styling.chop_top} ##### chop_bot := {if comma_count(styling.chop_top) == ",," then split_text(match:",", styling.chop_top).1 else if styling.chop_bottom == "" then 0 else styling.chop_bottom} ##### bar_offset := {if styling.flavor_bar_offset == "-" or styling.flavor_bar_offset == "+" then 0 else to_number(styling.flavor_bar_offset)} ##### offset_lines := {offset_counter(styling.flavor_bar_offset)} top_of_textbox := {card_style.text.top } bottom_of_textbox := {card_style.text.bottom } top_of_textbox2 := {card_style.text_2.top } bottom_of_textbox2 := {card_style.text_2.bottom } offset_counter := {length(filter_text(input, match:"u")) - length(filter_text(input, match:"d"))} paragraph_count := filter_text@(match:"\n") hard_paragraph_count := replace@(match:"\n", replace:"")+ #count hard breaks for their extra space filter_text@(match:"\n") soft_break_filter := filter_text @(match:"<", in_context: "soft-line>") #count soft breaks for quotes word_split := split_text@(match:" ") #split words to better calculate line lengths small_filter := filter_text@(match:"[\\.,\\?!il’]") #grab the tiny characters fb_length := {length(input) - 0.3 * length(small_filter(input))}#reduce the effect of tiny characters calc_lines := { sum := 0 #estimate lines by character limit lines := 1 #minimum of 1 for e from 0 to length(input)-1 do ( sum := sum + fb_length(input[e]); if sum > char then ( #if new word is over the limit lines := lines + 1; #add new line sum := fb_length(input[e])) #reset the sum else sum := sum + 1; #else add it and a space to the sum ) lines #return number of lines } lines_of_text := { #estimate lines in break blocks lines := 0 #further improves the previous eq for x from 0 to length(input)-1 do if input[x] or else "" != "" then #if the break isn't empty, check it lines := lines + calc_lines(word_split(input[x]), char:char) lines } flavor_text := {split_text(match:"\n", remove_tags(card.flavor_text+"\n"))} #remove tags, add \n so .1 doesn't explode hard_flavor_break := { if not contains(card.flavor_text, match:"\n") then 0 else if contains(card.flavor_text, match:"\n") then 0 else if lines_of_rules() >= 3 then -3 else -2} font_size := {min(14,round_near(card_style.text.content_height / card_style.text.content_lines) - 8)} #approximate font size adj_char_width := {7.35 * min(14, font_size()+0.95) / 14} #average char width, adjusted for font size char_per_line := {min(52,round_up(card_style.text.content_width / adj_char_width())+1.5)} #approximate character limit. very rarely over 52 but standard eq can reach 60+ lines_of_flavor := {lines_of_text(flavor_text(), char:char_per_line())} lines_of_rules := { card_style.text.content_lines - lines_of_flavor() } #rules of lines for ratio weirdness line_height := {(card_style.text.content_height / card_style.text.content_lines)} padding_height := { 0.5*(bottom_of_textbox() - top_of_textbox() - card_style.text.content_height) } #space between top of textbox and text linebreak_height := { 2*length(hard_paragraph_count(card.rule_text)) } ###correction for ratio of rules/flavor causing weirdness uneven_correction := { if lines_of_flavor() == 1 then max(4, (card_style.text.content_lines - (2*lines_of_flavor()))) else (card_style.text.content_lines - (2*lines_of_flavor())) } ###add it all up ###old_bar_equation is compatibilty for 2.0.0 old_bar_equation := { top_of_textbox() + padding_height() + card_style.text.content_height - line_height()*(lines_of_flavor() + offset_lines()) + linebreak_height() - uneven_correction() + front_corr() + bar_offset() + hard_flavor_break() +1 } bar_equation := {if card_style.text.layout.blocks[1].bottom or else 0 > 0 then card_style.text.top + 0.5*(card_style.text.layout.blocks[0].bottom+card_style.text.layout.blocks[1].top) else old_bar_equation()} flavor_text2 := {split_text(match:"\n", remove_tags(card.flavor_text_2+"\n"))} #remove tags, add \n so .1 doesn't explode hard_flavor_break2 := { if not contains(card.flavor_text_2, match:"\n") then 0 else if contains(card.flavor_text_2, match:"\n") then 0 else if lines_of_rules2() >= 3 then -3 else -2} font_size2 := {min(14,round_near(card_style.text_2.content_height / card_style.text_2.content_lines) - 8)} #approximate font size adj_char_width2 := {7.35 * min(14, font_size2()+0.95) / 14} #average char width, adjusted for font size char_per_line2 := {min(52,round_up(card_style.text_2.content_width / adj_char_width2())+1.5)} #approximate character limit. very rarely over 52 but standard eq can reach 60+ lines_of_flavor2 := {lines_of_text(flavor_text2(), char:char_per_line2())} lines_of_rules2 := { card_style.text_2.content_lines - lines_of_flavor2() } #rules of lines for ratio weirdness line_height2 := {(card_style.text_2.content_height / card_style.text_2.content_lines)} padding_height2 := { 0.5*(bottom_of_textbox2() - top_of_textbox2() - card_style.text_2.content_height) } #space between top of textbox and text linebreak_height2 := { 2*length(hard_paragraph_count(card.rule_text_2)) } ###correction for ratio of rules/flavor causing weirdness uneven_correction2 := { if lines_of_flavor2() == 1 then max(4, (card_style.text_2.content_lines - (2*lines_of_flavor2()))) else (card_style.text_2.content_lines - (2*lines_of_flavor2())) } ###add it all up old_bar_equation2 := { top_of_textbox2() + padding_height2() + card_style.text_2.content_height - line_height2()*(lines_of_flavor2() + offset_lines2()) + linebreak_height2() - uneven_correction2() + back_corr() + bar_offset2() + hard_flavor_break2() +1 } bar_equation2 := {if card_style.text_2.layout.blocks[0].bottom or else 0 > 0 then card_style.text_2.top + 0.5*(card_style.text_2.layout.blocks[0].bottom+card_style.text_2.layout.blocks[1].top) else old_bar_equation2()} ##### long correction coefficient based off several sets of data front_corr := {correction_coeff(lof:lines_of_flavor(), lor:lines_of_rules(), lbh:linebreak_height())} back_corr := {correction_coeff(lof:lines_of_flavor2(), lor:lines_of_rules2(), lbh:linebreak_height2())} correction_coeff := { (if lor == 1 then (if lof == 1 then 3 else if lof == 2 then 1 else if lof == 3 then 1.5 else if lof == 4 then 0 else 5 - lof) else if lor == 2 and lbh == 2 then (if lof == 1 then 1 else if lof == 2 then 1 else if lof == 3 then 2 else if lof == 4 then 2 else 3) else if lor == 2 then (if lof == 1 then 1 else if lof == 2 then 0 else if lof == 3 then 0 else if lof == 4 then 0 else -1) else if lor == 3 and lbh == 2 then (if lof == 1 then 0 else if lof == 2 then 0 else if lof == 3 then 1 else if lof == 4 then 1 else 2) else if lor == 3 then (if lof == 1 then 0 else if lof == 2 then -1 else if lof == 3 then -0.5 else if lof == 4 then -1 else 0) else if lor == 4 and lbh == 2 then (-2 + lof) else if lor == 4 then (if lof == 1 then -1 else if lof == 2 then 0 else if lof == 3 then -0.5 else -1) else if lor == 5 and lbh == 4 then (-5 + lof) else if lor == 5 and lbh == 2 then (-2 + lof) else if lor == 5 then (2 - lof) else if lor == 6 and lbh == 2 then (-1 - lof) else if lor == 6 then (2 - lof) else 0) + (if lbh >= 4 then 0.5*lbh-1) } ######################## Modal DFC hints auto_flags := {true} front_modal_hint := { if not auto_flags() then ["", "", 10.5] else if remove_tags(card.sub_type_2) != "" then [card.sub_type_2, ""+card.casting_cost_2+"", 10.5] else if card.casting_cost_2 != "" then [main_type(card.super_type_2), ""+card.casting_cost_2+"", 10.5] else [main_type(card.super_type_2), mana_ability(card.rule_text_2), 10.5] } back_modal_hint := { if not auto_flags() then ["", "", 10.5] else if remove_tags(card.sub_type) != "" then [card.sub_type, ""+card.casting_cost+"", 10.5] else if card.casting_cost != "" then [main_type(card.super_type), ""+card.casting_cost+"", 10.5] else [main_type(card.super_type), mana_ability(card.rule_text), 10.5] } mana_ability := { abils := break_text(input, match:"()?T()?: Add ()?(W|U|B|R|G|C)()?(, | or )?()?(W|U|B|R|G|C)?()?(, or )?()?(W|U|B|R|G|C)?()?.") abils[0] or else "" } main_type := { types := main_types(input) if length(types) == 0 then "" else if includes("Creature", array:types) then "Creature" else if includes("Land", array:types) then "Land" else types[0] } main_types := { types := break_text(input, match:"(Land|Instant|Sorcery|Artifact|Enchantment|Creature|Planeswalker)") types or else [""] } ######################## Mainframe mana use_v_mana := {contains(set.custom_mana_symbol_name, match:".png")} use_large_v_mana := { use_v_mana() and chosen(set.mana_symbol_options, choice:"enable in casting costs")} use_small_v_mana := { use_v_mana() and chosen(set.mana_symbol_options, choice:"enable in text boxes")} use_color_v_mana := { use_v_mana() and chosen(set.mana_symbol_options, choice:"colored mana symbols") and not use_hybrid_v_mana()} use_hybrid_v_mana := { use_v_mana() and chosen(set.mana_symbol_options, choice:"hybrid with colors")} v_mana_name := {if not use_v_mana() then "" else replace(set.custom_mana_symbol_name, match:"(.+/|\\.png)", replace:"")} v_mana_loc := {if not use_v_mana() then "" else replace(set.custom_mana_symbol_name, match:"{v_mana_name()}\\.png", replace:"")} v_mana_num := {max(to_number(set.number_hybrid_variants),0) or else -1} ub_stamp := { card.card_stamp == "universes beyond" } use_custom_stamp := {contains(set.custom_stamp_name, match:".png")} c_stamp_name := { if not use_custom_stamp() then "" else if card.stamp == "custom" then set.custom_stamp_name else if card.stamp == "custom color" then replace(set.custom_stamp_name, match:"(.+/|\\.png)", replace:"") else "" } c_stamp_loc := { if card.stamp != "custom color" or not use_custom_stamp() then "" else replace(set.custom_stamp_name, match:"{c_stamp_name()}\\.png", replace:"") } searchPull := filter_text@(match:"search(name|mana|type|rules|flavor|text|notes)") searchSnip := replace@(match:"search(name|mana|type|rules|flavor|text|notes)_", replace:"") custom_index := { sortIndex := split_text(set.custom_index, match:",") for each field in sortIndex do applyIndex(to_lower(field)) or else ( searchIndex(to_lower(searchPull(field)), query:searchSnip(field)) ) or else "" } applyIndex := { [ name: { fill_len(to_string(position ( of: card in: set order_by: { sort_name(card.name) + sort_name(export_name())} filter: set_filter() )), lead:"0", fill_to:3) }, alias: { fill_len(to_string(position ( of: card in: set order_by: { sort_name(card.alias) + sort_name(export_name())} filter: set_filter() )), lead:"0", fill_to:3) } name2: { fill_len(to_string(position ( of: card in: set order_by: { sort_name(card.name_2) + sort_name(export_name())} filter: set_filter() )), lead:"0", fill_to:3) }, alias2: { fill_len(to_string(position ( of: card in: set order_by: { sort_name(card.alias_2) + sort_name(export_name())} filter: set_filter() )), lead:"0", fill_to:3) } color: {fill_len(color_of_card(), lead:"A")}, artist: {fill_len(substring(card.illustrator, end:7), follow:" ", fill_to:7)}, artist2: {fill_len(substring(card.illustrator_2, end:7), follow:" ", fill_to:7)}, design: {fill_len(substring(card.card_code_text, end:7), follow:" ", fill_to:7)}, mv: {fill_len(to_string(cmc(card.casting_cost)), lead:"0")}, "mana value": {fill_len(to_string(cmc(card.casting_cost)), lead:"0")}, cmc: {fill_len(to_string(cmc(card.casting_cost)), lead:"0")}, "converted mana cost": {fill_len(to_string(cmc(card.casting_cost)), lead:"0")}, rarity: {index_of_rarity()}, power: {fill_len(card.power, lead:"0")}, toughness: {fill_len(card.toughness, lead:"0")}, pt: {fill_len(card.power, lead:"0") + fill_len(card.toughness, lead:"0")}, loyalty: {fill_len(card.loyalty, lead:"0")}, type: {fill_len(filter_text(match:"[A-Z][A-Z]?[A-Z]?", filter_text(match:"[A-Z]", card.super_type)), follow:"0", fill_to:3)}, hasrules: {if remove_tags(card.rule_text) != "" then "A" else "B"}, hasflavor: {if remove_tags(card.flavor_text) != "" then "A" else "B"}, hasrules2: {if remove_tags(card.rule_text_2) != "" then "A" else "B"}, hasflavor2: {if remove_tags(card.flavor_text_2) != "" then "A" else "B"}, ][input]() } searchIndex := { [ searchname: { if contains(card.name, match:query) or contains(card.name_2, match:query) then "A" else "B"}, searchmana: { if contains(card.casting_cost, match:query) or contains(card.casting_cost_2, match:query) then "A" else "B"}, searchtype: { if contains(card.type, match:query) or contains(card.type_2, match:query) then "A" else "B"}, searchrules: { if contains(card.rule_text, match:query) or contains(card.rule_text_2, match:query) then "A" else "B"}, searchflavor: { if contains(card.flavor_text, match:query) or contains(card.flavor_text_2, match:query) then "A" else "B"}, searchartist: { if contains(card.illustrator, match:query) or contains(card.illustrator_2, match:query) then "A" else "B"}, searchdesign: { if contains(card.card_code_text, match:query) then "A" else "B"}, searchtext: { if contains(card.text, match:query) or contains(card.text_2, match:query) then "A" else "B"}, searchnotes: { if contains(card.notes, match:query) then "A" else "B"}, unsearchname: { if contains(card.name, match:query) or contains(card.name_2, match:query) then "B" else "A"}, unsearchmana: { if contains(card.casting_cost, match:query) or contains(card.casting_cost_2, match:query) then "B" else "A"}, unsearchtype: { if contains(card.type, match:query) or contains(card.type_2, match:query) then "B" else "A"}, unsearchrules: { if contains(card.rule_text, match:query) or contains(card.rule_text_2, match:query) then "B" else "A"}, unsearchflavor: { if contains(card.flavor_text, match:query) or contains(card.flavor_text_2, match:query) then "B" else "A"}, unsearchartist: { if contains(card.illustrator, match:query) or contains(card.illustrator_2, match:query) then "B" else "A"}, unsearchdesign: { if contains(card.card_code_text, match:query) then "B" else "A"}, unsearchtext: { if contains(card.text, match:query) or contains(card.text_2, match:query) then "B" else "A"}, unsearchnotes: { if contains(card.notes, match:query) then "B" else "A"} ][input]() } index_of_rarity := { if card.rarity == "basic land" then "A" else if card.rarity == "common" then "C" else if card.rarity == "uncommon" then "D" else if card.rarity == "rare" then "E" else if card.rarity == "mythic rare" then "F" else if card.rarity == "special" then "G" else "J" } fill_len := { output := to_string(input) if output == "" then output := "0" fill := max(0,fill_to - length(output)) for x from 1 to fill do output := lead + output + follow; output }@(fill_to:2, lead:"", follow:"") skeleton_commons := 19 skeleton_uncommons := 11 skeleton_rares := 7 skeleton_mythics := 2 skeleton_land_commons := 1 skeleton_land_uncommons := 5 skeleton_land_rares := 0 skeleton_gold_commons := 0 skeleton_gold_uncommons := 1 skeleton_gold_rares := 1 skeleton_shard_commons := 0 skeleton_shard_uncommons := 0 skeleton_shard_rares := 0 skeleton_wedge_commons := 0 skeleton_wedge_uncommons := 0 skeleton_wedge_rares := 0 skeleton_artifact_commons := 5 skeleton_artifact_uncommons := 5 skeleton_artifact_rares := 0 skeleton_blank_commons := 0 skeleton_blank_uncommons := 5 skeleton_blank_rares := 8 skeleton_blank_mythics := 5 #### generates a set of CC00 Skeleton cards for each color #### by insertnamehere and cajun skeleton_runner := { cards:=[] for x from 0 to length(letter_list)-1 do ( for y from 1 to count do if mana_list == "nope" then (cards := cards + [new_card([name:prefix+letter_list[x]+fill_len(y, lead:"0"), rarity:rarity, card_color:color_list[x], super_type:super_type])];) else (cards := cards + [new_card([name:prefix+letter_list[x]+fill_len(y, lead:"0"), rarity:rarity, super_type:super_type, casting_cost:mana_list[x]])];) ) cards }@(count:1, rarity:"common", type:"", prefix:"C", super_type:"", color_list:["white", "blue", "black", "red", "green"], letter_list:["W", "U", "B", "R", "G"], mana_list:"nope") ###outside to make singleton scripts easier blank_list_5 := ["","","","",""] blank_list_10 := ["","","","","","","","","",""] mana_list_ally := ["WU","UB","BR","RG","GW"] mana_list_enemy := ["WB","UR","BG","RW","GU"] mana_list_shard := ["WUB","UBR","BRG","RGW","GWU"] mana_list_wedge := ["WBG","URW","BGU","RWB","GUR"] skeleton_script := { cards := []; cards := cards + skeleton_runner(count:skeleton_commons); cards := cards + skeleton_runner(count:skeleton_uncommons, prefix:"U", rarity:"uncommon"); cards := cards + skeleton_runner(count:skeleton_rares, prefix:"R", rarity:"rare"); cards := cards + skeleton_runner(count:skeleton_mythics, prefix:"M", rarity:"mythic rare"); cards := cards + skeleton_runner(count:skeleton_gold_commons, prefix:"CM", rarity:"common", letter_list:blank_list_10, mana_list:mana_list_ally+mana_list_enemy); cards := cards + skeleton_runner(count:skeleton_gold_uncommons, prefix:"UM", rarity:"uncommon", letter_list:blank_list_10, mana_list:mana_list_ally+mana_list_enemy); cards := cards + skeleton_runner(count:skeleton_gold_rares, prefix:"RM", rarity:"rare", letter_list:blank_list_10, mana_list:mana_list_ally+mana_list_enemy); cards := cards + skeleton_runner(count:skeleton_shard_commons, prefix:"CM", rarity:"common", letter_list:blank_list_5, mana_list:mana_list_shard); cards := cards + skeleton_runner(count:skeleton_shard_uncommons, prefix:"UM", rarity:"uncommon", letter_list:blank_list_5, mana_list:mana_list_shard); cards := cards + skeleton_runner(count:skeleton_shard_rares, prefix:"RM", rarity:"rare", letter_list:blank_list_5, mana_list:mana_list_shard); cards := cards + skeleton_runner(count:skeleton_wedge_commons, prefix:"CM", rarity:"common", letter_list:blank_list_5, mana_list:mana_list_wedge); cards := cards + skeleton_runner(count:skeleton_wedge_uncommons, prefix:"UM", rarity:"uncommon", letter_list:blank_list_5, mana_list:mana_list_wedge); cards := cards + skeleton_runner(count:skeleton_wedge_rares, prefix:"RM", rarity:"rare", letter_list:blank_list_5, mana_list:mana_list_wedge); for i from 1 to skeleton_artifact_commons do cards := cards + [new_card([name:"CA"+fill_len(i, lead:"0"), rarity:"common", super_type:"Artifact"])]; for i from 1 to skeleton_artifact_uncommons do cards := cards + [new_card([name:"UA"+fill_len(i, lead:"0"), rarity:"uncommon", super_type:"Artifact"])]; for i from 1 to skeleton_artifact_rares do cards := cards + [new_card([name:"RA"+fill_len(i, lead:"0"), rarity:"rare", super_type:"Artifact"])]; for i from 1 to skeleton_land_commons do cards := cards + [new_card([name:"CL"+fill_len(i, lead:"0"), super_type:"Land", rarity:"common"])]; for i from 1 to skeleton_land_uncommons do cards := cards + [new_card([name:"UL"+fill_len(i, lead:"0"), super_type:"Land", rarity:"uncommon"])]; for i from 1 to skeleton_land_rares do cards := cards + [new_card([name:"RL"+fill_len(i, lead:"0"), super_type:"Land", rarity:"rare"])]; for i from 1 to skeleton_blank_commons do cards := cards + [new_card([name:"CX"+fill_len(i, lead:"0"), rarity:"common"])]; for i from 1 to skeleton_blank_uncommons do cards := cards + [new_card([name:"UX"+fill_len(i, lead:"0"), rarity:"uncommon"])]; for i from 1 to skeleton_blank_rares do cards := cards + [new_card([name:"RX"+fill_len(i, lead:"0"), rarity:"rare"])]; for i from 1 to skeleton_blank_mythics do cards := cards + [new_card([name:"MX"+fill_len(i, lead:"0"), rarity:"mythic rare"])]; cards } skeleton_info := { trace("Set Skeleton Generator Help:" +"\nSet variables here to modify the Skeleton Add Cards script, for example 'skeleton_commons := 10'" +"\nCurrent variables:\n" +"skeleton_commons: " + skeleton_commons + " (of each color)\n" +"skeleton_uncommons: " + skeleton_uncommons + " (of each color)\n" +"skeleton_rares: " + skeleton_rares + " (of each color)\n" +"skeleton_mythics: " + skeleton_mythics + " (of each color)\n" +"skeleton_gold_commons: " + skeleton_gold_commons + " (of each color pair)\n" +"skeleton_gold_uncommons: " + skeleton_gold_uncommons + " (of each color pair)\n" +"skeleton_gold_rares: " + skeleton_gold_rares + " (of each color pair)\n" +"skeleton_artifact_commons: " + skeleton_artifact_commons + "\n" +"skeleton_artifact_uncommons: " + skeleton_artifact_uncommons + "\n" +"skeleton_artifact_rares: " + skeleton_artifact_rares + "\n" +"skeleton_land_commons: " + skeleton_land_commons + "\n" +"skeleton_land_uncommons: " + skeleton_land_uncommons + "\n" +"skeleton_land_rares: " + skeleton_land_rares + "\n" +"skeleton_blank_commons: " + skeleton_blank_commons + "\n" +"skeleton_blank_uncommons: " + skeleton_blank_uncommons + "\n" +"skeleton_blank_rares: " + skeleton_blank_rares + "\n" +"skeleton_blank_mythics: " + skeleton_blank_mythics + "\n" +"skeleton_shard_commons: " + skeleton_shard_commons + "\n" +"skeleton_shard_uncommons: " + skeleton_shard_uncommons + "\n" +"skeleton_shard_rares: " + skeleton_shard_rares + "\n" +"skeleton_wedge_commons: " + skeleton_wedge_commons + "\n" +"skeleton_wedge_uncommons: " + skeleton_wedge_uncommons + "\n" +"skeleton_wedge_rares: " + skeleton_wedge_rares) } ##number of chapter symbols each chapter textbox has ##example, symbols on abilities 2,2,3 returns [0,2,1] saga_lore_count := { one := 0 two := 0 three := 0 four := 0 five := 0 six := 0 seven := 0 eight := 0 for x from 0 to length(input)-1 do if input[x] == "1" then one := one +1 else if input[x] == "2" then two := two +1 else if input[x] == "3" then three := three +1 else if input[x] == "4" then four := four +1 else if input[x] == "5" then five := five +1 else if input[x] == "6" then six := six +1 else if input[x] == "7" then seven := seven +1 else eight := eight +1 [one, two, three, four, five, six, seven] } ##index of given chapter number in above array ##example, 2,2,3, returns 1,2,1 ##i tried to make this shorter but this is the only one that deigned to function saga_ch_placement := { box1 := 0 box2 := 0 box3 := 0 box4 := 0 one := 0 two := 0 three := 0 four := 0 five := 0 six := 0 seven := 0 len := length(input) if len >= 1 then ( if input[0] == "1" then ( box1 := box1 +1 one := box1+0 )else if input[0] == "2" then ( box2 := box2 +1 one := box2+0 )else if input[0] == "3" then ( box3 := box3 +1 one := box3+0 )else if input[0] == "4" then ( box4 := box4 +1 one := box4+0 )else (one := one) )else (one := one) if len >= 2 then ( if input[1] == "1" then ( box1 := box1 +1 two := box1+0 )else if input[1] == "2" then ( box2 := box2 +1 two := box2+0 )else if input[1] == "3" then ( box3 := box3 +1 two := box3+0 )else if input[1] == "4" then ( box4 := box4 +1 two := box4+0 )else (two := two) )else (two := two) if len >= 3 then ( if input[2] == "1" then ( box1 := box1 +1 three := box1+0 )else if input[2] == "2" then ( box2 := box2 +1 three := box2+0 )else if input[2] == "3" then ( box3 := box3 +1 three := box3+0 )else if input[2] == "4" then ( box4 := box4 +1 three := box4+0 )else (three := three) )else (three := three) if len >= 4 then ( if input[3] == "1" then ( box1 := box1 +1 four := box1+0 )else if input[3] == "2" then ( box2 := box2 +1 four := box2+0 )else if input[3] == "3" then ( box3 := box3 +1 four := box3+0 )else if input[3] == "4" then ( box4 := box4 +1 four := box4+0 )else (four := four) )else (four := four) if len >= 5 then ( if input[4] == "1" then ( box1 := box1 +1 five := box1+0 )else if input[4] == "2" then ( box2 := box2 +1 five := box2+0 )else if input[4] == "3" then ( box3 := box3 +1 five := box3+0 )else if input[4] == "4" then ( box4 := box4 +1 five := box4+0 )else (five := five) )else (five := five) if len >= 6 then ( if input[5] == "1" then ( box1 := box1 +1 six := box1+0 )else if input[5] == "2" then ( box2 := box2 +1 six := box2+0 )else if input[5] == "3" then ( box3 := box3 +1 six := box3+0 )else if input[5] == "4" then ( box4 := box4 +1 six := box4+0 )else (six := six) )else (six := six) if len >= 7 then ( if input[6] == "1" then ( box1 := box1 +1 seven := box1+0 )else if input[6] == "2" then ( box2 := box2 +1 seven := box2+0 )else if input[6] == "3" then ( box3 := box3 +1 seven := box3+0 )else if input[6] == "4" then ( box4 := box4 +1 seven := box4+0 )else (seven := seven) )else (seven := seven) [one, two, three, four, five, six, seven] } card_face := { front := card[input] back := if card[input+"_2"] or else "" != "" then card[input+"_2"] else card[input] if match(margin_code, match:"(text[2456]|lv[5678])") then back else front } cc_filter := replace@(match:"^[CURMSL][WUBRGMZACL][0-9]+ ?[-—]? ?", replace:"") strip_card_codes := { save := input input := cc_filter(input) input := if input == "" or input == " " then save else input if alch_compatible() and card.card_symbol == "alchemy" then "A-" + input else input } name_checker := {if not set.remove_card_codes then input else strip_card_codes(input)} face_code := { face := "" if margin_code == "text2" or margin_code == "lv5" or margin_code == "lv6" or margin_code == "lv7" or margin_code == "lv8" then face := "_2" output := face_scripts[input](face) or else if_parse(input, face:face) or else input output } flip_face := { if input == "_2" then "" else "_2" } face_scripts := [ iscreature: {is_creature(card["type"+face])}, iscreaturish: {is_creaturish(card["type"+face])}, isenchantment: {is_enchantment(card["type"+face])}, isartifact: {is_artifact(card["type"+face])}, island: {is_land(card["type"+face])}, isspell: {is_spell(card["type"+face])}, istarget: {is_targeted(card["text"+face])}, subtypes: {separate_words(card["sub_type"+face], spacer: " ")} contains: { contains(card[field+face], match:query) }, notcontains: {not contains(card[field+face], match:query)}, name: {card["name"+face]}, cost: {card["casting_cost"+face]}, altname: {card["name"+flip_face(face)]}, altcost: {card["casting_cost"+flip_face(face)]}, ] expand_facecodes := [ subtype: "sub_type", castingcost: "casting_cost", manacost: "casting_cost" ] if_parse := replace@( match: "if_(.*)_then_(.*)_else_(.*)", replace: {if_scripts(_1, t:_2, f:_3)} ) if_scripts := { contCheck := split_text(input, match:"_") func := contCheck[0] field := "" query := "^$" if length(contCheck) == 3 then ( field := contCheck[0] func := contCheck[1] query := contCheck[2] ) field := expand_facecodes[field] or else field if face_scripts[func](face, field:field, query:query) or else false then t else f } white_text := {false} phy_reminder := { phy_match := filter_text(input, match:"(/[WUBRG])+", in_context:"H") letters := split_text(phy_match, match:"/") reminder_text := "" if length(letters) == 2 then reminder_text := "[H/" + letters[1] + "] can be paid with [" + letters[1] + "] or 2 life." else if length(letters) > 2 then reminder_text := "[H/" + letters[1] + "/" + letters[2] + "] can be paid with [" + letters[1] + "], " + "[" + letters[2] + "], or 2 life." else reminder_text := "" reminder_text } ###### Print Fix rare_width := { cw := card_style.rarity.content_width cw := if cw > 44 then (if set.print_fix != "" then set.print_fix else 22) else if cw < 22 then 22 else cw if card_style.rarity.width == 0 then 0 else cw } ### Customize fonts swap_font := {false} ##{styling.apply_custom_fonts} split_font := split_text@(match:";") pop_font_name := {split_font(input).0 or else ""} pop_font_size := {split_font(input).1 or else ""} pop_font_color := {split_font(input).2 or else ""} pop_font_vertical := {split_font(input).3 or else ""} pop_font_italic := {split_font(input).4 or else ""} swap_font_name := { if swap_font() then ( test := pop_font_name(src) if test != "" then font_name := test ) font_name }@(font_name:"", src:"") swap_font_size := { if swap_font() then ( test := pop_font_size(src) if test != "" then font_size := test ) font_size }@(font_size:16, src:"") swap_font_color := { if swap_font() then ( test := pop_font_color(src) nums := split_text(test, match:",") test_color := nil if length(nums) >= 4 then test_color := rgba(nums.0, nums.1, nums.2, nums.3) or else nil if test_color == nil and length(nums) >= 3 then test_color := rgb(nums.0, nums.1, nums.2) or else nil if test_color == nil and test != "" then test_color := to_color(test) or else nil if test_color != nil then font_color := test_color ) else "" font_color }@(font_color:"", src:"") swap_font_vertical := { if swap_font() then ( test := pop_font_vertical(src) if test != "" then vertical := to_number(test) ) vertical }@(vertical:0, src:"") swap_font_italic := { font_name := "MPlantin-Italic" if swap_font() then ( test := pop_font_italic(styling.custom_body_font) test2 := pop_font_name(styling.custom_body_font) if test != "" then font_name := test else if test2 != "" then font_name := "" ) font_name }@(font_name:"", src:"") #### Customize rarity symbol alt_rarity := {""} ##{styling.alt_rarity_color} use_alt_rarity := {alt_rarity() != ""} alt_rarity_color := { string := "83,67,53:177,150,131:0,0,0:0,0,0:0.07:" src := alt_rarity() if match(src, match:":$") then string := src colons := length(filter_text(string, match:":")) output := split_text(string, match:",|:") splits := split_text(string, match:":") final_num := to_real(splits[length(splits)-2]) or else 0 final_border := final_num > 0 and final_num < 1 final_num := if not final_border then "0.07" else to_string(final_num); if final_border then ( colons := colons - 1; string := replace(string, match:"{final_num}:", replace:"") ) if colons == 4 then output := split_text(string+final_num+":", match:",|:") if colons == 3 then output := split_text(string+splits[2]+":"+final_num+":", match:",|:") else if colons == 2 then output := split_text(string+"0,0,0:0,0,0:"+final_num+":", match:",|:") else if colons == 1 then output := split_text(string+splits[0]+":0,0,0:0,0,0:"+final_num+":", match:",|:") output } alt_symbol := { alt_array := alt_rarity_color() symbol_variation( symbol:set.symbol, border_radius: alt_array.12, fill_type: "linear gradient", fill_color_1: rgb(alt_array.0, alt_array.1, alt_array.2), fill_color_2: rgb(alt_array.3, alt_array.4, alt_array.5), border_color_1: rgb(alt_array.6, alt_array.7, alt_array.8), border_color_2: rgb(alt_array.9, alt_array.10, alt_array.11), center_x:0.5, center_y:0.5, end_x:1, end_y:1 ) } # rough type_of script # fine for nil, boolean, color, date, string, number, and array # map and image are trickier # if you don't care about the difference use as normal, will return "map or image" # if you do, include key:"" parameter that's a key of the potential map # ex if you want to know if some_object is an image or [x:1] # use type_of(some_object, key:"x") type_of := { test := to_string(input) or else nil type := "idk" if test == "" and input == nil then type := "nil" else if test != nil and (input == true or input == false) then type := "boolean" else if (test != nil and test + 0 == input + 0) then ( if to_color(test) or else nil == input then type := "color" else if to_date(test) or else nil == input then type := "date" else type := "string" ) else if test != nil then type := "number" else if input[0] or else nil != nil then type := "array" else if key == "" then type := "map or image" else if input[key] or else nil == nil then type := "image" else type := "map" type }@(key:"") is_string := { test := to_string(input) or else nil if test == "" and input == nil then false else if test == nil then false else test == input } # mapping := ["up":"test/up.png" "down":"test/down.png" "left":"test/left.png" "right":"test/right.png"] multi_choice_image := { ## input = option string ##img_map = map of image links coll := split_text(input, match:", ?") imgs := for each x in coll do if img_map[x] or else false != false then [img_map[x]] len := length(imgs) if len == 0 then "" else if len == 1 then imgs[0] else if len == 2 then combine_blend(image1:imgs[0] image2:imgs[1], combine:combine) else mass_combine(imgs:imgs, combine:combine) }@(combine:"and") mass_combine := { base := combine_blend(image1:imgs[0] image2:imgs[1], combine:combine) for x from 2 to length(imgs)-1 do ( base := combine_blend(image1:base image2:imgs[x] combine:combine) "" # this is junk output so it doesn't try to add the images as strings ) base }@(combine:"and") zwsp := "​"