7.1. Entity properties

Almost all MESS scripting occurs within entity properties. The most basic form of scripting is to reference parent entity properties. There are also several special properties that trigger specific MESS behavior, and it's possible to do things like turning one property into multiple properties with scripting.

7.1.1. Parent entity properties

When a macro entity such as macro_insert or macro_cover creates an instance of a template (either a macro_template or a separate map file), all of its properties can be referenced inside that template.

Templates (macro_template entities and separate maps) can also have their own properties. These properties can reference parent entity properties, and can themselves be referenced by entities inside the current template. This makes for a good place to initialize common variables, or to set default values for required properties.

Take, for example, the following macro_insert:

key value
classnamemacro_insert
targetnamekey1
template_namekey_template
color255 255 0

and the macro_template that it references:

key value
classnamemacro_template
targetnamekey_template
color{color or [255, 255, 255]}

and finally, an entity inside that template:

key value
classnamefunc_wall_toggle
targetname{id()}
rendercolor{color}

When the macro_insert entity is processed, first any expressions in its properties are evaluated. In this case, there are none, so MESS will quickly proceed.

Next, any expressions in the properties of the chosen macro_template are evaluated (or, if a separate map is used via template_map, any expressions in the properties of that map). Here, the value of color consists of the expression {color or [255, 255, 255]}. This is a common mechanism to provide a default value. It references the color property of the instance-creating entity, which contains the value 255 255 0. If the macro_insert didn't contain a color property, or if it was empty, then the or [255, 255, 255] part would ensure a default color of 255 255 255.

Note that the classname, targetname, selection_weight and anchor properties of a macro_template are silently removed, to prevent them from hiding important parent entity properties - specifically the targetname.

Finally, any expressions in entities inside the template are evaluated. The func_wall_toggle's targetname contains the expression {id()}. This calls the id() function, which returns either the targetname of the parent macro entity, or the unique numeric ID of the current instance.

The rendercolor property references the color property. Both the macro_insert and the macro_template contain a color property. In that case, the value of the macro_template's color property is used - it's essentially hiding macro_insert's color property.

7.1.2. Special properties

The following properties can be added to entities to trigger special behavior in MESS. This includes setting spawnflags on the current entity, removing the entity, merging it with others, or inserting a template map at the entity's position:


_mess_spawnflagN

This set of properties can be used to enable or disable a specific spawn flag with MScript. These properties are removed from the entity after the spawnflag property has been updated. The first spawnflag has number 0, the last has number 31.

If a _mess_spawnflagN value is empty or 0, then the corresponding spawn flag will be disabled. Else, it will be enabled. For example, the following entity:

key value
classnameenv_beam
_mess_spawnflag0{start_on}
_mess_spawnflag2{enable_random_strike_time}

will have its first spawn flag enabled if start_on is true, and it will have its third spawn flag enabled if enable_random_strike_time is true. This would be the resulting entity if both are true:

key value
classnameenv_beam
spawnflags5

_mess_merge_entity_id

This property is used to merge brush entities together, which can be useful for certain optimization techniques. Merging happens after post-processing rewrite rules have been applied.

Entities that contain a _mess_merge_entity_id property are grouped by their _mess_merge_entity_id value. Each group is turned into a single entity. The resulting entity will have the properties of the first entity of that group (or the first entity that is marked as a master, see the _mess_merge_entity_master property below), and it will contain the brushes of all entities of that group. The resulting entity will not contain a _mess_merge_entity_id or _mess_merge_entity_master property.

It is recommended to only merge entities of the same type and with the same properties.

For example, the following two entities will be merged into a single one. Because none of them has been marked as a master, the resulting entity will use the properties of the first entity and so its targetname will be fence1:

key value
classnamefunc_wall
targetnamefence1
_mess_merge_entity_idouter_fence
key value
classnamefunc_wall
targetnamefence2
_mess_merge_entity_idouter_fence

_mess_merge_entity_master

An entity that contains this property will be marked as a master if the value of this property is true (any value other than leaving it empty or setting it to 0). When merging entities (see the above _mess_merge_entity_id property), the resulting entity will get the properties of the first master entity in that group.

For example, the following entity is the master of the courtyard_grass group, and the resulting entity will get the properties of this entity (minus the _mess_merge_entity_id and _mess_merge_entity_master properties):

key value
classnamefunc_illusionary
_mess_merge_entity_idcourtyard_grass
_mess_merge_entity_master1

_mess_remove_if

Entities that contain this property will be removed if the value of this property is true (which is any value other than leaving it empty or setting it to 0). If the entity is part of a template, then the value will be re-evaluated for every instance. This is similar to surrounding the entity with a macro_remove_if. This property is removed from the entity afterwards.

For example, the following entity will be removed if the global variable DEBUG exists and if its value is not none or 0:

key value
classnamefunc_wall
_mess_remove_if{getglobal('DEBUG')}

_mess_attached_template_map

Adding this property to a normal (non-macro) entity will insert the specified template map (or maps) at the position of that entity. This property is then removed from the entity. This also works for the special worldspawn entity - adding a _mess_attached_template_map property to the properties of a map will insert the specified map(s) at the center of the current map.

For brush entities that contain an ORIGIN brush, the maps will be inserted at the center of that ORIGIN brush. For brush entities without an ORIGIN brush, the center of their bounding box will be used instead.

The current entity will behave as a macro entity, in the sense that all of its properties will be available inside the selected template map(s).

When inserting multiple maps, their paths must be separated by a comma (,). Relative paths are taken to be relative to the templates directory, or relative to the current map when used inside a template map. For paths that contain comma's, use a double comma escape sequence: a, b and c.map is interpreted as two paths (a and b and c.map), whereas a,, b and c.map is interpreted as a single path (a, b and c.map).

key value
classnameworldspawn
_mess_attached_template_mapTODO.map,TODO2.map

_mess_attached_template_name

This property is similar to _mess_attached_template_map, except that it inserts one or more local templates at the position of the entity that contains this property. The same positioning rules apply for brush entities and for inserting multiple templates.


_mess_allow_rewrite_rules

Adding this property to a (template) map will block rewrite directives from all .ted files, except for the paths listed in this property. Paths can cover specific files or entire directories, and do not need to contain a .ted extension. This property is removed afterwards.

Relative paths are relative to the directory that contains the current (template) map. Multiple paths must be separated by comma's (,). Use the ted_path(relative_path) function to reference .ted files from other template entity directories.

This is a specific property that is intended for template entity authors. A common use-case is to disallow rewrite rules from all .ted files by setting an empty value:

key value
classnameworldspawn
_mess_allow_rewrite_rules{}
NOTE

Some editors will remove custom properties if their value is empty, hence the use of {} - an MScript expression that evaluates to an empty string.


_mess_deny_rewrite_rules

Adding this property to a (template) map will block rewrite directives from the .ted file paths listed in this property. Paths can cover specific files or entire directories, and do not need to contain a .ted extension. This property is removed afterwards.

Relative paths are relative to the directory that contains the current (template) map. Multiple paths must be separated by comma's (,). Use the ted_path(relative_path) function to reference .ted files from other template entity directories.

This is a specific property that is intended for template entity authors. For example, this blocks the rewrite rule that enables target patterns:

key value
classnameworldspawn
_mess_deny_rewrite_rules{ted_path('target_pattern_handler.ted')}

_mess_replace_texture

This is a set of properties that can be used to replace textures on a brush entity. As with all the other special properties, they are removed from an entity after any textures have been replaced.

There are several ways to use this property. The most basic usage is as following:

key value
classnamefunc_wall
_mess_replace_texture redwallbluewall
_mess_replace_texture redfloorbluefloor
_mess_replace_texturenull

This will replace the 'redwall' texture with 'bluewall', the 'redfloor' texture with 'bluefloor', and any other texture with 'null'. If the last property was left out, then only the 'redwall' and 'redfloor' textures would be replaced - any other textures would remain unchanged. Note that texture name comparisons are case-insensitive, so 'redwall' also matches 'REDWALL' and 'REDwall'.

An alternative to the above is to use a single MScript object that contains multiple replacement rules. For example, this achieves the same as the previous set of properties:

key value
classnamefunc_wall
_mess_replace_texture{{redwall: 'bluewall', redfloor: 'bluefloor', '': 'null'}}

Finally, it's also possible to use an MScript function to decides which textures to replace:

key value
classnamefunc_wall
_mess_replace_texture{name => name.contains('red') ? name.replace('red', 'blue') : name.contains('grey') ? 'null' : ''}

This replaces any texture whose name contains 'red' by replacing the 'red' in their name with 'blue', so not only does it replace 'redwall' with 'bluewall' and 'redfloor' with 'bluefloor', it also replaces 'redceiling' with 'blueceiling' and 'credit' with 'cbluedit'. Any texture that does not contain 'red' but does contain 'grey' will be replaced with 'null', and any other textures are left unchanged.

MScript string comparisons are case-sensitive by default, so to avoid problems, texture names are converted to lowercase before being passed into the replacement function.


7.1.3. Lifted properties

Normally, expressions in properties can only reference properties from their parent entity, but in some cases it's useful to reference properties from the same entity. One particular case is with TrenchBroom linked groups: by default, all copies of a linked group will have the same entity properties, so if a linked group contains a button and a door that is opened by that button, then pressing a button in any of the copies will open the doors in all copies.

Properties in linked group copies can be overridden, but that is somewhat tedious and easily forgotten. Instead, we can tell MESS to lift the special _tb_group property that gets added to entities that are part of a linked group. This property contains a number that is unique for every linked group copy. With this, a linked group that contains the following entities:

key value
classnamefunc_button
targetdoor{_tb_group}
key value
classnamefunc_door
targetnamedoor{_tb_group}

will, when two copies of the group are made, produce the following entities:

key value
classnamefunc_button
targetdoor1
key value
classnamefunc_door
targetnamedoor1

and:

key value
classnamefunc_button
targetdoor2
key value
classnamefunc_door
targetnamedoor2

The exact numbers will vary depending on how many other linked groups the map contains, but the point is that each copy now automatically gets unique entity names. In this case that means that a button from one copy will only open the door from that copy, instead of all doors.

See also: configuration file: lifted-properties and Creating interactive linked groups in TrenchBroom.

7.1.4. Array property keys

If a property key consists of a single MScript expression that returns an array, then MESS will turn that property into multiple properties, one for every value in that array. The property value should also produce an array of equal length, so each property can be given a specific value. If the property value array is too short, then the value for the last few properties will be empty.

For example, an entity with the following properties:

key value
classnamemulti_manager
{['a', 'b', 'c']}{[1, 2, 3]}

will, after processing, contain these properties:

key value
classnamemulti_manager
a1
b2
c3

This can be particularly useful when combined with array functions. For example, the following entity:

key value
classnamemtl_trigger_random
{range(0, 5).map(n => 'target' + n)}{repeat(8, 2).concat(repeat(10, 3))}

will become:

key value
classnamemtl_trigger_random
target08
target18
target210
target310
target410

It's also possible to copy properties from a parent entity, by using the parent entity property functions (a parent entity is the macro entity that is creating an instance of the current template):

key value
classnamemulti_manager
{get_attr().map(a => a.key)}{get_attr().map(a => a.value)}

This will copy all parent entity properties, including standard properties like classname, origin, targetname, and so on. In practice, certain properties will need to be excluded. This can be done with the filter function. Because both the key and value array must be filtered, it's better to do this in a template property, so the filter doesn't need to be repeated.

7.1.5. Empty property keys

If, after evaluating MScript expressions, a property key is empty, MESS will remove that property. In this case, any MScript expressions in its value will not be evaluated.

In the following example entity, all keys except classname end up being empty:

key value
classnametrigger_relay
{}empty
{''}also empty
{1 == 0 ? 'killtarget' : ''}conditionally empty

So the resulting entity will only contain the classname property:

key value
classnametrigger_relay

The last property shows how the ?: conditional operator can be used to exclude properties based on certain conditions. For example, a trigger_relay entity only needs a killtarget property if it needs to kill another entity.