Left 4 Dead 2/Scripting: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
m (Substituted IO templates)
 
(50 intermediate revisions by 16 users not shown)
Line 1: Line 1:
{{otherlang2
{{LanguageBar}}
|noborder=true
{{TabsBar|main=Scripting}}
|zh-cn=L4D2_Vscripts:zh-cn
{{back|Left 4 Dead 2/Docs}}
}}
{{toc-right}}


{{toc-right}}
== Useful links ==
{{sq}}{{l4d2}} '''Left 4 Dead 2 [[VScript|VScripts]]''' are server-side scripts that are run in an in-game virtual machine. They are written in [[Squirrel]], a compiled scripting language similar to [http://www.lua.org/ Lua].
* [[/Game Events|List of game events]]
* [[/Script Functions|List of script functions]]
* [[/Director Scripts|Director Scripts]]
* [[/Expanded Mutation System|Expanded Mutation System]]
* [[/Mutation Gametype|Mutation Gametype]]
* [[/Decrypted mutations|Decrypted mutations]]


== Overview ==
{{sq}}{{l4d2}} '''Left 4 Dead 2 [[VScript]]s''' are server-side scripts that are run in an in-game virtual machine. They are written in [[Squirrel]], a compiled scripting language similar to [http://www.lua.org/ Lua]. It currently runs Squirrel version 3.0.4.


== Uses ==
== Uses ==


=== [[L4D2_Director_Scripts|Director Scripts]] ===
=== [[L4D2_Director_Scripts|Director Scripts]] ===
The most common use of [[VScript|VScripts]] in Left 4 Dead 2 is to influence the behavior of the AI Director. These scripts can range from simple adjustments of infected spawning and [[L4D2_Level_Design/Boss_Prohibition|prohibiting boss infected]], to custom events like onslaughts and gauntlets, and even complex staged panic events and fully [[L4D2_Level_Design/Custom_Finale|custom finales]]. Most of the events in the official campaigns are mainly implemented this way.
The most common use of [[VScript]]s in ''Left 4 Dead 2'' is to temporarily influence the behavior of the AI Director. These scripts can range from simple adjustments of infected spawning and [[L4D2_Level_Design/Boss_Prohibition|prohibiting boss infected]], to custom events like onslaughts and gauntlets, and even complex staged panic events and fully [[L4D2_Level_Design/Custom_Finale|custom finales]]. Most of the events in the official campaigns are mainly implemented this way.


Director Scripts work mainly by writing overriding values of the various variables used by the Director into a <code>DirectorOptions</code> table.
Director Scripts work mainly by writing overriding values of the various variables used by the Director into a <code>DirectorOptions</code> table.
Line 17: Line 24:
Only one Director Script can be running at a time. Executing a new one will terminate any previous running one and remove any values it set in <code>DirectorOptions</code>.
Only one Director Script can be running at a time. Executing a new one will terminate any previous running one and remove any values it set in <code>DirectorOptions</code>.


=== [[#Entity Scripts 3|Entity Scripts]] ===
=== [[#Entity Scripts 2|Entity Scripts ]] ===
Another common use is to attach a script to an entity. The script provides easy access to read and modify many of the entity's properties, and even to write new [[KeyValues]]. This allows for controlling entities in ways that would be very complicated or impossible to with the entity I/O system in Hammer.
Another common use is to attach a script to an entity. The script provides easy access to read and modify many of the entity's properties, and even to write new [[KeyValues]]. This allows for controlling entities in ways that would be very complicated or impossible to with the entity I/O system in Hammer.


Any entity is capable of running a script, and has the ability to set a specified ''think'' function to run every 0.1 seconds, as well as executing script code as an entity output.
Any entity is capable of running a script, and has the ability to set a specified ''think'' function to run every 0.1 seconds, as well as executing script code as an entity output.


Some entities also have specialized functions for VScripts, with the most prominent being [[point_script_use_target]], which allows for turning other entities into fully programmable timed buttons.  
Some entities also have specialized functions for VScripts, with the most prominent being {{ent|point_script_use_target}}, which allows for turning other entities into fully programmable timed buttons.  


=== [[#Global Scripts 3|Global Scripts]] ===
=== [[#Global Scripts 2|Global Scripts ]] ===
Scripts can also be made to run on map load, based on game mode and optionally map name. These scripts are commonly used to create scripting and modify global Director options for [[Mutation_Gametype_(L4D2)|mutations]], but can also be used in custom maps.
Scripts can also be made to run on map load, based on game mode and optionally map name. These scripts are commonly used to create pure script addons and modify global Director options for [[Mutation_Gametype_(L4D2)|mutations]].


Global scripts can have [[List_of_L4D2_Script_Functions#Scripted_Mode_hooks|script hook functions]] added that get called from the game at certain events, like when players/objects take damage.  
Global scripts can have [[Left 4 Dead 2/Script Functions#Scripted_Mode_hooks|script hook functions]] added that get called from the game at certain events, like when players/objects take damage.  


There are many utility functions and features readily available for these scripts, including a resource and building system, and custom panic wave spawning. Please see Valve's [[L4D2_EMS|Expanded Mutation System tutorial]] for more information.
There are many utility functions and features readily available for these scripts, including a resource and building system, and custom panic wave spawning. Please see Valve's [[L4D2_EMS|Expanded Mutation System tutorial]] for more information.


=== Other uses ===
=== Other Uses ===
All scripts can access functions for many features, including [[L4D2_EMS/Appendix:_Spawning|spawning entities]] either from precompiled lists or programmatically, [[L4D2_EMS/Appendix:_Spawning_Infected|spawning infected]], a [[L4D2_EMS/Appendix:_HUD|HUD system]], [[L4D2_EMS/Appendix:_Table_Save_Restore|storing data]] across levels and to disk, and much more.
All scripts can access functions for many features, including [[L4D2_EMS/Appendix:_Spawning|spawning entities]] either from precompiled lists or programmatically, [[L4D2_EMS/Appendix:_Spawning_Infected|spawning infected]], a [[L4D2_EMS/Appendix:_HUD|HUD system]], [[L4D2_EMS/Appendix:_Table_Save_Restore|storing data]] across levels and to disk, and much more.


Please see [[L4D2 Vscript Examples]] for more examples and ideas.
Please see [[L4D2 Vscript Examples]] for more examples and ideas.


 
== Script Files ==
== Script files ==
The scripts are loaded from text files with the file extensions <code>.nut</code> and <code>.nuc</code>, where <code>.nuc</code> denotes encryption of plaintext <code>.nut</code>. Custom scripts are read from '''\left 4 dead 2\left4dead2\scripts\vscripts\''', as well as '''\scripts\vscripts\''' when packed into a <code>.vpk</code> file.
The scripts are loaded from text files with the file extensions <code>.nut</code> and <code>.nuc</code>, where <code>.nuc</code> denotes encryption of plain text <code>.nut</code>. Custom scripts are read from '''\left 4 dead 2\left4dead2\scripts\vscripts\''', as well as '''\scripts\vscripts\''' when packed into a .vpk file.


=== Location ===
=== Location ===
;Official .nuc script files are located in '''scripts/vscripts''' in multiple locations
;Official <code>.nuc</code> script files are located in '''scripts/vscripts''' in multiple locations
{{note|Browse and extract [[VPK]] files with third-party programs like [[GCFScape]].}}
{{note|Browse and extract [[VPK]] files with third-party programs like [[GCFScape]].}}
*'''left 4 dead 2\left4dead2\pak01_dir.vpk'''
*'''left 4 dead 2\left4dead2\pak01_dir.vpk'''
Line 51: Line 57:
:March 22, 2011 Cold Stream Beta / L4D1 Transition Project update
:March 22, 2011 Cold Stream Beta / L4D1 Transition Project update
;*'''left 4 dead 2\update\pak01_dir.vpk'''
;*'''left 4 dead 2\update\pak01_dir.vpk'''
:This is where mutations were updated/replaced bi-weekly.
:This is where mutations were updated/replaced bi-weekly. Also contain files introduced with September 24, 2020 The Last Stand Community Update.
;*'''left 4 dead 2\sdk_content\scripting\scripts\vscripts\'''
;*'''left 4 dead 2\sdk_content\scripting\scripts\vscripts\'''
:Plaintext versions of many of the scripts introduced in the EMS update.
:Plaintext versions of many of the scripts introduced in the EMS update.


=== Decrypting NUC Files ===
.nuc files are ICE encrypted .nut files. The encryption key is '''SDhfi878'''. You can use [[VICE]] to decode them.<br>
You may find decrypted mutation vscripts [[L4D2_Decrypted_mutations|here]].


=== Decrypting NUC files ===
== Loading VScripts ==
.nuc files are ICE encrypted .nut files. The encryption key is '''SDhfi878'''. You can use [[VICE]] to decode them.
VScripts are loaded in a variety of ways, depending on their context. They can also be manually loaded with the console command <code>script_execute ''filename''</code>.
 
[[#External_links|Packages with deciphered official scripts are also available.]]
 
 
== Loading vscripts ==
VScripts are loaded in different ways depending on what they are used for. They can alos be manually loaded with the console command <code>script ''filename''</code>


=== Director Scripts ===
=== Director Scripts ===
;*{{ent|info_director}} inputs
{{I|BeginScript|param=scriptlist|Executes generic Director scripts, whether for onslaught events or changing spawning behavior.}}
:They are placed in the <code>LocalScript</code> script scope.
{{I|EndScript|Ends the currently running local script, then resets the Director options to either map-specific values, or default values.}}
{{I|ScriptedPanicEvent|param=scriptlist|With the given scripts, set up the structure of a [[L4D2 Director Scripts#Finales and Scripted Panic Events|scripted panic event]].}}
:They are placed in the <code>LocalScript</code> script scope.


;Using the [[info_director]] entity using the following inputs:
{{note|The scripts of these inputs ''must'' reside under the "vscripts" subfolder. Events will play out only the 1 second DELAY "stage 0" otherwise.}}
:<code>BeginScript <''script name''></code>
::Executes a generic Director script, for example for onslaught events or changing spawning behavior.
:<code>EndScript</code>
::Ends the running script and resets the Director options to the map specific values.
:<code>BeginScriptedPanicEvent <''script name''></code>
::Begins a Scripted Panic event.
 
{{note|Scripts used with <code>BeginScriptedPanicEvent</code> will not work if they are in a subdirectory, even though you can use subdirectories in other script contexts. They must reside under the vscripts folder, or they will simply act as a 1 stage 1 second delay.}}
 
;Finale scripts
:The <code><map name>_finale.nut</code> script is atumatically loaded when a finale map starts. The script is triggered when the [[trigger_finale]] is used, either manually by the player, or with the <code>ForceFinaleStart</code> input.
:{{todo|[[trigger_finale]] also has an option to specify a finale script, but it doesn't seem to work}}
 


All Director Scripts are placed in the script scope <code>DirectorScript</code>
;*[[L4D2 Director Scripts#Finales and Scripted Panic Events|Finale scripts]]
:As a {{ent|trigger_finale}} finale starts, it loads a script of this format: <code>[mapname]_finale.nut</code>.
:They are placed in the <code>g_MapScript</code> script scope.


=== Entity Scripts ===
=== Entity Scripts ===
;Automatic loading at map start
;*Keyvalue
:Uses the script set in the '''Entity Scripts''' KeyValue of the entity.
{{KV|Entity Scripts|intn=vscripts|scriptlist|As an entity is preparing itself before it spawns, the VScript path names in that keyvalue will be ran. (See [[L4D2_Vscripts#Entity_Scripts_3|Entity Scripts]] for more info.)}}
;Manual loading
;*Input
:Using the <code>RunScriptFile</code> input.
{{I|RunScriptFile|param=script|Inserts the given script into the entity's scope, then runs it.}}


Entity Scripts are placed in the script scope <code>_<unique ID>_<entity name></code>
Entity Scripts are placed in the <code>_<unique ID>_<entity name></code> script scope.


=== Global Scripts ===
=== Global Scripts ===
;Mode Specific Scripts
;*Mode scripts
:Will automatically run the script with the same name as the [[Mutation_Gametype_(L4D2)|game mode]]. For example, running a map <code>map <map name> mutation12</code> will automatically load the Realism Versus script, <code>mutation12.nuc</code>.
:A script with the same name as the current [[Mutation_Gametype_(L4D2)|game mode]]. Loaded when a new mode is set.
:They are placed in the script scope <code>g_ModeScript</code>
:They are placed in the <code>g_ModeScript</code> script scope.
 
:{{tip|The <code>map</code> command can also set gamemodes. For example, <code>map <map name> mutation12</code> loads the Realism Versus mode script, <code>mutation12.nuc</code>.}}
{{note|Adding a script for a mode will enable Scripted Mode on it.}}
:{{note|Adding a script for a mode will enable Scripted Mode.}}


;Map Specific Scripts (only available in Scripted Mode)
;*Map-specific mode scripts
:Per-map scripts can be created that run when the map is loaded in the specified game mode, using the syntax <code><map name>_<mode name>.nut</code>, for example, <code>c1m4_atrium_mutation12.nut</code>.
:Per-map scripts when the map is loaded in the specified game mode. They are in the name format: ''<nowiki>[mapname]_[modename].nut</nowiki>''.
:They are placed in the script scope <code>g_MapScript</code>
:They are placed in the <code>g_MapScript</code> script scope.


;*Addon scripts
:These scripts vary in context, but they all share one big attribute: they don't override files with the same name, but instead load alongside them. They are executed in the order below, each after its respective base script (without <code>_addon</code> suffix). A script is considered an "addon script" if it's named as:
:# <code>mapspawn_addon.nut</code> (runs once every chapter) - <code>getroottable()</code> scope
:# <code>response_testbed_addon.nut</code> (runs once every chapter) - <code>g_rr</code> scope
:# <code>scriptedmode_addon.nut</code> (runs twice every round) - <code>g_MapScript</code> scope
:# <code>director_base_addon.nut</code> (runs twice every round) - <code>DirectorScript</code> scope


== Scripting Environment ==
'''Please see [[Left 4 Dead 2/Script Functions]] for built in classes and functions.'''


== Scripting environment ==
When a script is loaded, it is placed into a table, or Script Scope. Global and Director Scripts are put into set scopes, while a unique scope is generated for each Entity Script. Please see [[Vscript Fundamentals]] for more information.
'''Please see [[List of L4D2 Script Functions]] for built in classes and functions.'''


When a script is loaded, it is placed into a table, or Script Scope. Mode, map and Director Scripts are put into set scopes, while a unique scope is generated for each Entity Script. Please see [[Vscript Fundamentals]] for more information.
=== Table Structure ===
 
=== Table structure ===
<source lang=cpp>
<source lang=cpp>
DirectorScript = // Base Director Scope.
DirectorScript = // Base Director Scope.
{
{
DirectorOptions // Base DirectorOptions table.
DirectorOptions // Base DirectorOptions table.
MapScript =  // Map Script scope.
MapScript =  // Script scope for either map scripts or trigger_finale scripts
{
{
BaseScriptedDOTable // Hardcoded DirectorOptions.
DirectorOptions       
ChallengeScript = // Mode Script scope.
BaseScriptedDOTable // Default DirectorOptions for Scripted mode
ChallengeScript = // Script scope for mode scripts
{
{
MutationState // Initial values for SessionState.
DirectorOptions // Filled with BaseScriptedDOTable, MutationOptions and MapOptions; if identical keys are present then the most-right table gets precedence.
MutationOptions // Initial values for SessionOptions.
MutationState // Filled with MapState overwriting previous values
MutationOptions // Initial values used if defined in mode script
}
}
LocalScript = // Script Scope Director Scripts are placed in.
LocalScript = // Script scope for scripts executed through info_director 'BeginScript' or 'ScriptedPanicEvent' inputs
{
{
DirectorOptions // DirectorOptions for current Director Script (like onslaughts). Only availabe when a script is active.
DirectorOptions // DirectorOptions for current Director Script (like onslaughts). Only available when a script is active
}
}
MapOptions // Initial values for SessionOptions.
MapOptions // Initial values used if defined in map script
MapState // Initial values for SessionState.
MapState // Initial values used if defined in map script
}
}
}
}
g_MapScript // Global reference to the Map Script scope (DirectorScript.MapScript).
g_MapScript // Global reference to the Map Script scope (DirectorScript.MapScript).
g_ModeScript // Global reference to the Mode Script scope (DirectorScript.MapScript.ChallengeScript).
g_ModeScript // Global reference to the Mode Script scope (DirectorScript.MapScript.ChallengeScript).
SessionOptions // Global reference to g_ModeScript.DirectorOptions (Scripted mode only).
SessionState  // Global reference to g_ModeScript.MutationState (Scripted mode only).
g_rr // Scope holding the Response Rule system.
g_rr // Scope holding the Response Rule system.
g_RoundState // TODO
g_RoundState // TODO
SessionOptions //Global Director options (Scripted mode only).
SessionState  //State variables for game modes (Scripted mode only).
</source>
</source>


=== Delegation ===
=== Delegation ===
Some of the tables have [http://squirrel-lang.org/doc/squirrel3.html#d0e2038 delegation] set up, so that if a key isn't present in it, it is read from its parent table instead.
Some of the tables have [http://squirrel-lang.org/doc/squirrel3.html#d0e2038 delegation] set up, so that if a key isn't present in it, it is read from its delegate (usually parent) table instead.


The tables are delegated like this (parent tables on the right):
The tables are delegated like this (delegates on the right):
; The Director Scope
; The Director Scope
: <code>(DirectorScript.MapScript.ChallengeScript; DirectorScript.MapScript.LocalScript) < DirectorScript.MapScript < DirectorScript < ::</code>
: <code>(DirectorScript.MapScript.ChallengeScript or DirectorScript.MapScript.LocalScript) < DirectorScript.MapScript < DirectorScript < ::</code>
;DirectorOptions
; DirectorOptions
:<code>DirectorScript.MapScript.LocalScript.DirectorOptions (When Director Script active) < DirectorScript.MapScript.ChallengeScript.DirectorOptions (Scripted mode only) < DirectorScript.DirectorOptions</code>
: <code>DirectorScript.MapScript.ChallengeScript.DirectorOptions (Scripted mode only) < DirectorScript.MapScript.LocalScript.DirectorOptions (when Director Script active) < DirectorScript.MapScript.DirectorOptions < DirectorScript.DirectorOptions</code>
: See GetDirectorOptions in {{ent|director_base.nut}}.


== Entity Scripts ==
== Entity Scripts ==
Line 154: Line 160:
Adding a script to the '''Entity Scripts''' KeyValue of a server-side entity loads the script as an Entity Script. The script is executed when the entity spawns, and loads into a unique script scope made up of an unique identifier followed by the entity name or class name.  
Adding a script to the '''Entity Scripts''' KeyValue of a server-side entity loads the script as an Entity Script. The script is executed when the entity spawns, and loads into a unique script scope made up of an unique identifier followed by the entity name or class name.  


A think function can be set with the <code>thinkfunction</code> [[Keyvalue|KeyValue]], the specified script function every 0.1 seconds. While it has the potential to become expensive, a programmer is able to limit the amount of code executed. Functions can also be manually called through the I/O system with the input <code>RunScriptCode ''function_name(argument, ...)</code>.
A think function can be set with the <code>thinkfunction</code> [[Keyvalue|KeyValue]], the specified script function every 0.1 seconds. While it has the potential to become expensive, a programmer is able to limit the amount of code executed. Functions can also be manually called through the I/O system with the input <code>RunScriptCode ''function_name(argument, )</code>.


Entity Scripts have a <code>self</code> reference to their owning entity handle, allowing the script easy access to control the entity through its class methods. There are also hook functions available depending on the entity class. Both methods and hooks are documented [[List_of_L4D2_Script_Functions#Classes|here]].
Entity Scripts have a <code>self</code> reference to their owning entity handle, allowing the script easy access to control the entity through its class methods. There are also hook functions available depending on the entity class. Both methods and hooks are documented [[Left 4 Dead 2/Script Functions#Classes|here]].


Some entities have additional script functionality:
Some entities have additional script functionality:
*[[point_script_use_target]] - Has both methods and hooks for controlling the button.
*{{ent|point_script_use_target}} - Has both methods and hooks for controlling the button.
*[[logic_script]] - Can pass multiple entity names to the script as an array called <code>EntityGroup</code>.
*{{ent|logic_script}} - Can pass multiple entity names to the script as an array called <code>EntityGroup</code>.
*[[point_template]]
*{{ent|point_template}}
*[[env_entity_maker]]
*{{ent|env_entity_maker}}
*[[info_item_position]]
*{{ent|info_item_position}}
 


The script can be reloaded with console command <code>ent_fire <name of entity> runscriptfile ''<relative vscript path>''</code>. This is useful for quick script reloading.
The script can be reloaded with console command <code>ent_fire <name of entity> runscriptfile ''<relative vscript path>''</code>. This is useful for quick script reloading.


 
=== [[Inputs_and_Outputs|I/O system]] Interaction ===
=== [[Inputs_and_Outputs|I/O system]] interaction ===
Any script can use the <code>EntFire()</code> and <code>DoEntFire()</code> functions to fire outputs to map entities. Since the ''<code>activator</code>'' and ''<code>caller</code>'' arguments in <code>DoEntFire()</code> take a script handle, it can be used to fire an output to an entity using the {{ent|!self}} or {{ent|!activator}} keyword, even without having to know its name, as long as the entity handle is available.
Any script can use the <code>EntFire()</code> and <code>DoEntFire()</code> functions to fire outputs to map entities. Since the ''<code>activator</code>'' and ''<code>caller</code>'' arguments in <code>DoEntFire()</code> take a script handle, it can be used to fire an output to an entity using the "!self" or "!activator" keyword, even without having to know its name, as long as the entity handle is available.


<source lang=cpp>
<source lang=cpp>
Line 182: Line 186:
</source>
</source>


 
Conversely, the <code>[[Left 4 Dead 2/Script Functions#CBaseEntity|CBaseEntity]]::ConnectOutput()</code> and <code>DisconnectOutput()</code> functions can be used to call a script function when the specified entity output fires.
Conversely, the <code>[[List_of_L4D2_Script_Functions#CBaseEntity|CBaseEntity]]::ConnectOutput()</code> and <code>DisconnectOutput()</code> functions can be used to call a script function when the specified entity output fires.
In addition, arbitrary VScript code can be run from the I/O system, using the <code>RunScriptCode</code> input available in all entities. The code will run in the current entities script scope.
In addition, arbitrary VScript code can be run from the I/O system, using the <code>RunScriptCode</code> input available in all entities. The code will run in the current entities script scope.
{{warning|Never use double-quotation marks in any Hammer Output, since it will corrupt the map file. This means that strings cannot be passed with <code>RunScriptCode</code>.}}
{{warning|Never use double-quotation marks in any Hammer Output, since it will corrupt the map file. This means that strings cannot be passed with <code>RunScriptCode</code>.}}


== Global Scripts ==
== Global Scripts ==
Naming a script file with a game mode name a mode specific script, and makes it execute every time a map is loaded in the specified mode. If a Mode Script exists, a map specific script with the map name followed by an underscore and the mode name can also be loaded.
Naming a script file with a game mode name makes it a mode specific script which executes every time a map is loaded in the specified mode. If a Mode Script exists, a map specific script with the map name followed by an underscore and the mode name can also be loaded.
 
{{todo|Add information about the features and utility functions that get loaded into these.}}
 
=== Scripted Mode ===
Adding a Mode Script will enable Scripted Mode for the game mode. This works on the base game modes included in the game as well.
 
Scripted Mode loads utility functions into the <code>g_ModeScript</code> scope, disables the hardcoded setting of 2 on the <code>MaxSpecials</code> Director Option, and enables [[L4D2_EMS/Appendix:_Game_Events|game event callbacks]] and [[List_of_L4D2_Script_Functions#Scripted_Mode_hooks|script hook functions]]. It also seems to break the finale tank music in Dark Carnival.
 
{{todo|Does enabling Scripted Mode have any other consequences?}}
 
=== Shared Tables ===
;<code>SessionState</code>
:A table for storing session specific variables. Not preserved across level transitions.
;<code>SessionOptions</code>
:Base [[L4D2_Director_Scripts#DirectorOptions|Director Options]] for the game mode.
 
=== Available Functions ===
{{todo|Document the available utility features.}}
 


=== Mode Scripts ===
=== Mode Scripts ===
Line 218: Line 201:
;<code>MutationOptions</code>
;<code>MutationOptions</code>
:Initial values for the <code>SessionOptions</code> table.
:Initial values for the <code>SessionOptions</code> table.


=== Map Scripts ===
=== Map Scripts ===
Line 229: Line 211:
:Map specific values for the <code>SessionOptions</code> table.
:Map specific values for the <code>SessionOptions</code> table.


=== Scripted Mode ===
Adding a Mode Script will enable Scripted Mode for the game mode. This works on the base game modes included in the game as well.
Scripted Mode loads utility functions into the <code>g_MapScript</code> scope, disables the hardcoded setting of 2 on the <code>MaxSpecials</code> Director option, and enables [[L4D2_EMS/Appendix:_Game_Events|game event callbacks]] and [[Left 4 Dead 2/Script Functions#Scripted_Mode_hooks|script hook functions]]. It also seems to break the finale tank music in Dark Carnival.
{{todo|Does enabling Scripted Mode have any other consequences?}}
==== Available Functions ====
{{todo|Document the available utility features.}}
=== Shared Tables ===
;<code>SessionState</code>
:A table for storing session specific variables. Not preserved across level transitions.
;<code>SessionOptions</code>
:Active [[L4D2_Director_Scripts#DirectorOptions|Director Options]] for the game mode.


== Glossary ==
== Glossary ==
Line 240: Line 237:
:The table where the variables, functions and classes of a VScript are placed.
:The table where the variables, functions and classes of a VScript are placed.


 
== Director Options ==
== Director options ==
'''Please see [[L4D2 Director Scripts#DirectorOptions|L4D2 Director Scripts]] for a table of available options.'''
'''Please see [[L4D2 Director Scripts#DirectorOptions|L4D2 Director Scripts]] for a table of available options.'''


 
== Third-Party Tools ==
== Third party tools ==


===VSLib===
===VSLib===
Line 251: Line 246:


== See also ==
== See also ==
=== Intros ===
*[[VScript]]
*[[Mutation Gametype (L4D2)]]
=== Documentations ===
*[[VSLib]]
*[[L4D2 Vscript Examples]]
*[[L4D2 Vscript Examples]]
*[[List of L4D2 Script Functions]]
*[[L4D2_Director_Scripts|L4D2 Director Scripts]]
*[[Left 4 Dead 2/Script Functions|L4D2 Script Functions]]
*[[L4D2_Decrypted_mutations|Decrypted Mutation Vscripts]]
*[[L4D2_Level_Design/Boss_Prohibition|L4D2 Level Design/Boss Prohibition]]
*[[L4D2_Level_Design/Custom_Finale|Custom Finales]] ''Contains all original finale scripts as reference.''
*[[L4D2 EMS|Extended Mutation System]]
*[[L4D2 EMS|Extended Mutation System]]
*[[L4D2_Level_Design/Boss_Prohibition|L4D2 Level Design/Boss Prohibition]]
*[[Left_4_Dead_2_Tool_Updates|Left 4 Dead 2 Tool Updates]]
*[[Left_4_Dead_2_Tool_Updates|Left 4 Dead 2 Tool Updates]]
*[[Mutation Gametype (L4D2)]]
 
*[[Trigger_finale|trigger_finale]]
=== Miscelleanous ===
*[[Info_director|info_director]]
*{{ent|logic_script}}
*[[Logic_script|logic_script]]
*{{ent|trigger_finale}}
*[[VScript|vscripts]]
*{{ent|info_director}}
*[[VSLib]]


== External links ==
== External links ==
;Alternative Tool
;Alternative Tool
* [http://www.mediafire.com/?q4dqbs554p494vk (mediafire)L4D2 VScript Editor Beta 0.5 by Cynick:support nut (de)compile for l4d2]
* [http://www.mediafire.com/?q4dqbs554p494vk (mediafire)L4D2 VScript Editor Beta 0.5 by Cynick:support nut (de)compile for l4d2]  
;Alternative Documentation
;Alternative Documentation
* [http://forums.steampowered.com/forums/showthread.php?t=1128303 Director Scripts - .nuc files (Steam forums)]
* [http://forums.steampowered.com/forums/showthread.php?t=1128303 Director Scripts - .nuc files (Steam forums)] {{deadlink}}
* [http://forums.steampowered.com/forums/showthread.php?t=1238461 It's the vscript'ing documentation FAQ! (Steam forums)]
* [http://forums.steampowered.com/forums/showthread.php?t=1238461 It's the vscript'ing documentation FAQ! (Steam forums)] {{deadlink}}
* [http://forums.steampowered.com/forums/showthread.php?t=1242468 Tutorial - Writing a Mini Game - Tic Tac Toe - Part One (Steam Forums)]
* [http://forums.steampowered.com/forums/showthread.php?t=1242468 Tutorial - Writing a Mini Game - Tic Tac Toe - Part One (Steam Forums)] {{deadlink}}
**[http://leeland.stores.yahoo.net/l4d2-scripts-play-tic-tac-toe.html Writing a Mini Game - Tic Tac Toe - Part One] - Author's Website
**[http://leeland.stores.yahoo.net/l4d2-scripts-play-tic-tac-toe.html Writing a Mini Game - Tic Tac Toe - Part One] - Author's Website {{deadlink}}
**[http://www.youtube.com/watch?v=B9hASsoHK54 l4d2 - Vscript example - Tic-Tac-Toe] - Video of early Prototype
**[http://www.youtube.com/watch?v=B9hASsoHK54 l4d2 - Vscript example - Tic-Tac-Toe] - Video of early Prototype
**[http://www.youtube.com/watch?v=mvDFEoA0ib0 l4d2 - Vscript example - Tic-Tac-Toe - updated] - Video of current version with "brutally misanthropic AI"
**[http://www.youtube.com/watch?v=mvDFEoA0ib0 l4d2 - Vscript example - Tic-Tac-Toe - updated] - Video of current version with "brutally misanthropic AI"
* [http://forums.steampowered.com/forums/showthread.php?t=1238004 Mutation scripts (Steam forums)]
* [http://forums.steampowered.com/forums/showthread.php?t=1238004 Mutation scripts (Steam forums)] {{deadlink}}
* [http://modulatum.wordpress.com/2008/03/20/squirrel-binary-for-windows/ Squirrel Binary for Windows]
* [http://modulatum.wordpress.com/2008/03/20/squirrel-binary-for-windows/ Squirrel Binary for Windows]
* [http://en.wikipedia.org/wiki/Squirrel_(programming_language) Squirrel (programming language)] - Wikipedia Article on Squirrel
* [http://en.wikipedia.org/wiki/Squirrel_(programming_language) Squirrel (programming language)] - Wikipedia Article on Squirrel
* {{sq}}[http://squirrel-lang.org/ Squirrel: The Programming Language - Documentation and Sample Code]
* {{sq}}[http://squirrel-lang.org/ Squirrel: The Programming Language - Documentation and Sample Code]
* [http://www.valvesoftware.com/publications/2009/ai_systems_of_l4d_mike_booth.pdf The AI Systems of Left 4 Dead by Michael Booth (PDF)]
* [https://steamcdn-a.akamaihd.net/apps/valve/2009/ai_systems_of_l4d_mike_booth.pdf The AI Systems of Left 4 Dead by Michael Booth (PDF)]
* {{as}}[http://swarmarmory.com/forums/viewtopic.php?f=19&t=541 "Creating a "Money"/Point System"] - Swarm Armory
* {{as}}[http://swarmarmory.com/forums/viewtopic.php?f=19&t=541 "Creating a "Money"/Point System"] - Swarm Armory
;Deciphered Official Scripts:
;Deciphered Official Scripts:
*[http://www.mediafire.com/?k280fhwjsp21sn8 Version 2.1.3.6 and all mutations]
*[http://www.mediafire.com/?k280fhwjsp21sn8 Version 2.1.3.6 and all mutations]
*[http://ata4.info/downloads/left4dead2/scriptsrc.zip Version 2.0.8.4 (August 16, 2011)]
*[http://ata4.info/downloads/left4dead2/scriptsrc.zip Version 2.0.8.4 (August 16, 2011)]
<div style="text-align: right; direction: ltr; margin-left: 1em;">{{sq}}+{{l4d2}} = [[image:pnkhrt-16px.png]]</div>
<div style="text-align: right; direction: ltr; margin-left: 1em;">{{sq}}+ {{l4d2}} = [[File:PinkHeartCensor.png|16px]]</div>


[[Category:Left_4_Dead_2]]
[[Category:Left_4_Dead_2]]
[[Category:VScript]]
[[Category:Scripting]]
[[Category:Scripting]]

Latest revision as of 11:06, 21 April 2025

English (en)Translate (Translate)
edit
Left 4 Dead 2/Docs

Useful links

Overview

SquirrelLeft 4 Dead 2 Left 4 Dead 2 VScripts are server-side scripts that are run in an in-game virtual machine. They are written in Squirrel, a compiled scripting language similar to Lua. It currently runs Squirrel version 3.0.4.

Uses

Director Scripts

The most common use of VScripts in Left 4 Dead 2 is to temporarily influence the behavior of the AI Director. These scripts can range from simple adjustments of infected spawning and prohibiting boss infected, to custom events like onslaughts and gauntlets, and even complex staged panic events and fully custom finales. Most of the events in the official campaigns are mainly implemented this way.

Director Scripts work mainly by writing overriding values of the various variables used by the Director into a DirectorOptions table.

Only one Director Script can be running at a time. Executing a new one will terminate any previous running one and remove any values it set in DirectorOptions.

Entity Scripts ↓

Another common use is to attach a script to an entity. The script provides easy access to read and modify many of the entity's properties, and even to write new KeyValues. This allows for controlling entities in ways that would be very complicated or impossible to with the entity I/O system in Hammer.

Any entity is capable of running a script, and has the ability to set a specified think function to run every 0.1 seconds, as well as executing script code as an entity output.

Some entities also have specialized functions for VScripts, with the most prominent being point_script_use_target, which allows for turning other entities into fully programmable timed buttons.

Global Scripts ↓

Scripts can also be made to run on map load, based on game mode and optionally map name. These scripts are commonly used to create pure script addons and modify global Director options for mutations.

Global scripts can have script hook functions added that get called from the game at certain events, like when players/objects take damage.

There are many utility functions and features readily available for these scripts, including a resource and building system, and custom panic wave spawning. Please see Valve's Expanded Mutation System tutorial for more information.

Other Uses

All scripts can access functions for many features, including spawning entities either from precompiled lists or programmatically, spawning infected, a HUD system, storing data across levels and to disk, and much more.

Please see L4D2 Vscript Examples for more examples and ideas.

Script Files

The scripts are loaded from text files with the file extensions .nut and .nuc, where .nuc denotes encryption of plaintext .nut. Custom scripts are read from \left 4 dead 2\left4dead2\scripts\vscripts\, as well as \scripts\vscripts\ when packed into a .vpk file.

Location

Official .nuc script files are located in scripts/vscripts in multiple locations
Note.pngNote:Browse and extract VPK files with third-party programs like GCFScape.
  • left 4 dead 2\left4dead2\pak01_dir.vpk
  • left 4 dead 2\left4dead2_dlc1\pak01_dir.vpk
April 22, 2010 The Passing update
  • left 4 dead 2\left4dead2_dlc2\pak01_dir.vpk
October 5, 2010 The Sacrifice update
  • left 4 dead 2\left4dead2_dlc3\pak01_dir.vpk
March 22, 2011 Cold Stream Beta / L4D1 Transition Project update
  • left 4 dead 2\update\pak01_dir.vpk
This is where mutations were updated/replaced bi-weekly. Also contain files introduced with September 24, 2020 The Last Stand Community Update.
  • left 4 dead 2\sdk_content\scripting\scripts\vscripts\
Plaintext versions of many of the scripts introduced in the EMS update.

Decrypting NUC Files

.nuc files are ICE encrypted .nut files. The encryption key is SDhfi878. You can use VICE to decode them.
You may find decrypted mutation vscripts here.

Loading VScripts

VScripts are loaded in a variety of ways, depending on their context. They can also be manually loaded with the console command script_execute filename.

Director Scripts

BeginScript <scriptlistRedirectInput/string>
Executes generic Director scripts, whether for onslaught events or changing spawning behavior.
They are placed in the LocalScript script scope.
EndScript
Ends the currently running local script, then resets the Director options to either map-specific values, or default values.
ScriptedPanicEvent <scriptlistRedirectInput/string>
With the given scripts, set up the structure of a scripted panic event.
They are placed in the LocalScript script scope.
Note.pngNote:The scripts of these inputs must reside under the "vscripts" subfolder. Events will play out only the 1 second DELAY "stage 0" otherwise.
As a trigger_finale finale starts, it loads a script of this format: [mapname]_finale.nut.
They are placed in the g_MapScript script scope.

Entity Scripts

  • Keyvalue
Entity Scripts (vscripts) <scriptlist>
As an entity is preparing itself before it spawns, the VScript path names in that keyvalue will be ran. (See Entity Scripts for more info.)
  • Input
RunScriptFile <scriptRedirectInput/string>
Inserts the given script into the entity's scope, then runs it.

Entity Scripts are placed in the _<unique ID>_<entity name> script scope.

Global Scripts

  • Mode scripts
A script with the same name as the current game mode. Loaded when a new mode is set.
They are placed in the g_ModeScript script scope.
Tip.pngTip:The map command can also set gamemodes. For example, map <map name> mutation12 loads the Realism Versus mode script, mutation12.nuc.
Note.pngNote:Adding a script for a mode will enable Scripted Mode.
  • Map-specific mode scripts
Per-map scripts when the map is loaded in the specified game mode. They are in the name format: [mapname]_[modename].nut.
They are placed in the g_MapScript script scope.
  • Addon scripts
These scripts vary in context, but they all share one big attribute: they don't override files with the same name, but instead load alongside them. They are executed in the order below, each after its respective base script (without _addon suffix). A script is considered an "addon script" if it's named as:
  1. mapspawn_addon.nut (runs once every chapter) - getroottable() scope
  2. response_testbed_addon.nut (runs once every chapter) - g_rr scope
  3. scriptedmode_addon.nut (runs twice every round) - g_MapScript scope
  4. director_base_addon.nut (runs twice every round) - DirectorScript scope

Scripting Environment

Please see Left 4 Dead 2/Script Functions for built in classes and functions.

When a script is loaded, it is placed into a table, or Script Scope. Global and Director Scripts are put into set scopes, while a unique scope is generated for each Entity Script. Please see Vscript Fundamentals for more information.

Table Structure

DirectorScript = 			// Base Director Scope.
{
	DirectorOptions 		// Base DirectorOptions table.
	MapScript =  			// Script scope for either map scripts or trigger_finale scripts
	{
		DirectorOptions         
		BaseScriptedDOTable 	// Default DirectorOptions for Scripted mode
		ChallengeScript = 	// Script scope for mode scripts
		{
			DirectorOptions // Filled with BaseScriptedDOTable, MutationOptions and MapOptions; if identical keys are present then the most-right table gets precedence.
			MutationState 	// Filled with MapState overwriting previous values
			MutationOptions // Initial values used if defined in mode script 
		}
		LocalScript =		// Script scope for scripts executed through info_director 'BeginScript' or 'ScriptedPanicEvent' inputs
		{
			DirectorOptions // DirectorOptions for current Director Script (like onslaughts). Only available when a script is active
		}
		MapOptions 		// Initial values used if defined in map script 
		MapState 		// Initial values used if defined in map script 
	}
}
g_MapScript 	// Global reference to the Map Script scope (DirectorScript.MapScript).
g_ModeScript 	// Global reference to the Mode Script scope (DirectorScript.MapScript.ChallengeScript).
SessionOptions 	// Global reference to g_ModeScript.DirectorOptions (Scripted mode only).
SessionState  	// Global reference to g_ModeScript.MutationState (Scripted mode only).

g_rr		// Scope holding the Response Rule system.
g_RoundState	// TODO

Delegation

Some of the tables have delegation set up, so that if a key isn't present in it, it is read from its delegate (usually parent) table instead.

The tables are delegated like this (delegates on the right):

The Director Scope
(DirectorScript.MapScript.ChallengeScript or DirectorScript.MapScript.LocalScript) < DirectorScript.MapScript < DirectorScript < ::
DirectorOptions
DirectorScript.MapScript.ChallengeScript.DirectorOptions (Scripted mode only) < DirectorScript.MapScript.LocalScript.DirectorOptions (when Director Script active) < DirectorScript.MapScript.DirectorOptions < DirectorScript.DirectorOptions
See GetDirectorOptions in director_base.nut.

Entity Scripts

Use script scope _<unique ID>_<entity name>

Adding a script to the Entity Scripts KeyValue of a server-side entity loads the script as an Entity Script. The script is executed when the entity spawns, and loads into a unique script scope made up of an unique identifier followed by the entity name or class name.

A think function can be set with the thinkfunction KeyValue, the specified script function every 0.1 seconds. While it has the potential to become expensive, a programmer is able to limit the amount of code executed. Functions can also be manually called through the I/O system with the input RunScriptCode function_name(argument, …).

Entity Scripts have a self reference to their owning entity handle, allowing the script easy access to control the entity through its class methods. There are also hook functions available depending on the entity class. Both methods and hooks are documented here.

Some entities have additional script functionality:

The script can be reloaded with console command ent_fire <name of entity> runscriptfile <relative vscript path>. This is useful for quick script reloading.

I/O system Interaction

Any script can use the EntFire() and DoEntFire() functions to fire outputs to map entities. Since the activator and caller arguments in DoEntFire() take a script handle, it can be used to fire an output to an entity using the !self or !activator keyword, even without having to know its name, as long as the entity handle is available.

EntFire( "church_bell_relay", "Trigger", 0 ); // Fires an output to the Trigger input of the named entity.

player <- null;
while(player = Entities.FindByClassname(player, "player"))   // Iterate through the script handles of the players.
{
    DoEntFire("!self", "speakresponseconcept", "PlayerLaugh", 0, null, player); // Make each player laugh.
}

Conversely, the CBaseEntity::ConnectOutput() and DisconnectOutput() functions can be used to call a script function when the specified entity output fires. In addition, arbitrary VScript code can be run from the I/O system, using the RunScriptCode input available in all entities. The code will run in the current entities script scope.

Warning.pngWarning:Never use double-quotation marks in any Hammer Output, since it will corrupt the map file. This means that strings cannot be passed with RunScriptCode.

Global Scripts

Naming a script file with a game mode name makes it a mode specific script which executes every time a map is loaded in the specified mode. If a Mode Script exists, a map specific script with the map name followed by an underscore and the mode name can also be loaded.

Mode Scripts

Use script scope g_ModeScript

Tables

MutationState
Initial values for the SessionState table.
MutationOptions
Initial values for the SessionOptions table.

Map Scripts

Use script scope g_MapScript

Tables

MapState
Map specific values for the SessionState table.
MapOptions
Map specific values for the SessionOptions table.

Scripted Mode

Adding a Mode Script will enable Scripted Mode for the game mode. This works on the base game modes included in the game as well.

Scripted Mode loads utility functions into the g_MapScript scope, disables the hardcoded setting of 2 on the MaxSpecials Director option, and enables game event callbacks and script hook functions. It also seems to break the finale tank music in Dark Carnival.

Todo: Does enabling Scripted Mode have any other consequences?

Available Functions

Todo: Document the available utility features.

Shared Tables

SessionState
A table for storing session specific variables. Not preserved across level transitions.
SessionOptions
Active Director Options for the game mode.

Glossary

DirectorOptions
A table of named variables that override the AI Director behavior.
Entity handle
Also known as EHANDLE.
Todo: Looks like some sort of pointer reference to an entity.
Script handle
An entity instance with accessors and mutators to the C++ entity object. Also known as HScript.
Script scope
The table where the variables, functions and classes of a VScript are placed.

Director Options

Please see L4D2 Director Scripts for a table of available options.

Third-Party Tools

VSLib

VSLib (VScript Library) is a simple, lightweight library for L4D2's VScript mutation system. It greatly simplifies coding VScripts by taking care of a lot of tedious work for you. It is used in several popular mods like Rayman1103's Admin System and Stranded. Read more about VSLib.

See also

Intros

Documentations

Miscelleanous

External links

Alternative Tool
Alternative Documentation
Deciphered Official Scripts
Squirrel+ Left 4 Dead 2 = PinkHeartCensor.png