Skip to content

EDT Map script format

Alienmario edited this page Oct 28, 2024 · 27 revisions

EDT format

Our edt file format takes some inspiration from Synergy and Stripper:Source, however, has been built from the ground up specifically for the needs of this project. It allows to configure a map with co-op related settings as well as do some significant modifications to it. It uses Valve's keyvalues syntax which can inherit properties from parent configs.

Features

  • Checkpoint system
  • Equipment system
  • Advanced entity editing system
  • Conditions (if-then-else)
  • Regex matching
  • Delayed mapchange and delayed map start support
  • Support for various map intros
  • Setup convars, plugin features and more

Adding coop support

To enable coop mode on desired map, an edt file for it needs to be created first. EDTs are searched at locations in this order:

  1. sourcemod/data/srccoop/mapname.edt
  2. maps/mapname.edt (This location can also be loaded from inside the bsp, therefore enabling embedded configs)

If you're adding a new edt, it's recommended to start with the included samples.

Dumping map entities

The entity list for current map can be dumped to a file with sc_dump.

Full documentation

General information

Structure

#base "..."

"config"
{
	"param1" "value"
	"param2" "another value"
	// ..etc.. (this is a comment)
	
	"features"
	{}
	"define"
	{}	
	"console"
	{}
	"equipment"
	{}
	"entity"
	{}
	"checkpoint"
	{}
}
  • config is the root element and is required. It can contain properties and other sub-elements.
  • elements inside config are optional
  • #base optionally specifies the parent config to inherit values from. The path is relative to the current file. Think of it as copying elements from the parent to this file, with this file taking precedence if property names clash. Multiple levels of nesting are allowed.
  • base configs may use "base" subsection naming. E.g. entity_base_mybaseconfig instead of entity. This is especially useful when using #if conditions or for entity edits. When multiple keyvalue files get merged together, they would get "corrupted" due to merging of identical key names from both files.

Regex

By putting a value between forward slashes, you can create a regex match. This uses sourcemod's internal regex extension, that is PCRE. Regex is supported in most properties that match some value.

Examples:

Regex Description
"/^(suit|weapons|ammo)$/" Matches the values "suit", "weapons" or "ammo"
"/^snds_conveyors/" Matches all values starting with "snds_conveyors"
"/.*/" Matches all possible values

Go to regex101.com to test and build your regexes.

Conditions

Conditions allow to selectively parse sub-elements by testing the given condition against known states. The #else block is optional.

Basic - all conditions must be true:

#if
{
	"condition1" "tested value"
	"condition2" "tested value"
	...
	
	#then
	{
		...
	}
	#else
	{
		...
	}
}

At least 1 condition must be true:

#if
{
	#any
	{
		"condition1" "value"
		"condition2" "value"
	}
	#then
	{
		...
	}
	#else
	{
		...
	}
}

Mixing and nesting is possible - either condition 1 or both 2 and 3 must be true:

#if
{
	#any
	{
		"condition1" "value"
		#all
		{
			"condition2" "value"
			"condition3" "value"
		}
	}
	#then
	{
		...
	}
	#else
	{
		...
	}
}

Available conditions

Condition Description
globalstate Tests whether the given engine global state is currently active
prevmap Tests for the name of previous map
os Tests the server operating system - linux or windows

To negate the condition, add ! in front of it.

When a condition is not found, the "define" list is searched. If the condition is not even found in defines, the result will be false.

Context flags

Some sections allow you to specify custom flags inside their key-values, making it possible to give the plugin extra context on how the given value should be processed. These are called context flags.

Format

Context flags are simple characters in a row at the beginning of a value.

They are prefixed with ~ (tilda) and end with a space, followed by the actual value.

If a ~ character is needed at the beginning of the value, double tilda "~~etc" can be used instead.

Example

"~fd value" translates to context flags [f, d] and value "value"

Sections

Config

Property Plugin Type Description Repeatable Regex Default
campaign voting string The campaing, used as first category for map voting.
chapter voting string The chapter, used as second category for map voting.
nextmap core string Tells the mod which trigger_changelevel entities are allowed by comparing their map name with this value. Depending on the transitions in the map, can be specified to prevent players from backtracking. ✔️ ✔️
intro_type core string Used together with delayed entity outputs.
"freeze" - freezes players in place until everyone connects or the startup timer runs out
"none" - players walk around freely
"fade" - same as freeze but holds the screen black.
none
voting_skip_to voting string If this is an intro map, set the map a successful skip vote will change to.
voting_skip_autostart voting bool If this is an intro map, whether to start a skip vote automatically. 0
allow_server_download workshop manager bool 1 to use direct server download for workshop maps. Not recommended - see "Authoring maps for SourceCoop". 0

Config➡️Features

Sets up enabled plugin features for the map. Usually defaulted in base configs.

Example - disable first person death camera:

"features"
{
	"FIRSTPERSON_DEATHCAM" "0"
}

Config➡️Define

Sets up defines, which consist of a name and value (like convars).

Usually setup in base configs and overridden in map config as a form of communication between the two.

For example, the base config can do a specific action, only if the define is set to 1. The map config can override the define to 0 to prevent the action.

Example - base/pizza_base.edt:

"define"
{
	"all_is_pizza" "1"
}
"entity_base_pizza"
{
	#if
	{
		"all_is_pizza" "1"
		#then
		{
			"modify"
			{
				"model" "/.*/"
				"set"
				{
					"model" "models/props_junk/interdimensional_pizza.mdl"
				}
			}
		}
	}
}

melon_map.edt:

"define"
{
	"all_is_pizza" "0"
}

Config➡️Console

Lets you setup server console variables (convars) for the map. They are, by default, applied before any server configs and are reverted to their default value after the map ends.

Context flags

Flag Description
H Hides the convar (unavailable to console access, unless using sm_cvar)
L Late convars are set after server configs (thus overriding them)
F Forces the convar value throughout the duration of the map

Examples

  • Enable item spawn effects by default
"console"
{
	// won't stick if server.cfg also sets this convar
	"sv_mp_spawneffect_item" "1"
}
  • Override server setting for mp_flashlight
"console"
{
	// will override server.cfg
	"mp_flashlight" "~L 1"
}

Config➡️Client Console

Lets you setup console variables (convars) for the map that will be sent to players.

Context flags

Flag Description
S Applied every time the player spawns (as opposed to first join)

Examples

  • Turn off drawing flashlights from other players
"client_console"
{
	"r_flashlight_3rd_draw" "0"
}

Config➡️Equipment

Sets up the state and items players spawn with.

Property Plugin Type Description Repeatable Default
health core int Spawn health -1
armor core int Spawn armor (suit) -1
item core string Classname of item to equip ✔️
defaults core bool Allow the game to equip players with its defaults 0
lookup core subsection Imports equipment from map entities. Uses identical matching rules as in the entity section. Matched entities are imported by their classname and removed from the map. ✔️

Example - Spawn with crowbar, mp5, 70 hp and 15 suit:

"equipment"
{
	"defaults" "0"
	"item" "item_weapon_crowbar"
	"item" "item_weapon_mp5"
	"item" "item_suit"
	"health" "70"
	"armor" "15"
}

Example - Import equipment from the map:

"equipment"
{
	"lookup"
	{
		"targetname" "items_at_start"
	}
}

Config➡️Entity

This section allows modifying map's entities before the level starts. Modifications are processed sequentially, so for example if you add a prop entity, then remove all props, your prop will be removed too.

Small number of entities are precompiled into the map and cannot be modified - for example static lights and static props.

Brush entities have a "model" property which starts with * followed by number. The matching geometric model representation is saved separately in a different "lump" of the map and cannot be altered. SourceCoop can however create basic "box" brushes that can be used for invisible entities, like triggers.


Config➡️Entity➡️Add

alt: create

Adds an entity.

Example - add an ambient_generic:

"add"
{
	"classname" "ambient_generic"
	"targetname" "gman_offer_fix"
	"spawnflags" "49"
	"message" "endgame.gman.wiselydone01"
}

Config➡️Entity➡️Remove

alt: delete

Deletes entities with matching properties. Additional properties narrow down the filter. Supports regex in key and value.

Example - delete entity with name trigger_slamdoor:

"delete"
{
	"targetname" "trigger_slamdoor"
}

Config➡️Entity➡️Modify

alt: edit

Modifies entities with matching properties. Additional properties narrow down the filter. Supports regex in key and value.

➡️ Set

Udates or adds an entity property if missing, never adding duplicates.

This is the preferable choice for most occasions (vs add/replace).

➡️ Add

alt: create

Adds properties to the entity. Does not check for duplicate properties.

➡️ Replace

Updates existing properties, never creating new ones.

➡️ Remove

alt: delete

Removes properties from the entity.

  • if the value is empty "", only the key is matched
  • if the value is specified, both the key and value are matched

Example - make a changelevel entity stay enabled:

"modify"
{
	"targetname" "c1a4a_c1a4b_transition"
	"set"
	{
		"StartDisabled" "0"
	}
	"remove"
	{
		"targetname" ""
	}
}

Config➡️Entity➡️M/A

M/A = Modify or Add

When modifying or adding an entity, there are additional helpers, used as subsections, which allow for advanced editing.

Config➡️Entity➡️M/A➡️Functions

Special functions provided by the plugin.

delay_output

Delays the named output until after the initial readyup timer completes.

Example - to delay the common outputs from logic_auto entity:

"functions"
{
	"delay_output" "OnNewGame"
	"delay_output" "OnMapSpawn"
}
copy_model

Copies the model value from the matched entity to this entity. Also copies "origin" if found. Care should be taken that only 1 entity matches.

Example - copy the model from the entity named "trigger_c1a2c_c1a3a" to this entity:

"functions"
{
	"copy_model"
	{
		"targetname" "trigger_c1a2c_c1a3a"
	}
}
set_model

Create a "box" model for this entity. This uses a workaround that runs after the map starts. Only usable for invisible brush entities.

Example - set by origin and size:

"functions"
{
	"set_model"
	{
		"origin" "-1896 2104 -320"
		"size" "64 16 191"
	}
}

Example - set by 2 corners from, to:

"functions"
{
	"set_model"
	{
		"from"	"544 -576 -672"
		"to"	"-264 256 -776"
	}
}

Config➡️Entity➡️M/A➡️Flags

Removes or adds specific flags.

Tip: to get a spawnflag's number in Hammer, make it the only one selected, then turn off smart edit.

Example - add num. 2048 and remove num. 1, 2 spawnflags:

"flags"
{
	"spawnflags"
	{
		"add" "2048"
		"remove" "1"
		"remove" "2"
	}
}

Config➡️Entity➡️M/A➡️Outputs

Allows adding, removing or modifying the matched entities' outputs.

Output keys:

Key Description Default
output Output name
target Target entity name
input Target entity input
parameter Optional parameter [none]
delay Delay in secs 0
timestofire Number of fires before removing itself. -1 = no limit 1
Add

Example - add an output. Parameter, delay and timestofire are defaulted:

"outputs"
{
	"add"
	{
		"output"	"OnFullyOpen"
		"target"	"!self"
		"input"		"Lock"
	}
}
Remove

Example - remove all outputs where the input is "Close":

"outputs"
{
	"remove"
	{
		"input" "Close"
	}
}
Modify

Example - replace input in an output matched by "target" and "input":

"outputs"
{
	"modify"
	{
		"target" "c2a1a_c2a1b_changelevel"
		"input" "ChangeLevel"
		"replace"
		{
			"input" "Enable"
		}
	}
}

Advanced example - replace input in an output matched by searching potential target entity's properties:

"outputs"
{
	"modify"
	{
		"input" "Enable"
		"target"
		{
			"classname" "point_viewcontrol"
		}
		"replace"
		{
			"input" "EnableAll"
		}
	}
}

Config➡️Checkpoint

Property Plugin Type Description Repeatable Regex Default
use_map_spawnpoint core bool Add spawn point from map as the first checkpoint (currently just info_player_start). 0
use_map_autosave core bool Add autosave from map as checkpoints (currently just trigger_autosave). 0
strict_order core bool 1 = Checkpoints are specified in order of progression. Activation of one will also mark all preceding unactivated checkpoints as activated. Not applicable if using use_map_autosave.
0 = Checkpoints are not ordered. Any checkpoint can become active at any time (once).
1
respawn_on_logic_autosave core bool Whether to respawn players on logic_autosave in survival mode. 1

Config➡️Checkpoint➡️Checkpoint name

Property Plugin Type Description Repeatable Regex Default
:: Teleport target ::
origin core vector Destination location 0 0 0
angles core vector Destination orientation 0 0 0
followid core string Set to move the checkpoint with an entity. If set, origin and angles become relative to the center of this entity. If the entity is deleted, its last known position is used. Accepts targetname or hammerid.
:: Triggers ::
triggerid core string Entity which activates this checkpoint with its output. Accepts targetname or hammerid.
output core string Output from the trigger entity which activates this checkpoint.
touchid core string Entity which activates this checkpoint when touched by a player. Accepts targetname or hammerid.
radius core float Min unobstructed distance from destination to any player needed for this checkpoint to self-activate (0 = Disabled) 0
:: Activation ::
delay core float Delays the checkpoint activation, in seconds. 0
bringall core bool Teleport all players here upon activation. 0
bringall_radius core float Bringall exclusion zone (Maximum range from the destination a player is allowed to be in order to not be teleported by bringall.) 0
portal core vector Location of a portal teleporter to spawn when this checkpoint becomes active. Portals always teleport players to active checkpoint and do not despawn (except when multiple occupy same space). They are configurable in gamedata/srccoop_config.games.txt ✔️
respawn core bool Respawn dead players when activated in survival mode? 0
:: Other options ::
spawn core bool By setting 0, you can create portal-only checkpoints - players will not spawn here and have to use portals instead to teleport. 1

Example - add spawn point and 1 checkpoint, in addition to any checkpoints imported from map:

"checkpoint"
{
	"use_map_autosave" "1"
	
	"spawn"
	{
		"origin"	"-13200 -2544 9878"
		"angles"	"0 0 0"
	}
	"doubledoor"
	{
		"origin"	"-10747 -1900 9573"
		"angles"	"0 30 0"
		"triggerid"	"bd_door"
		"output"	"OnOpen"
	}
}

Checkpoints without a trigger are assumed to be initial spawn points and will start activated.

Checkpoint names can be anything descriptive, they are unused at the moment.