Survival Gametype (L4D)
This article includes basic instructions for creating a Survival mode map for Left 4 Dead.
Starting Survival
Survival rounds begin by triggering any form of panic event.
Any entity capable of telling the Director to force a Panic Event will work. Such as func_button, func_button_timed, trigger_finale, trigger_once, prop_car_alarm or even that one song on the Jukebox.
This is set up in the same method as starting a finale or crescendo event.
All Survival mode maps rely on using the "Finale" or "Battlefield" and the optional "Battlestation" attribute on your navigation mesh to define the play space for the Survival mode. Setting up the Nav mesh works differently based on whether your map is exclusively for survival, or if it adds survival mode to maps already used for campaigns.
Pure Survival Maps
If your map is only meant for survival, select the starting area navmesh In Nav edit mode and use the command "mark Player_start". to mark it as starting location.
Afterwards use the console command "nav_select_radius 1000000000" to select the entire navmesh and mark it using the command "mark finale".
Also, the "Battlestation" attribute can be used to define good holdout spots for the Survivor Bots, which will then prefer to stick to that area. This is set up in the same way as finales or Crescendo Events.
For pure survival maps, it is possible to control which areas infected can spawn in by either marking all areas with both "Finale" and "Battlefield" and then removing the "Finale" attribute from areas to disable spawning there. Note that this will break navigation for other game modes.
Template:ModernNote
Multi-Gamemode Maps
Existing crescendo or finale events that use the "Battlefield'" or "Finale" nav attributes can often be used without any changes to the nav mesh.
If your map adds survival sections to a coop map, add a func_nav_attribute_region encasing the area you want to play Survival in, as well as areas where infected should spawn for survival.
Call it "survival_nav_battlefield" and enable the Flag "Battlefield". You may also add additional "func_nav_attribute_region" entities of same names for more attributes like "Battlestation", where Survivor bots tend to stay.
Template:ModernNote
To enable the nav attributes, you need a info_gamemode entity which force spawns a point_template entity with the output OnSurvivalPostIO.
My Output | Target Entity | Target Input | Parameter | Delay | Only Once | |
---|---|---|---|---|---|---|
![]() |
OnSurvivalPostIO | Point_template | ForceSpawn | <none> | 0.0 | No |
This very same point_template can be used to spawn all other entities required by survival, such as all weapons and props to block paths.
info_survivor_position
Survivors spawn at info_survivor_position entities.
Unfortunately finale maps use the same entity to "teleport" the survivors away when approaching the escape vehicle. If your survival map is also the finale of a campaign, or if your map uses the info_survivor_position for anything but the survival spawnpoint, you will need to delete those. Else your players might spawn at the wrong place.
Delete the extra info_survivor_position entities via the Info_gamemode entity, using the following outputs
My Output | Target Entity | Target Input | Parameter | Delay | Only Once | |
---|---|---|---|---|---|---|
![]() |
OnSurvival | info_survivor_position used by finale | kill | <none> | 0.0 | No |
Items
In L4D, all placed items in the map will spawn in survival mode regardless of the normal densities allowed in other modes. If you wish to change the item placement or numbers, you can use the info_gamemode to spawn or kill items.
In L4D2, all item spawns are removed in survival mode.
In order to spawn items, you must give every intended survival item a name. You may give all of them the same name to make it easier.
Template:ModernNote
Add a point_template, give it a unique name which lists all survival item names in its "Template" lines.
Add a info_gamemode entity with the following outputs
My Output | Target Entity | Target Input | Parameter | Delay | Only Once | |
---|---|---|---|---|---|---|
![]() |
OnSurvivalPostIO | Point_template | ForceSpawn | <none> | 0.0 | No |
info_gamemode - other uses
Maps are able to load different entities, depending on which gamemode the map is run in. As mentioned in the previous section, survival gamemodes in L4D2 require a info_gamemode and point_template to spawn any items in survival gamemode at all.
The same two entities can be used to load func_brush walls, clip brushes, prop_dynamic, items, or any other sort of entity into your map for survival gamemodes. Like adding barricade props to stop players from reaching the end map saferoom.
Alternatively, you could use info_gamemode along with a logic_relay to delete items you do not wish to have in survival, like Alarm cars which when shot would start the survival round prematurely.
Mission file and testing
Before you can test your map in survival mode, you must add your map to the mission files "survival" mode section.
Example:
"modes" { "survival" { "1" { "Map" "mymap" "DisplayName" "My survival Map" "Image" "maps/preview_01" } } }
The map can be loaded into survival either through the main menu, or using the console via the Command "map mapname_here survival". The latter allows you to use sv_cheats 1 while on survival mode.
Changing Default Settings via Vscript
Most, if not all, settings of survival gamemode are sets of console commands. This means that we can change how the gamemode behaves almost in its entirety.
The following Vscript can be added to any point_entity's Vscript Variable. Preferably info_director. Once the map launches, it will swap all settings with the ones you had defined.

survival_horde_stage_interval_decay
set to 0 will stop hordes from appearing in shorter intervals.// Survival Convars
Convars.SetValue("director_survival_setup_time", 0) //default: 0 - Time limit to set up before the round auto-starts.
Convars.SetValue("survival_boomer_limit_increase", 0) //default: 0 - After each special wave, increase max boomers by this amount.
Convars.SetValue("survival_charger_limit_increase", 0) //default: 0 - After each special wave, increase max chargers by this amount.
Convars.SetValue("survival_horde_stage_interval", 60) //default: 60 - Seconds between horde attacks
Convars.SetValue("survival_horde_stage_interval_decay", 2) //default: 2 - After each horde attack, reduce the interval by this many seconds
Convars.SetValue("survival_hunter_limit_increase", 1) //default: 1 - After each special wave, increase max hunters by this amount.
Convars.SetValue("survival_jockey_limit_increase", 1) //default: 1 - After each special wave, increase max jockeys by this amount.
Convars.SetValue("survival_lull_time", 15) //default: 15 - Lull duration between survival waves.
Convars.SetValue("survival_lull_time_increment", 15) //default: 15 - Increment for the lull time per wave.
Convars.SetValue("survival_lull_time_max", 60) //default: 60 - Max lull duration.
Convars.SetValue("survival_max_boomers", 2) //default: 2 - Max boomers alive at one time.
Convars.SetValue("survival_max_chargers", 2) //default: 2 - Max chargers alive at one time.
Convars.SetValue("survival_max_hunters", 3) //default: 3 - Max hunters alive at one time.
Convars.SetValue("survival_max_jockeys", 2) //default: 2 - Max jockeys alive at one time.
Convars.SetValue("survival_max_smokers", 4) //default: 4 - Max smokers alive at one time.
Convars.SetValue("survival_max_specials", 8) //default: 8 - Max number of special zombies alive at one time.
Convars.SetValue("survival_max_spitters", 3) //default: 3 - Max spitters alive at one time.
Convars.SetValue("survival_round_restart_delay", 15) //default: 15 - After a loss, restart the round after this many seconds.
Convars.SetValue("survival_smoker_limit_increase", 1) //default: 1 - After each special wave, increase max smokers by this amount.
Convars.SetValue("survival_special_limit_increase", 1) //default: 1 - After each special wave, increase max specials by this amount.
Convars.SetValue("survival_special_spawn_interval", 20) //default: 20 - Seconds between special spawn waves
Convars.SetValue("survival_special_spawn_interval_decay", 1) //default: 1 - After each special wave, reduce the spawn interval by this many seconds
Convars.SetValue("survival_special_stage_interval", 60) //default: 60 - After this many seconds, increase special zombie limits
Convars.SetValue("survival_spitter_limit_increase", 1) //default: 1 - After each special wave, increase max spitters by this amount.
Convars.SetValue("survival_tank_multiple_spawn_delay", 10) //default: 10 - Delay between the two tanks during double spawns.
Convars.SetValue("survival_tank_stage_interval", 80) //default: 80 - Seconds between tank attacks
Convars.SetValue("survival_tank_stage_interval_decay", 20) //default: 20 - After some number of waves, reduce the interval by this many seconds
DirectorOptions <-
{
//Intentionally left blank.
//Is required for the below Mutation15 stuff to work.
}
//Mutation15 (Versus survival) Convars. Only changed when mutation 15 is ran.
if ( Director.GetGameMode() == "mutation15" )
{
DirectorOptions.ActiveChallenge <- 1;
DirectorOptions.cm_ProhibitBosses <- 0;
DirectorOptions.cm_CommonLimit <- 25;
DirectorOptions.cm_TankLimit <- 1;
DirectorOptions.ZombieTankHealth <- 2667;
DirectorOptions.SurvivalSetupTime <- 90;
// 90 seconds to auto start survival. This only triggers "PanicEvent"
// If you have any entity to trigger that also starts animations, opens doors and plays sound;
// Use the timer below to auto trigger the entity that starts the entire survival gamemode,
// then change SurvivalSetupTime to trigger right when the relay would fire its own output.
// Keep in mind, Special infected ghosts (not spawned players) cannot walk through prop_dynamic doors.
// If you have gates that are crucial to walk through, before the round starts for the SI Ghosts to get to their spots, open those doors way in advance.
// Fires logic_relay named "Survival_Start_relay" 89 seconds after spawning into the round.
// The relay itself would fire "ForcePanicEvent" after one second. So it aligns with "SurvivalSetupTime" above
function OnGameEvent_round_start_post_nav(params){
DoEntFire("Survival_Start_relay", "trigger", "", 89, null, null)
}
Convars.SetValue("director_special_initial_spawn_delay_max", 10) //coop default: 60 - mutation15 default: 10
Convars.SetValue("director_special_initial_spawn_delay_min", 2) //coop default: 30 - mutation15 default: 2
Convars.SetValue("tongue_break_from_damage_amount", 300) //coop default: 50 - mutation15 default: 300
Convars.SetValue("tongue_choke_damage_amount", 5) //coop default: 10 - mutation15 default: 5
Convars.SetValue("tongue_dropping_to_ground_time", 0.5) //coop default: 2 - mutation15 default: 0.5
Convars.SetValue("tongue_hit_delay", 15) //coop default: 20 - mutation15 default: 15
Convars.SetValue("tongue_los_forgiveness_time", 1.5) //coop default: 1 - mutation15 default: 1.5
Convars.SetValue("tongue_miss_delay", 3) //coop default: 15 - mutation15 default: 3
Convars.SetValue("tongue_no_progress_choke_early_delay", 1.0) //coop default: 1.5 - mutation15 default: 1.0
Convars.SetValue("z_ghost_los_expected_progress", 2000) //coop default: 1500 - mutation15 default: 2000
Convars.SetValue("z_hunter_limit", 2) //coop default: 1 - mutation15 default: 2
Convars.SetValue("z_jockey_ride_damage", 2) //coop default: 4 - mutation15 default: 2
Convars.SetValue("z_jockey_ride_damage_interval", 0.5) //coop default: 1 - mutation15 default: 0.5
Convars.SetValue("z_max_stagger_duration", 0.9) //coop default: 6 - mutation15 default: 0.9
Convars.SetValue("z_pounce_damage_interrupt", 150) //coop default: 50 - mutation15 default: 150
Convars.SetValue("z_pounce_stumble_radius", 160) //coop default: 0 - mutation15 default: 160
Convars.SetValue("z_scrimmage_creep_delay", 0) //coop default: 30 - mutation15 default: 0
Convars.SetValue("z_scrimmage_creep_rate", 100) //coop default: 30 - mutation15 default: 100
Convars.SetValue("z_smoker_limit", 2) //coop default: 1 - mutation15 default: 2
Convars.SetValue("z_spawn_safety_range", 200) //coop default: 550 - mutation15 default: 200
}