For the past 2 months I've been working on a custom compile tool named MESS, short for Macro Entity Scripting System. It enables the creation of templates that can be instantiated throughout a map, and provides a basic scripting language for entity attribute customization. It works by modifying the exported .map file before the other compile tools get to process it.
I'm specifically designing MESS for the following use-cases:
- Treating complicated entity setups as a single 'composite entity' that can be duplicated and customized without having to change entity names and other attributes in each individual entity.
- Sprinking small func_details, models or sprites across a surface or area without having to manually place each object.
You can think of it as something like Hammer's prefab system, except that when you modify a prefab, all instances of it are updated as well, and that each instance can be customized by giving it different attribute values. The trade-off is that you don't get to see the actual result until after you run MESS on the exported .map file.
I used a very early version for my Buddy competition entry: the electric slug and teleporting enemy setups were created in separate template maps, and were inserted in the main map with a special macro entity. Based on that experience I decided to improve on it with a couple of other ideas. Hopefully I can create something release-worthy in a few more weeks.
Macro entities
MESS will provide the following entities:
- macro_insert - Point entity. Creates a single instance of a template in a specific place and with a specific orientation and scale.
- macro_cover - Brush entity. Sprinkles template instances across one or more surfaces (brush faces).
- macro_fill - Brush entity. Sprinkles template instances within an area (inside a brush).
- macro_template - Brush entity. Anything inside its bounding box becomes part of a template that can be used by the above 3 entities.
- macro_remove_if - Brush entity. Used inside templates. Anything inside its bounding box can be excluded from an instance, if the removal condition is met.
Templates can contain insertion entities, so it's possible to create recursive templates. It's also possible to use other map files as templates. I'm also thinking about creating a custom .fgd system that lets you create your own 'entities', which act as aliases for insertion entities with specific attributes (e.g. an 'env_warpball' entity would be treated as a 'macro_insert' entity that references a 'warpball.rmf' template map).
Scripting system
Here's an example of how the scripting system works. Imagine a 'rat hunt' rat template that consists of a model, a func_breakable 'hitbox' and a trigger_relay that triggers something when the rat is 'killed'. The scripting system takes the attributes of the insertion entity:
targetname = super_rat
template = rat_template
health = 100
and makes these attributes available to all entities in the selected template:
targetname = ratdie_{targetname} --> ratdie_super_rat
target = {target_on_kill OR 'ratcount'} --> ratcount (because the insertion entity doesn't have a 'target_on_kill' attribute)
delay = 0.5
killtarget = {targetname} --> super_rat
triggerstate = 2
material = 3
target = ratdie_{targetname} --> ratdie_super_rat
health = {health OR 1} --> 100
gibmodel = models/hgibs.mdl
targetname = {targetname} --> super_rat
model = models/bigrat.mdl
framerate = 1
Anything between curly braces is treated as an expression, and will be evaluated to produce the final attribute value. I'm also working on various utility functions, for things like fetching a unique instance ID or generating semi-random numbers.
I still need to finish up the scripting system, and each of the insertion entities requires some more work to make them fully functional, so it'll be a couple of weeks before I can release anything. Please let me know if this sounds interesting or useful, or if there are other tedious things you wish could be automated when creating a level.