0% found this document useful (0 votes)
63 views54 pages

Magic Set Editor Template Creation Tutorial

Uploaded by

remdrlremdrl
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
63 views54 pages

Magic Set Editor Template Creation Tutorial

Uploaded by

remdrlremdrl
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 54

1

Magic Set Editor


Template Creation Tutorial

This tutorial will go over how to create a custom template for Magic Set Editor. If you only wish to
learn how to make cards using existing templates, then this tutorial is not for you.
2

Setting up
First, you will need to download this special version of MSE I made here. (Alternate link here.) It’s
an MSE 2.1.2 install, but with only a few tutorial templates. I have also slightly modified some files to
make them simpler. MSE has acquired a lot of functionality over the years. If I bombard you with
everything at once, you're gonna give up instantly, so I have stripped down some of the more
advanced features for the sake of clarity. You have to have these files handy to follow along,
otherwise this tutorial will be much harder to understand.

You will want to keep this tutorial install separate from any other version of MSE you are using. We
are going to be messing with code, so things can go really wrong really quickly. We want to work in
a separate environment, that way errors we make will not affect anything we were working on prior.
Unzip what you downloaded into a new folder, not your pre-existing MSE folder.

Also, since these files are slightly modified, it does mean that when you are ready to make your own
templates, you will want to move back to a standard install of MSE to regain the missing features.

Second, you will need a text editor. I really, really recommend using Notepad++. It's open source,
fast to install, and just an amazing piece of software. You can get it here.

Third, you’ll need an image manipulation program, like Photoshop. Although we won't need one in
this tutorial, it's essential for creating templates. Magic Set Editor is not itself an image manipulation
program, so you'll have to supply it with the images that will make up your template, like the card
frame, mana symbols or the like.

If you don't already have a preferred image manipulation program, you can use GIMP, which is kind
of like Photoshop, but open source. You can get it here. It has a very steep learning curve, but
mastering it is very useful in all sorts of contexts, not just template creation.
3

How the program works


Magic Set Editor creates cards by combining rectangles. You can think of a card as being a canvas
upon which these rectangles will be placed. These rectangles will then contain text, images made
with an image editor, simple colors, or other things. They also support transparency, so even though
they are always rectangles, they can actually appear to have any shape you want, by leaving some
parts see-through. These rectangles are called fields.

Fields contain within them bits of information that specify their size, their position within the card, the
type of their content, etc.. These bits of information are called properties.

This information can be explicitly specified, like for instance: this rectangle will be 40 pixels wide.
However, it can also be specified by code, like for instance: this rectangle will be 40 pixels wide if
there is no casting cost, but only 30 pixels wide if there is. This is where the versatility and potential
for automation of the program comes from, and how we can make templates that adapt to user
inputs.

MSE uses a custom scripting language that is relatively easy to learn. I will be teaching you the
basics in this tutorial, you do not need to know how to code. You can find more in-depth
documentation here as well.

Fields also contain a special piece of information called their value, which is basically their contents.
So for a text field, it will be the actual text written inside. For an image field, it will be the image that's
currently drawn, etc...

A template is, in its most basic form, just a list of fields.


4

Folder and File Structure


Open the folder you just downloaded. Double click on 'magicseteditor.exe' to open the program.
Select 'New Set', then select the Magic game, and finally select the 'Tutorial 1' template.

Separately, open the 'data' folder in your file explorer. It contains folders that end with '.mse-game',
and ones that end with '.mse-style'. These correspond to the games and templates you just saw
when you booted up the program. So, the 'magic.mse-game' folder basically IS the game Magic. It
contains all the data needed for that game. Similarly, the 'magic-tutorial-1.mse-style' folder IS the
'Tutorial 1' template.

A template folder's name must start with the same name as the game folder it is made for, followed
by a hyphen, followed by another name of your choosing, and finally end with '.mse-style'.
Otherwise it will not show up in the list.

Open the 'magic-tutorial-1.mse-style' folder, then open the 'style' file that's inside with your text
editor. This 'style' file is the backbone that defines how the template behaves. ( I will also sometimes
call it the 'template' file. ) All the information explaining how to display the fields is stored in this file.

We will now go over what is in this particular 'style' file, line by line.
5

Template headers
On top are headers that tell the program how this file interacts with other files in the program. This is
not super important, but lets still explain them briefly:

mse version: 2.0.0

This specifies the lowest version of MSE that is still compatible with the template. If the person using
the template has a lower version, the program will produce a warning, and it may behave strangely.

game: magic

This specifies what game this template is made for. (The name of the game's folder.)

A game has predefined fields that are specified in another file. We will have access to those fields in
our template. For example, every Magic card has a name. So if we make a template that inherits
from the game Magic, we will automatically have access to the name field without having to define
it. We will not go in any more detail about the game files for now. We’ll come back to them at the
end of this tutorial.

short name: Tutorial 1


full name: First Tutorial Template

These are the names that our template will have in the template list, which you just saw when you
booted up the program.

icon: card-sample.png

This is the image our template will have in that list. It references a file that must be present in the
template folder. It should be around 75 pixels wide and 105 pixels tall.

position hint: 001

This is the position in the template list. Templates with a lower number appear first in the list.
6

version: 2015-12-20

This is the version of our template. Not useful for the template itself, but for other things that refer to
it. These other things might want to make sure they have an up to date version.

depends on:
package: magic.mse-game
version: 2014-06-25

This is a list of other files from which we will be borrowing information. For now the only thing listed
here is the folder containing the game files.

card width: 375


card height: 523

These are the dimensions in pixels of the card we are creating.

card dpi: 150

This is the Dots Per Inch, which is the resolution quality that will be used when we print the cards on
paper. The higher this number is, the smaller the card will appear on the paper, because the pixels
will be crammed into a tighter space. If you’re making realistic looking proxies, keep the dpi at 150,
otherwise you will facilitate counterfeiting.

If you are making an original template, you can increase this number, but keep in mind you will
probably have to increase the dimensions in pixels by the same factor, to compensate for the
printing size reduction. You could go with, for example:

card width: 750


card height: 1046
card dpi: 300
7

Defining the card fields


After the headers, there is the following line:

####################### Extra Card Field Definitions

Any line that starts with one or more # is ignored by the program. It’s basically just a comment that
you leave for yourself. Very useful for keeping things organized, or for explaining information that
isn’t immediately obvious by reading the code.

After that we get into the meat of the actual template: the fields.

To make a field, first you need to define it, then you need to specify how it looks.

These two steps, "Defining the card fields" and "Shaping the card fields", are the most crucial to
understand. For this reason, I have made a video explaining how this goes. I recommend watching
it now, then coming back and resuming the reading from here. I will be repeating what is in the
video here though, so you can skip it if you prefer reading.

You can watch the video here.


8

In the style file you've opened with your text editor, there are three fields. They are first defined
using the

extra card field:

line, followed by two properties:

type: image
name: smiley face

These lines tell us about the type of their content, and the name we will be using to reference them
in code. They may have other properties in the future, but for now let's keep it simple.

Two of the three fields in our file are images, and the third one is text.

If you’re wondering why they are 'extra' card fields, that’s because the 'main' card fields are defined
in the game files. This is done so because every template of a game would normally use the same
fields. For example, every Magic card has a name, regardless of if it's a creature, a planeswalker, a
saga or whatnot. That way, we only define the field which contains this name once, in the game
files, then each different template only has to specify what the field will look like, that is, where it's
placed on this particular type of card, what font it uses, etc. This is also why defining and specifying
how it looks are two distinct operations.

For now we don’t want to learn about the game files though, so we'll use extra card fields. Extra
card fields are normally used for things that only appear on a particular template, for example a
chapter icon on a saga. For that reason, they are defined in the template file, since other templates
won't need them.

Using extra card fields at first will allow me to show you everything from within the template file. I
believe it will make things simpler to follow.

Extra card fields work almost exactly like main card fields anyway, so everything we learn now, we
will be able to apply to main card fields when we start using them soon.
9

Shaping the card fields


After the fields are defined, we must specify how they will be drawn. When we define something, we
use the keyword 'field', like 'card field' or 'extra card field'. When we specify how something looks,
we use the keyword 'style', like 'card style' or 'extra card style'.

I introduce the section where we specify how fields are drawn with the following comment:

####################### Extra Card Field Looks

We then identify which field we are talking about with these lines:

extra card style:


field name:

…where 'field name' is the actual field's name.

After that, we are going to give properties to the field:

left: 10

Remember that all fields are rectangles. This is telling us where on the card the left edge of the
rectangle is. Here our field will start 10 pixels from the left border of the card.

width: 200

This is the width of the rectangle, again in pixels. Alternatively, we could have specified

right: 210

This would mean that the rectangle’s right edge should be 210 pixels from the left. Yes, left. We
always start counting from the left.

You must specify exactly two of these three properties. ( The third can then be deduced. ) Here we
went with left and width. Depending on the situation, it’s sometimes easier to specify left and right,
and other times it’s easier to specify right and width. The order in which you write properties in a
field does not matter.
10

top: 60
height: 200

Same as left and width, but for the vertical direction. Alternatively we could have used 'bottom:'. We
always start counting from the top.
11

z index: 1

If two fields overlap, this tells the program which one should be drawn in front of the other. Fields
with a higher z index value will cover ones with a lower value.
12

visible: true

This tells the program if this field should be drawn at all. For now this seems useless, and in this
form, it is. If a field should always be drawn, then you can omit this line, and the program will
automatically assume it should draw the field. Later, we will be able to add code to this line, so that
a field can be made visible or invisible depending on some other things that are happening on the
card. For example, the power/toughness box should only be drawn on cards that are creatures,
etc…

default: smiley-face-image.png

This provides a default image that will be the content of this field. The program will look in the
template’s folder for a file matching this name, and load it. If you wish to point to an image that is
somewhere else in the 'data' folder of the program, you must write the full path starting from the
'data' folder. One common use will be to pull from the 'magic-mainframe-extras.mse-include' folder.
In that case the syntax would be:

default: /magic-mainframe-extras.mse-include/smiley-face-image.png

Notice that the path must start with a / if the file is not directly in the template folder.
13

Let’s now switch to MSE and see all this in action. Make sure MSE is outlining the fields by going in
the Edit menu > Preferences… > Display tab, and enable "Show lines around fields".

You should be looking at this:

Lets notice a few thing:

- There are 3 things on the card. The 2 image fields, and the 1 text field.
- The red rectangle is drawn in front of the green rectangle, where they overlap, because it
has a higher z index value.
- The red rectangle is narrower than the green rectangle. Even though both source images
have the same size, the code in the template says the red rectangle should only be 160
pixels wide. The program will automatically stretch and squeeze the source image so that it
fits the dimensions specified in the style file.
- Both images have this 'double click to load image' text on them. That's because they are
currently using the default value. This text will disappear once the user selects a proper
image to display.
- There is a text field at the bottom, but it does not have a default value. The user can type
anything they want into it.
14

Analyzing an existing template


Okay, we’re done with the basics. Let's now load a more realistic template. Close and re-open the
program, select 'New Set', then select the 'Tutorial 2' template. In parallel, open the 'data' folder,
open the 'magic-tutorial-2.mse-style' folder, then open the 'style' file with your text editor.

When you want to create a new template, it’s often easier to modify an existing one, than to start
from scratch.

When you modify a template, for the modifications to take effect, make sure you saved the modified
template file, then you must reload MSE by going in the 'File' menu and clicking on 'Reload Data'
( or completely closing and re-opening the program ).

Let's gloss over the headers of this new file, they are pretty much the same as before ( although we
are listing a second folder in our dependencies ).

We arrive at this comment:

####################### Card Field Looks

Okay, no 'extra' this time. These are the main fields. However, you will notice that we are
immediately specifying how they look, but we never defined them. That’s because as I said before,
they are defined in the game files. The game files are still too much info for us now, so i will just take
what is relevant to us and paste it here as needed. We’ll get back to them I promise. If you just want
to take a peek now, the definitions are taken from this file:
MSE Folder/data/magic.mse-game/card_fields

Our first field goes by the name 'border color', and it corresponds to the card's border, shown here
in red.
15

The field will be drawn on the card as follows:

card style:
border color:
left: 0
top: 0
width: 375
height: 523
z index: 1

To understand this, I will also pull the definition from the game files. The main card fields are
defined exactly like the extra card fields that we saw before:

card field:
type: color
name: border color
default: set.border_color
allow custom: true
description: The border of the card; can be any solid color.

We’ll go over these two snippets of code slowly. Let's focus on the definition first.

This field is of type 'color'. This means that this rectangle will basically just be filled with a single
solid color. If the user clicks somewhere inside the rectangle, a menu will appear, prompting them to
select a color from among the specified choices. In this example, no choices have been specified in
the definition of the field, so the only available option will be the default.

The default is 'set.border_color'. This is referencing a set field, which is defined in the game files.
These fields are a bit much to chew on right now, but just know that they contain information that is
specified for the entire set, not just a single card. By default, our card will look at the border color
that we have specified for our set, and copy that value in its own personal border color card field.
Since every card makes a separate copy for itself, this value can then be changed on a card by card
basis, like any other card field value.

The field allows for a custom color. This will add an option in the menu which, when clicked on, will
open a color selection interface.

There is a description. This can be any text we want, meant to help the user. It will be displayed at
the bottom of the program window, when the user hovers their mouse over this field.

Now turning our attention to how the field is drawn, we can see that it actually covers the entire
card. It starts at the top left corner, and spans the entire width and height of the card. But since it
has the lowest z index of the file, every other field will be drawn in front of it, and so it will only be
visible on the edges.
16

Our second field goes by the name 'card color', and it corresponds to the frame:

It's style is specified as follows:

card style:
card color:
left: 8
top: 15
width: 359
height: 476
z index: 2
popup style: in place
render style: image
image: { if count_chosen(card.card_color) >= 2
then "goldframe.png"
else ( card.card_color + "frame.png" ) }

To understand it I will again pull the definition from the game files:

card field:
type: multiple choice
name: card color
choice: white
choice: blue
choice: black
choice: red
choice: green
empty choice: colorless
description: The frame of the card, used to indicate card color.

Again, let's go over this slowly, starting with the definition.


17

It’s of the type 'multiple choice'. 'Choice' and 'multiple choice' are fields that will present a drop-down
menu with some choices when the user clicks on them. 'Choice' requires the user to select exactly
one option, while 'multiple choice' allows the user to select any number of options.

After that, we must list the choices that will appear in the drop-down menu. We will see later how to
use these choices in code to modify the look of our card according to what the user selected.

Since this is a 'multiple choice' field, we must also specify what happens when the user selects none
of the choices, that’s the purpose of the 'empty choice' property.

Looking now at the style, we see that the rectangle covers nearly the whole card, leaving only a
small margin on the sides for the border. It will be drawn over the border, because it has a greater z
index.

The 'popup style' property is set to 'in place', meaning the drop-down menu will appear exactly
where the user clicked. Another possible value would be 'menu', which would make the drop-down
menu appear at the bottom of the field.

We then have the following line:

render style: image

This means that this field, although being a 'multiple choice' field, will actually be drawn as an
image.

At the bottom we have:

image: { if count_chosen(card.card_color) >= 2


then "goldframe.png"
else ( card.card_color + "frame.png" ) }

This will determine which image will be drawn in this field. We are going to go over this code
methodically, but first I’d like you to go in the program to see everything we just explained in action.

Click on the frame to make the drop-down menu appear, select different values, see how it
changes.

Click on the border of the card, at the very edge, and select a custom color.

Even though the border rectangle technically covers the entire card, you can only click on it at the
edges, because the frame rectangle is in front of it.

The frame image has some transparent pixels. This allows us to see the border underneath in some
places, which makes the two blend together.

On the right of the program window, there are columns. One of these columns is called 'Card Color'.
This column contains the value that is stored in the field 'card color' that we just examined. The
value that is stored in a 'multiple choice' field is the list of choices selected by the user, separated by
commas, and always in the order in which they are defined in the code.
18

The scripting language


We now have to dive into how the scripting language works. If you already know how to code, this
will sound very basic, but I will assume you don’t know, so I will explain as much as possible.

Formatting

Normally, when we write code, formatting does not affect the code. We can add spaces or go to a
new line to make the code clearer to read, it won't change what it does.

However, sometimes MSE has trouble parsing when we get too crazy with formatting. Indentation,
for example, is something it is very finicky with. You should try to use the same indentation patterns
as you see in my files. To indent a line, use the 'Tab' key on your keyboard, do not use spaces.

If the program tells us there is an error in our code, but we are certain there isn't, it may seldom be a
formatting issue. We can try to write the whole code on a single line to see if it fixes the problem.
Most likely though, there really is an error in our code.

I also noticed that when I copy code from Google Docs, or from Discord, into my template files,
sometimes it corrupts them. It might have to do with character encoding being different, or it might
be that I'm pasting some sort of invisible character that MSE doesn't know how to interpret…
Anyway, if that happens, try to write the code manually instead of pasting it.

Whenever you're dealing with code, make sure to create backup copies frequently.
19

Values

A value is an explicit piece of information. It can be one of many types.

A value can be a number, either integer or decimal.

A value can be a string, which is the same as text, or just a chain of characters. Strings are written
inside double quotes ".

A value can be a boolean. A boolean has two possible states: true and false. You can also interpret
them as yes and no respectively.

A value can be a color, which is basically an amount of red, an amount of green, an amount of blue,
and an amount of opaqueness. Each of these amounts ranges between 0 and 255. Sometimes the
amount of opaqueness, also called alpha value, is not specified. In that case it defaults to 255,
which means the color is completely opaque.

A value can be a list of any of those previous things.

We saw that card fields hold a value inside them. To access this value in code, we write
'card.field_name', where field_name is the actual field's name, but using underscores instead of
spaces. So for example, to access the value stored in the field named 'card color', we would write
'card.card_color'. To access values in extra card fields, use 'extra_card.field_name'.
20

Variables

A variable is a container for a value. We define variables in the following way:

my_new_number_variable := 100

my_new_string_variable := "apple"

my_new_boolean_variable := false

my_new_color_variable := rgb(255, 62, 0)

my_new_string_list_variable := [ "apple", "car", "wax candle" ]

Here, 'my_new_number_variable' is the name we have given to this container. Variable names are
of our choosing. They can't start with a number, and they can't contain spaces, use underscores
instead. Whenever we want to use the value that is stored within the variable, we just type its name.
100 is the value we have stored in the variable.

You might ask: 'If I want to use the value that is stored inside it, why don’t I just type 100 directly,
that seems much simpler.' While you could do that, there are several reasons why you might want
to define variables instead of just using the value directly. These reasons can only become clear
with practice, but I’ll try to give you at least two:

1) Imagine you write the value 100 somewhere. Two months later you come back and you read
100. You'll have no idea what that 100 refers to, or why it's 100 and not 120. Variables, on the other
hand, have a name of your choosing. If you read 'typeline_width' instead of 100, it helps you
remember what this piece of code is talking about. Then you can look for the place where you
defined that variable to know the precise value stored inside, but in reality most of the time you don't
even really care, you just know it holds some value that you deemed appropriate at the time.

2) You might be using the same value at thirty different locations in your code. Now if you suddenly
want to change that value, you will have to go to thirty different locations to make the modification.
That’s a huge pain, and it’s prone to errors, because you might forget one or two locations. If you
defined a variable, stored the value in the variable, and then used the name of that variable instead
of typing the value explicitly everywhere, you would only need to make one modification, on the line
where you stored the value in the variable. Just store a different value inside it, and the program will
now automatically know to use this new value everywhere you wrote the name of the variable.

We said that fields store a value. In that regard, it's correct to think of them as also being variables.
Fields additionally have properties though, so they are a bit more than variables.

We also said that to access the value stored within a card field, we had to use the 'card.field_name'
syntax. You may be wondering where the 'card' comes from. It's actually itself a variable, but a built-
in one. You can find a list of these variables here.
21

Operators

An operator is a symbol that combines what is to its left and its right to produce a result based on
some rule. The most familiar example is the addition operator:

2 + 3

These three distinct things now act as one. At first, it's useful to visualize parentheses around the
operator and its two operands:

( 2 + 3 )

That way, it's easier to understand that we should now see this as a single thing, whose value is the
result of the operation. So in this case, all this acts as if we had simply written the number 5.

Some operators can act on things that are not numbers. In fact, the + sign itself has another
meaning ( we say that it's overloaded ). It can concatenate strings. Concatenating strings is a fancy
term for gluing two words together. So if I write:

"Hello" + "World"

That is equivalent to writing:

"HelloWorld"

Note that the concatenation does not automatically add spaces between words, you'll have to add
them yourself if needed.

MSE usually knows whether a + sign means number addition or string concatenation. Sometimes it
drops the ball though. So if you're getting weird results like 2 + 3 = 23, that's because it's gluing the
word "2" to the word "3", instead of adding the number 2 to the number 3. In that case, you can
force addition by writing 2 - ( -3 ). Since the subtraction operator can only be used with numbers,
you eliminate all ambiguity.

The + sign can also be used for list concatenation. So:

[ 52, 123, 46, 4 ] + [ 11, 3, 52 ]

is equivalent to just a single list:

[ 52, 123, 46, 4, 11, 3, 52 ]


22

The result of an operation does not need to be of the same type as the operands. For example, a
very useful operator is the == operator. It checks if two things are equal.

If I write:

card.name == "Lightning Bolt"

This will look at the value stored in the field 'name', which is of type string, and check if it is equal to
the string "Lightning Bolt". But the result will not itself be a string. It will be a boolean, either 'true', if
that card's name is indeed "Lightning Bolt", or 'false' otherwise.

Other useful operators include:


!= which is asking: 'Is this thing different from that other thing?'
>= which is asking: 'Is this thing greater or equal to that other thing?'
> which is asking: 'Is this thing greater than that other thing?'
<= which is asking: 'Is this thing smaller or equal to that other thing?'
< which is asking: 'Is this thing smaller than that other thing?'
or which is asking: 'Is at least one of these things true?'
and which is asking: 'Are both of these things true?'

There are also operators which require only a single operand, like for example the 'not' operator. It
acts on a boolean that is to its right, and flips it from 'true' to 'false' or vice-versa. So:

not true

is the same as:

false

You can find more info on operators here.


23

Functions

A function is a snippet of code we have given a name to, because we expect to use it often. It will
generally be faster to write the name of the function, then to re-write the lines of code that it
represents.

Functions are defined similarly to variables:

my_new_area_function := { width * height }

Here, 'my_new_area_function' is the name I have given to this function. Everything inside the
braces is the code that is represented by the function, also called 'body' of the function. Any variable
that is not defined inside the braces is called an argument of the function. Arguments must be given
to a function when it is called.

If we want to call a function, we use the following syntax:

my_new_area_function(width: 45, height: 10)

consisting of the name of the function, followed by parentheses containing all the needed
arguments. The function will then replace all the arguments with the values we have provided,
execute the code, and return a result. Here, the result of this function call would be 450.

A function can have one argument with no name. That argument will automatically be assigned the
name 'input'. This is most useful for functions with a single argument.

Functions can also have zero arguments. In this case, just leave the parentheses empty when you
call them.

They must, however, always give a result, otherwise calling them would be useless. The result they
will return is always the last statement in the braces.
24

As a slightly less trivial example, let’s examine the following function:

character_count := { prefix_character_count := length(prefix)


suffix_character_count := length(suffix)
prefix_character_count + suffix_character_count }

This function begins by defining two variables: 'prefix_character_count' and 'suffix_character_count'.


The values that are stored in these variables are obtained by calling a different function, 'length', on
two variables: 'prefix' and 'suffix'.

'prefix' and 'suffix' are not defined anywhere in the function, so they must be arguments that are
passed to the function when we call it.

The 'length' function is a built-in function of the scripting language. You can find a list of the built-in
functions here. This 'length' function takes an argument of type string and returns the number of
characters inside it. Since it has only a single argument, we don't give the argument a name, that is,
we don't write

length(input: prefix)

the 'input:' is implied. We just need to pass it a value, which in this case is the value stored inside
the 'prefix' variable.

Finally our function adds the two variables together. This is the last statement, so it is also the result
of the function.

We would call the function like this:

character_count(prefix: "Astral", suffix: "of Knowledge")

And the result would be 18. It just counts the total number of characters, spaces included, inside the
prefix and the suffix.
25

The 'if' statement

The 'if' statement is the heart of programming. It's what allows code to produce different behavior
depending on information you give it, like for example user inputs. Here is how it works:

if condition then someCode else otherCode

We evaluate a given condition, whose result must be a boolean. If the result is 'true', the program
will execute the code after the 'then' keyword, and ignore the code after the 'else' keyword. On the
other hand, if the result of the condition is 'false', the program will ignore the code after the 'then'
keyword, and execute the code after the 'else' keyword.

We sometimes call this 'branching' execution, because there are two branches of code, but only one
is executed.

As an example, we can actually take the code that decided which image our 'card color' field would
use. Here is this code again.

image: { if count_chosen(card.card_color) >= 2


then "goldframe.png"
else ( card.card_color + "frame.png" ) }

The code is specifying a value for the 'image' property. This property expects a string, which
represents the name of the image file that has to be loaded. This means our code must return as its
result a value of type string.

It uses an 'if' statement. The condition is the following:

count_chosen(card.card_color) >= 2

It's calling another function named 'count_chosen'. This is a built-in function that counts the number
of options that have been selected by the user in a 'multiple choice' field. Here we are looking at the
field 'card color'. We are then asking if this count is greater or equal to 2. So this condition will
evaluate to true if the user has selected two or more colors in the drop-down menu, and false
otherwise.
26

If the condition is true, the code that is executed is the following:

"goldframe.png"

We could have written arbitrarily complex code here, but in this example, it's just a string value.
After executing this code, we will skip the rest of the code since it's after the 'else' keyword. This
means that in this case, "goldframe.png" is the last statement, and hence the return value ( or
result ) of the code.

In practice, what this does is it looks at the colors of the card. If the card is two or more colors, it will
load a gold frame, that we have provided in the template folder under the name "goldframe.png".

If the condition is false, the code that is executed is the following:

( card.card_color + "frame.png" )

This code will look at the value that is stored inside the field 'card color', and glue "frame.png" at the
end of it. Again, since this is the last statement of the code, it is also its return value.

The value that is stored in 'card color' is the list of choices selected by the user, separated by
commas.

But in this case, we know the user has only selected one or zero choices, because the other cases
were addressed by the other branch of the 'if' statement. So we know that the value stored is either
"white" or "blue" or "black" or "red" or "green" or possibly "colorless" since that's what we had
specified the empty choice to be. It can't be "white, red, green" for example.

We then provide images in the template folder called "whiteframe.png", "blueframe.png",


"blackframe.png", "redframe.png", "greenframe.png", and "colorlessframe.png".

The code will hence load the appropriate one, depending on the user's choice.
27

Analyzing an existing template ( part 2 )


Now that we are world class experts in coding, we can return to our style file and continue reading it
line by line.

The third field in the file corresponds to the casting cost:

It will be drawn in the following way:

card style:
casting cost:
right: 343
top: 27
width: 38
height: 24
z index: 22
alignment: right middle
always symbol: true
font:
name: MPlantin
size: 16
symbol font:
name: magic-mana-large
size: 16

There are a few properties here that we haven't already talked about, but other than that it's a pretty
standard text field, so I'm not going to pull its definition from the game files.
28

Text fields have this 'alignment' property, which specifies how the text behaves.

'left', 'center' and 'right' tell us how the text aligns horizontally. You can only have one of these three
keywords at a time in the property.

'top', 'middle' and 'bottom' tell us how the text aligns vertically. You can only have one of these three
keywords at a time in the property, in addition to the horizontal keyword.

In text fields that have only one line, the default behavior when the text is too long to fit is that it just
overflows. You can prevent this by adding the 'shrink-overflow' keyword. In that case, the letters will
become narrower so that the text remains in the bounds of the text field. If you add the 'shrink-
justify' keyword instead, then letters will also be stretched so that they fill the textbox completely
when the text is too short.

The next property, 'always symbol', means that the program will always try to convert the text into
symbols.

We then specify the font, which itself has some sub-properties: its size and name.

Finally we specify the symbol font, since this text field can accept symbols to be displayed inside it.
I'll now explain what symbol fonts are and how they work.
29

Symbol fonts
A symbol font is a separate folder that contains images that can be inserted inside text. It also
contains a special file named 'symbol-font' which specifies how we write the symbols.

The 'casting cost' field is referencing the 'magic-mana-large' symbol font, which is the reason we
had to add it in our dependencies, in the file headers.

Open the 'magic-mana-large.mse-symbol-font' folder that is inside the 'data' folder. You will see all
the images that are used to create the symbols for Magic. In parallel, open the 'symbol-font' file you
will find in this folder with your text editor.

Ignoring the headers, this file consists in a series of definitions of the form:

symbol:
code: B/G/W
image: mana_bgw.png
image font size: 145

This definition means that whenever MSE sees the string of characters "B/G/W" inside a text field
that is using this symbol font, if the user highlights this string and clicks on the symbol button, MSE
will replace it by the image "mana_bgw.png" found in this folder, and the image will be displayed at
size 145. ( What this number actually means is a bit complicated. Just know that the bigger this
number is, the smaller the symbol will appear. Fiddle with it until you find the size that you like. )

If MSE sees this string in a text field that has the property 'always symbol' set to true, it will always
replace this string by the image.

It's also possible to write scripts that will automatically replace this string by the image when it is
found in some particular context. With Magic for example, there is a script that looks for sentences
of the form "T: Add G.", and automatically replaces the T and the G with the tap symbol and the
green mana symbol. Explaining how to do that is outside of the scope of this tutorial though.

If two symbols have the same 'code' property, they should have a condition defined in their 'enabled'
property to specify which version is active. If for some reason multiple versions are active at the
same time, the one that is defined first in the file will be used.

If a symbol's code is a part of another symbol's code, like for example one symbol's code is "B", and
another is "B/G", you must define the longer one first in the file.
30

At the very end of the 'symbol-font' file, you will see another type of definition of the form:

insert symbol menu:


item: T
item: Q
etc...

This lets you customize what appears in the symbol menu of the program. Just add items by
specifying their code, and they will show up in the menu, in the order you wrote them in the file. The
user can then insert these symbols by just selecting them in the menu.

After you make changes to a symbol-font file, close and reopen MSE, otherwise it will have a
tendency to crash.
31

Analyzing an existing template ( part 3 )


Let's continue the analysis of our template file. The next field is the name field, but there isn't
anything new here, so we'll just skip over it and get to the following one, the illustration of the card:

Which is drawn as such:

card style:
image:
left: 27
top: 57
right: 347
bottom: 291
z index: 11
mask: image_mask.png
32

This field has the 'mask' property which we haven't seen before. A mask is an image who's pixels
are either white or black. We use these pixels to know which pixels from the real image we want to
draw.

The image and the mask should have the same width and height. If they don't, MSE will stretch and
squeeze the mask so that it matches the image.

If a pixel is white on the mask, the corresponding pixel on the image is drawn. If a pixel is black on
the mask, the corresponding pixel on the image is not drawn.

( You can actually have pixels that are different levels of gray, to encode opaqueness. So a black
pixel means completely transparent ( which is the same as not drawing it ), a white pixel means
completely opaque, and a perfect middle-of-the-line gray would mean exactly half transparent. )
33

If you look at our template, you will notice that the space for the illustration does not have straight
edges, due to our complicated frame pattern. If we just paste an image in there without a mask, it's
edges will not align nicely with the frame:

I'm going to add the following mask:

Which I created by taking the frame image, cropping it to the same dimensions and location as the
illustration field, changing colored pixels to black, and changing transparent pixels to white.
34

As a result, the illustration fits in nicely:

You might ask why we don't simply give a lower z index to the illustration, that way it will be drawn
behind the frame, which will make it look like it slots in perfectly, without the need for a mask. You
could do that, but there are two things you need to keep in mind.

First, which field the user is able to select is based on z index. If the illustration is drawn behind the
frame, the user can't select the illustration field to change the image. To remedy that, the frame itself
will need a mask to make some pixels transparent. The user will be able to click through these
pixels, and select what's behind.

Second, if the illustration is in front, we can add a popout effect. By changing the mask a bit, we can
make some parts of the illustration jump out in front of the frame, like for planeswalkers. If the
illustration is drawn behind the frame, then you will need to fake that effect by adding a second
image field.
35

We are almost done analyzing our template. There is just one last field I would like to go over. It's
the last extra card field in the file, here are its definition and style:

extra card field:


type: choice
name: pt box
editable: false
save value: false
choice: dummy choice

extra card style:


pt box:
left: 247
top: 469
width: 109
height: 38
z index: 3
visible: { card.pt != "" }
render style: image
image: { if count_chosen(card.card_color) >= 2
then "goldpt.png"
else ( card.card_color + "pt.png" ) }

This field is responsible for drawing the power and toughness box. Note that there is another field
(that we glossed over) that is simply called 'pt'. The 'pt' field is a text field that holds the actual text,
that is, the value of the power and toughness of the creature. The field we are looking at now is the
'pt box', that is the image of the box that surrounds the power and toughness text:

You might expect this 'pt box' field to be of type 'image', but it's of type 'choice'… what's going on
there? Well, this is a bit of a hack, but as far as I can tell, that's how everybody does it. Let me
explain.
36

A field of type 'image' actually expects the user to select an image themselves, like for the card's
illustration. As long as the user did not choose an image, the program will display the following text
in front of the image: 'double click to load image'. ( We encountered this at the very beginning. )

However, here, we do not want the user to select the image. We know exactly what image it should
be.

We can add the following property to this field:

editable: false

This will prevent the user from being able to change the image, which seems to be exactly what we
want. Unfortunately, because of how the program works, this does not get rid of the 'double click to
load image' text.

But there is a workaround. We saw previously that 'choice' and 'multiple choice' fields can also be
rendered as images, by adding these properties:

render style: image


image: frowny-face-image.png

And these 'choice' fields do not have this pesky 'double click to load image' text.

…so that's why we use a choice field instead of an image field…

We still keep the 'editable: false' property, so that when the user clicks on the field, it does not open
a drop-down menu. We also still have to define at least one choice, otherwise the program will not
bother rendering this field. This choice can't ever be selected by the user, though.

This is an ugly workaround, but it does what we want: display an image that can not be modified by
the user, and that does not have the 'double click to load image' text.

Additionally, we instruct the program not to save the value of this field. The value is driven purely by
code, and so it should be re-calculated every time the program is opened.
37

You can see that some code is determining if this 'pt box' field is visible or not:

visible: { card.pt != "" }

If we wanted to make this code clearer to read, at the price of being verbose, we could have
equivalently written:

visible: { if card.pt != "" then true else false }

Here we have the != operator, which is asking 'Is this thing different from that other thing?'

So this code is saying: 'if the card's power and toughness is different from the empty string, then it is
true that this box should be visible'. In other words, if this card has something written in the pt field,
we need to draw a box around it.

We also have some code that determines what image is to be used for the pt box:

image: { if count_chosen(card.card_color) >= 2


then "goldpt.png"
else ( card.card_color + "pt.png" ) }

You'll notice it's almost the same code as for the frame image. The only difference is that we are
gluing "pt.png" at the end, instead of "frame.png".
38

Defining the styling fields


So far we have talked about card fields. There is another type of field called styling fields. They work
similarly to card fields, except they are not drawn on the card. They just contain a value that can be
set by the user, and that we can then use in our code to modify the appearance of the card. This
allows for another level of customisation.

Re-open the program, select 'New Set', then select the 'Tutorial 3' template. In parallel, open the
'data' folder, then open the 'magic-tutorial-3.mse-style' folder, then open the 'style' file with your text
editor.

This template is almost identical to the last one, the only difference is we added two styling fields.

You can see I introduced a new section just after the headers, beginning with the comment:

####################### Styling Field Definitions

In this section there is a text styling field, and a choice styling field.

Go in the program, and switch to the 'Style' tab. You should see this:
39

This is where styling fields appear. Under the styling options we have the two fields defined in the
file, 'rule text font cap' and 'center rule text'.

The user can input text in the text field, and can choose an option from the choice field. We can
then use these values in our code to change how our card looks, based on the user's choices.

Before we do that, let's go back to the style file, and observe that there is another new section
called:

####################### Styling Field Looks

Just like card fields, once we have defined styling fields, we can specify how they look. You'll notice
we have not given such specification for the 'rule text font cap' field. Specifying how styling fields
look is optional.

We did do it for the 'center rule text' field though, it starts with:

render style: both

This means that the drop-down menu will contain both images and text. Alternatively, we could have
gone with just 'text' or 'image'.

The text will always be the names of the choices.

Since we also want images, we specify which image to use for each choice with these lines:

choice images:
always: center-all-text.png
two lines or less: center-2-line-text.png
never: center-no-text.png

We then provide these images in our template folder.


40

Using the styling fields


On their own the styling fields don't do much except hold a value chosen by the user. We now have
to write code that will read those values and make use of them.

Just like we accessed the values of card fields by writing 'card.field_name', we access the values of
styling fields by writing 'styling.field_name'.

Let's now find the 'rule text' card field in the file and see what we did to incorporate the info from the
styling fields. I'm not going to copy the whole field here, it's best if you look at it in Notepad++, the
formatting will be much clearer.

The first difference we made is in the 'alignment' property. It now contains this 'script' sub-property.
If we write code that fits on one line, we can just encase it in curly braces to signify to the program
that it is code. Here we want to write code on multiple lines to make it easier to read, so it's safer to
warn the program of our intention by adding this 'script' sub-property that will hold the code,
otherwise it can sometimes fail to parse.

Here is the code:

if styling.center_rule_text == "always"
or ( styling.center_rule_text == "two lines or less"
and card_style.rule_text.content_lines <= 2 )
then "center middle"
else "left middle"

Here is what this code says in english:

if the user selected the option to always center the rule text,
or if the user selected the option to center the rule text when it has two lines or less
and at the same time the rule text actually has two lines or less,
then the alignment of this text should be "center middle",
in all other cases the alignment of this text should be "left middle".

You can go in the program and verify that the rule text actually behaves according to the option you
select.
41

The second difference is in the font size, and symbol font size properties. They both have this code:

{ if styling.rule_text_font_cap != ""
then to_number(styling.rule_text_font_cap)
else 14 }

Here is what this code says in english:

if the user has written something in the 'rule text font cap' field,
then convert this text to a number and use this number as the size for this font,
otherwise use 14 as the size for this font.

The 'to_number' function is another one of those built-in functions.

Note that we aren't doing any error checking in this code, for the sake of clarity. The 'rule text font
cap' field is a text field, not a number field. ( Number fields don't exist for some reason, but you can
always use a text field instead. ) So if the user goes in this field and writes "I love pizza", the
program will freak out because it can't convert this into a number. It will give an error in the console
tab, and this code will not run. The value for the font size will just stay whatever it was before.

Depending on the severity of the error, sometimes the entire field can fail to render.
42

Extracting functions
We have the exact same code written at two different locations: in the font size property, and in the
symbol font size property. Whenever the same code appears more than once, it's good practice to
factor it out into a function. If the same code is written in multiple locations, when you want to modify
it you have to remember every location. If you forget one, you'll be left scratching your head as to
why your modifications work in some cases but not others.

Lets define a function that represents this code:

font_size := { if styling.rule_text_font_cap != ""


then to_number(styling.rule_text_font_cap)
else 14 }

If the program fails to parse code that is written on multiple lines within curly braces, remove any
unwanted white-space characters, then either write everything on one line, or move the start of the
code to a new indented line, like so:

font_size :=
{ if styling.rule_text_font_cap != ""
then to_number(styling.rule_text_font_cap)
else 14 }

The common practice is to write all necessary functions on top of the file, just after the headers. So
just before the line:

####################### Styling Field Definitions

I will add the following:

####################### Extra Script Definitions

init script:
font_size := { if styling.rule_text_font_cap != ""
then to_number(styling.rule_text_font_cap)
else 14 }

If I were to define more functions after that, I would not need to write 'init script:' again. This 'init
script' is executed when the program loads the template for the first time.

I can now replace this code by the function call in both the font size and symbol font size properties
of the 'rule text' field:

size: { font_size() }

The body of the code is now written in a single location. If I want to modify it, I won't have the risk of
forgetting a location.
43

The game files


Okay, we're finally going to talk about the game files, but first, a word of warning.

If you are making a template for an existing game, you should not modify the game files. You
should only modify these files if you are making a new game ( or a game that isn't currently
supported by MSE ). Otherwise, you will create the following problems:

1) Your template will no longer be compatible with a standard install of MSE, because it assumes
there are things in the game files that are not present in a standard MSE install. Everytime you will
want to update to a new version of MSE, the update will overwrite your modifications, and you will
need to re-modify the game files.

2) All other templates in your MSE install that were using the same game files will now potentially be
broken, again because they assume the game files are in their standard state, which they are no
longer.

3) If you want to share your template, you will not only need to provide its folder, but also the
modified game files. The recipient will have to overwrite their game files with yours, meaning you will
now have thrusted problems 1 and 2 onto them.

A template should, as much as possible, contain within its own folder all the custom information and
data it needs. It should only use standard, unmodified files outside of that.

If you are trying to do something by modifying the game files, you can probably accomplish the
same thing by simply adding styling fields and extra card fields to your template.

You can also override functions defined in the game files by re-defining them in your template file.
The program will automatically use your version over the one in the game files.
44

The game files are located in a folder whose name must end with '.mse-game'. Just like for
templates, this folder basically IS the game.

This folder must contain a file simply named 'game' (with no extension), which will hold all the
information relevant to our game.

Open the 'data' folder, open the 'magic.mse-game' folder, then open the 'game' file with your text
editor.

It starts with the same headers as a template file.

mse version: 2.0.0


short name: Magic
full name: Magic the Gathering
installer group: magic/game files
icon: card-back.png
position hint: 01

version: 2020-04-25
depends on:
package: magic-blends.mse-include
version: 2014-06-25
depends on:
package: magic-watermarks.mse-include
version: 2007-09-23

Make sure the icon file is present in the game folder, and is around 75x105 pixels.

The 'installer group' line is not really used anymore, and can be safely omitted.

After the headers, you can see a bunch of lines starting with 'include file:'. There is a ton of
information that is defined for Magic. This information has been broken up into multiple different
files, so that it is better organized and easier to access. Each 'include file:' line acts as if, in its place,
we had written the entire contents of the file it's referencing.

If you want to include a file that is not directly in the same folder as the file that's including it, then it
must be in a folder whose name ends with '.mse-include'. Additionally, that folder must contain
another file simply named 'include'. This 'include' file can be empty, it just needs to exist. To
reference the file, first write a / then write the full path, starting from the 'data' folder.

The first included file is called 'script'. Since its name does not start with /, it must be directly inside
the game folder itself. This file contains functions that are very useful to have access to, in any
template that inherits from this game. For Magic, this would include functions that sort mana cost
symbols in the right order, functions that determine if a card should have a hybrid multicolor frame
instead of a gold multicolor frame, etc…

The next two are the most important: card fields and set fields. The rest is more nitty gritty, we will
not cover these here. (In fact, almost all of it is optional. The only things the game file must
absolutely contain are the headers, and the definition for at least one card field.)
45

The card_fields file


Open the 'card_fields' file that is in the 'magic.mse-game' folder with your text editor.

This file contains the definitions for the main card fields.

As a game creator, you should put in here every possible field that every possible template of your
game could need. That way, template makers will not need to modify this game file. They can pick
which of these fields they want to use for their particular template. They do not need to use all of
them.

Of course, it's impossible to really predict everything that they will need, but the idea is to make it as
easy for them as possible.

Since template creators should not modify the game files, they should only create styling fields and
extra card fields. These are a bit clunkier than the main card fields, because their values are not
shared between templates, meaning that even if two different templates both have an extra card
field named 'alias', if the user changes a card to use the other template, the value inside that field
will not transfer. They will have to retype it in.

You can find more information about the different types of card fields you can add here.
46

The main card fields are defined just like extra card fields, but there are a number of properties we
haven't seen before.

The first property I want to talk about is:

card list allow: true

Main card fields actually correspond to the columns shown in the program. When a field has this
property set to true ( which it has by default if the property is not explicitly specified ), this means it
can be selected to be one of the columns that the program displays.
47

These columns are very useful, they allow the user to view at a glance a ton of information about
the cards in their set, and they allow them to sort cards based on the values in the column.

Along with this property, there is a whole family of other properties that specify how the column
should look:

'card list name' tells us what name the column header will have. If not specified, the column will
have the same name as the field it corresponds to.

'card list visible' tells us if this column starts out displayed or not. The user can override this if they
choose, this is just the default value.

'card list column' tells us the position of the column. Columns with a lower number will be displayed
more to the left, columns with a higher number will be displayed more to the right. Again this is only
the default value, it can be overwritten by the user.

'card list width' is self explanatory.

'card list alignment' is the alignment of the text inside it.


48

I'd also like to mention the 'script' property. It holds a piece of code that will be run every time the
value that is stored in the field changes. The result will be stored as the new value for the field.

When you write code inside the 'script' property, you exceptionally do not have to encase it in curly
braces.

In this code, you can use the name 'value' to refer to the field's current value. (The value that has to
be replaced by the script's result.)

You might have noticed that in our templates, when we wrote a casting cost, the color symbols
would always sort themselves in the correct order, even though no code in our template file was
instructing them to do so. This is because the 'casting cost' card field has a script defined, and this
script re-writes the contents so that they respect the Magic conventions.

As a template creator, it can be a bit confusing at first. Some fields might exhibit behavior that we
never coded for them. When that's the case, remember to check their definition in the game file, to
see if they have a script associated with them.

Most of these scripts are just a function call. These functions are generally stored in the file named
'script' that is inside the game folder. Sometimes though, these functions are defined elsewhere,
and you will have to chase the dependencies to find their definition.

If you would like to disable one of these scripts without modifying the game files, you can use the
following trick, if the script is just a single function call, like in the case of the casting cost:

script: mana_filter(value)

I will redefine the mana_filter function at the start of my template file:

mana_filter := { input }

This function just takes its input and returns it as its result. In other words, it does nothing. But it has
the same name as the function used in the script for the casting cost, so it will override it, effectively
disabling it.

You can also redefine the function any other way, for example if you still want it to do what it used
to, but want to add a tiny bit of functionality to it.

On the flip side, as a game creator, when you are defining a new card field with a script attached to
it, make sure you create a function that represents the code you want, and have the 'script' property
call this function. Don't write the code explicitly in the property. This will give other template makers
of your game the option to disable or redefine the function using the above method, without having
to modify your game files.

There is another property called 'default', which works exactly like the 'script' property, except its
code is only run while the field is in its default state. As soon as the user manually modifies the
value in the field, the 'default' property will be deactivated.
49

The set_fields file


This is where set fields are defined.

There's not much to say about set fields, they work very similarly to styling fields. The main
difference being that a set field has only one instance that all the cards in the set share access to,
whereas for styling fields, each card has its own copy that can be modified independently.

Set fields hold a value that can be modified by the user in the 'Set info' tab.

That value can be accessed in code using the 'set.field_name' syntax.

Looking inside the file, we see there are fields of type 'info'. These are used to make the dark gray
title bar you can see in the image. They cannot be edited by the user.

There are also fields of type 'symbol' whose content is a file of type '.mse-symbol'. These files are
used for the set symbol, and can be produced with the built-in symbol editor. This symbol editor is
pretty cool, it's quick and easy to use and will handle the different rarity gradients. ( You could of
course just use a choice field directly with '.png' files instead. )
50

Magic modules files


If you want to create templates for Magic: The Gathering, some of the work may already have been
done for you. If you are creating templates for another game, you can skip this section.

Some elements on Magic cards are extremely stable, meaning they always look the same
regardless of the template. The best example is the information section, containing the copyright,
card number, set code, language and artist credit:

Since it's always the same, we have written its behavior once and for all in a file, and you can just
include that file in your template, which will automatically add all the needed card fields, and place
them correctly on the card. We call these bundles of functionality 'modules'.

Modules are found in the following folder:


MSE Folder/data/magic-modules.mse-include/

There are a ton of them, each with its own subfolder. Inside these subfolders, you will find a readme
file that explains how to use the module. It generally involves two steps.

First, there are 'include file:' lines that you must add to your template at specific places. For
example, the information module needs you to add:

include file: /magic-modules.mse-include/information/card_fields

just before the card style definitions. This will essentially paste all the contents of this file directly into
your template.

Second, there are a bunch of optional variables that you may want to override, by adding them to
the init script of your template. Again, using the information module as example, you may want to
add:

information_offset_top_1 := { 10 }

which would shift all the information fields down by 10 pixels, if your template needs a little more
room.

Most existing templates use modules now, so if you're looking for something in the files, but can't
find it where it should be, that's probably because it's actually using files from a module.
51

Debugging with the console


The console tab is where errors and warnings are written.

It also lets you query the value of a field or function while the program is running. You can do this in
two ways.
52

The first is through the use of the built-in function called 'trace'. This function is very simple: you give
it an argument, and it prints it in the console.

Imagine you have some complicated function determining the value of a field, through a series of
steps:

complicated_function := { initial_value := some complicated code


intermediate_value := more complicated code
final_value := mega complicated code
final_value }

If the result is not what you expected, you can insert the trace function so that it will print the
intermediate values, allowing you to narrow down where the error occurs:
.
complicated_function := { initial_value := some complicated code
trace(initial_value)
intermediate_value := more complicated code
trace(intermediate_value)
final_value := mega complicated code
trace(final_value)
final_value }

For some weird reason, the messages created by 'trace' seem to appear in the console in the
reverse order that they are produced. So in this example, it would first show the final value, then the
intermediate value, then the initial value. You can add some text to better identify which is which:

trace("The final value is: " + final_value)

But the 'trace' function has another, even more useful application. Sometimes things go wrong, not
because the code is faulty, but because the code is not executed at all. Due to an 'if' statement in
the execution path, we end up following another branch than what we would expect. It can
sometimes be difficult to realize that it's happening.

If you add 'trace("Hello handsome")' to the code, you can know whether the code was executed or
not. If no messages complimenting your looks show up in the console, you know this particular
branch of code was never executed.
53

The second way to query values from the console, is to type a bit of code, like a field name or a
function call, at the bottom of the console tab, and hit the Evaluate button.

This is less flexible than the 'trace' function, but it's much quicker as you don't have to modify any
code in the files.

For example, imagine the font in the rule text field does not have the size I would expect. I know that
its value is governed by a function I wrote named 'font_size', which uses the value of a styling field
named 'rule text font cap' to make its calculations.

I can type 'font_size()' in the bottom line of the console, and hit Evaluate. The program will then find
this function in my template, run the code, and show me its result. I can then go in the Style tab,
tweak the value inside the 'rule text font cap' styling field, and come re-evaluate the function to see
how it took into account the changes I made, potentially allowing me to identify the faulty behavior.

The console has read access to the rest of the program, but it cannot influence it. What is written in
the console stays in the console. It cannot make any permanent change to anything else.

Finally, let's do a little experiment. Let's type "Trample" inside the 'rule text' field on the card, and
then evaluate what is in that field by writing 'card.rule_text' in the console.

You would expect the result to just be "Trample", but instead we get something like "<kw-
a><nospellcheck>Trample</nospellcheck></kw-a>".

This is because there is a script associated with the 'rule text' field in the game files. This script adds
markup tags that help the program identify keywords, remember if you want to display reminder
text, allow some parts of text to have alternate formatting, etc...

These tags are not rendered on the final card image, but they are nonetheless a part of the field's
value, so we must take them into account if our code checks for the contents of this field in some
way. If I were to make the following check somewhere in my template:

card.rule_text == "Trample"

this condition would evaluate to false, even though when I look at the card's image, it seems like
"Trample" is indeed the contents of the 'rule text' field.

Looks can be deceptive, but the console reveals the truth behind the veil.
54

Conclusion
There is a ton of stuff I glossed over, but I should have given you the tools to fill in the blanks.

The best course of action for you now is to go download a huge pack of templates, for example
here. Pick one you like, or one that does something similar to what you wish to do, and dive into its
style file to reverse engineer how it works. It's really satisfying when you figure it out.

I do not recommend starting with the Mainframe template though. It just has so much functionality
that only the most powerful of wizards can untangle its inner workings.

I also made another video which might interest you. It documents every step in the process of taking
canon showcase cards and turning them into a template, including making the blanks and coding
the template. You can watch it here.

If you have feedback concerning this tutorial or if something wasn't clear, you can @ me on Discord:
GenevensiS#5934

If you have further questions, you can find good documentation here. Also, there is an #mse-tech-
support channel on the Discord server with lots of people willing to help.

Have fun!

You might also like