-
Notifications
You must be signed in to change notification settings - Fork 13
EDT Map script 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.
- 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
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:
- sourcemod/data/srccoop/mapname.edt
- 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.
The entity list for current map can be dumped to a file with sc_dump
.
#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 ofentity
. 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.
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 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
{
...
}
}
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.
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.
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.
"~fd value" translates to context flags [f, d] and value "value"
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 |
Sets up enabled plugin features for the map. Usually defaulted in base configs.
Example - disable first person death camera:
"features"
{
"FIRSTPERSON_DEATHCAM" "0"
}
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"
}
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.
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 |
- 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"
}
Lets you setup console variables (convars) for the map that will be sent to players.
Flag | Description |
---|---|
S | Applied every time the player spawns (as opposed to first join) |
- Turn off drawing flashlights from other players
"client_console"
{
"r_flashlight_3rd_draw" "0"
}
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"
}
}
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.
alt: create
Adds an entity.
Example - add an ambient_generic:
"add"
{
"classname" "ambient_generic"
"targetname" "gman_offer_fix"
"spawnflags" "49"
"message" "endgame.gman.wiselydone01"
}
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"
}
alt: edit
Modifies entities with matching properties. Additional properties narrow down the filter. Supports regex in key and value.
Udates or adds an entity property if missing, never adding duplicates.
This is the preferable choice for most occasions (vs add/replace).
alt: create
Adds properties to the entity. Does not check for duplicate properties.
Updates existing properties, never creating new ones.
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" ""
}
}
M/A = Modify or Add
When modifying or adding an entity, there are additional helpers, used as subsections, which allow for advanced editing.
Special functions provided by the plugin.
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"
}
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"
}
}
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"
}
}
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"
}
}
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 |
Example - add an output. Parameter, delay and timestofire are defaulted:
"outputs"
{
"add"
{
"output" "OnFullyOpen"
"target" "!self"
"input" "Lock"
}
}
Example - remove all outputs where the input is "Close":
"outputs"
{
"remove"
{
"input" "Close"
}
}
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"
}
}
}
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 |
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.