Difference between revisions of "L4D2 Vscripts"

From Valve Developer Community
Jump to: navigation, search
m (CPointTemplate)
m
 
(50 intermediate revisions by 9 users not shown)
Line 1: Line 1:
 +
{{otherlang2
 +
|noborder=true
 +
|zh-cn=L4D2_Vscripts:zh-cn
 +
|zh-tw=L4D2_Vscripts:zh-cn
 +
}}
 +
 
{{toc-right}}
 
{{toc-right}}
{{sq}}{{l4d2}} '''Left 4 Dead 2 [[VScript|vscripts]]''' are Squirrel language-based scripts that can be run in-game. For examples, please see '''[[L4D2 Vscript Examples]]'''.
+
{{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].
 +
 
 +
 
 +
== Uses ==
 +
 
 +
=== [[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.
 +
 
 +
Director Scripts work mainly by writing overriding values of the various variables used by the Director into a <code>DirectorOptions</code> 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 <code>DirectorOptions</code>.
 +
 
 +
=== [[#Entity Scripts 3|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 3|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.
  
== Description ==
+
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.  
Left 4 Dead 2 vscripts are written in [http://squirrel-lang.org/ Squirrel], a compilable scripting language similar to [http://www.lua.org/ Lua]. The file extensions are .nut and .nuc, where .nuc denotes encryption of plain text .nut.
 
  
=== Usage ===
+
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.
*Director manipulation - onslaughts, CI wanderer options, complete emptiness/silence, [[L4D2_Level_Design/Boss_Prohibition|prohibition of boss infected]] (tanks and witches), direction of mobs, specific spawning behavior, etc.
+
 
*Finale - Custom sequences of events, Gauntlet and Scavenge Logic
+
=== Other uses ===
*Complex entity scripting - entity I/O, logic, arithmetic, loops, counters, timers, prop spawning, etc. (Example: Dark Carnival mini-games)
+
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.
*Game modes such as Mutations and Scavenge
+
 
*Miscellaneous!
+
Please see [[L4D2 Vscript Examples]] for more examples and ideas.
 +
 
 +
 
 +
== 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 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 ===
Line 23: Line 52:
 
: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 are updated/replaced bi-weekly.
+
:This is where mutations were updated/replaced bi-weekly.
 +
;*'''left 4 dead 2\sdk_content\scripting\scripts\vscripts\'''
 +
:Plaintext versions of many of the scripts introduced in the EMS update.
 +
 
  
 
=== Decrypting NUC files ===
 
=== Decrypting NUC files ===
Line 29: Line 61:
  
 
[[#External_links|Packages with deciphered official scripts are also available.]]
 
[[#External_links|Packages with deciphered official scripts are also available.]]
 +
  
 
== Loading vscripts ==
 
== Loading vscripts ==
*Entities
+
VScripts are loaded in different ways depending on what they are used for. They can also be manually loaded with the console command <code>script ''filename''</code>
**Any entity is capable of loading a script on map spawn.
 
**The vscript can be reloaded with console command <code>ent_fire <name of entity> runscriptfile <relative vscript path></code>. This is useful for quick script reloading.
 
**Script functions can be called with entity inputs like <code>RunScriptCode</code>.
 
**Features '''thinkfunction''', a [[Keyvalue|keyvalue]] that calls a user-defined function every 0.1 seconds. While it has the potential to become expensive, a programmer is able to limit the amount of code executed. The shoot gallery in Dark Carnival relies on this.
 
**Some functions are specialized for certain entity classes, such as [[point_template]] and [[env_entity_maker]].
 
**Also available is [[logic_script]], an entity that registers multiple entities as an array EntityGroup.
 
*[[info_director]]
 
**Loads DirectorOptions such as onslaughts, panic events, infected limits, etc.
 
**Custom DirectorOptions are used frequently to tweak director behavior that best suits the environment. c1_mall_ambient.nut is one such example.
 
{{note|Scripts used with <code>ScriptedPanicEvent</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.}}
 
*Game Modes
 
**[[L4D2 Level Design/Scavenge Maps|Scavenge]]
 
***A per-map script is loaded automatically during Scavenge Mode
 
***Name the script <map name>_scavenge.nut.
 
***For example, c1m4_atrium_scavenge.nut.
 
**[[Mutation Gametype (L4D2)|Mutations]]
 
***Will automatically run the script with the same name as the [[L4D2_Gamemodes_File|game mode]].
 
***For example, running a map <code>map <map name> mutation12</code> will automatically load Realism Versus script.
 
*Finale
 
**Loaded via [[trigger_finale]], either automatically or pointing to a specific vscript.
 
**Automatically loads <map name>_finale.nut script on finale start.
 
**[[L4D2 Level Design/Scavenge Finale|Scavenge]], [[L4D2 Level Design/Custom Finale|Custom]], and [[L4D2 Level Design/Gauntlet Finale|Gauntlet]] finales are dependent on vscripts.
 
  
== Example scripts ==
+
=== Director Scripts ===
'''Please see [[L4D2 Vscript Examples]].'''
+
 
 +
;Using the [[info_director]] entity using the following inputs:
 +
:<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}}
  
== Director options ==
 
This is by no means an exhaustive list of all the director options. Additions and updates can be found in the [http://forums.steampowered.com/forums/showthread.php?t=1238461 Steam Forums]
 
*'''A_CustomFinaleX''' = stage type (enumerated PANIC, ONSLAUGHT, DELAY, TANK); where X is the stage number. For scripted panic event or custom finale.
 
*'''A_CustomFinaleValueX''' = Value depends on the stage type. Please see example article or official decrypted scripts. For scripted panic event or custom finale.
 
*'''AlwaysAllowWanderers''' = true|false
 
*'''BehindSurvivorsSpawnDistance''' = Appears to require ''PreferredSpecialDirection = SPAWN_BEHIND_SURVIVORS''
 
*'''BileMobSize''' = NUM ? Doesn't seem to do anything (found in c6m3_port_finale.nut)
 
*'''BoomerLimit''' = maximum number of boomers allowed
 
*'''BuildUpMinInterval'''
 
*'''ChargerLimit''' = maximum number of chargers allowed
 
*'''CommonLimit''' = maximum number of commons allowed
 
*'''DisallowThreatType''' = ZOMBIE_WITCH, ZOMBIE_TANK (other values???) Ex: c8m1_apartment.nut
 
*'''FallenSurvivorPotentialQuantity''' = int
 
*'''FallenSurvivorSpawnChance''' = float [0...1]
 
*'''DominatorLimit''' {{todo|confirm category/working}}
 
*'''GasCansOnBacks''' = true|false
 
*'''HunterLimit''' = maximum number of hunters allowed
 
*'''IntensityRelaxAllowWanderersThreshold'''
 
*'''IntensityRelaxThreshold''' = All survivors must be below this intensity before a Peak is allowed to switch to Relax (in addition to the normal peak timer)
 
*'''IntensityThreshold'''
 
*'''JockeyLimit''' = maximum number of jockeys allowed
 
*'''LockTempo''' = 0 ???
 
*'''MaxSpecials''' = number of specials allowed at once
 
*'''MegaMobMaxSize''' = maximum megamob size
 
*'''MegaMobMinSize''' = minimum megamob size
 
*'''MegaMobSize''' {{todo|confirm category/working}}
 
*'''MinimumStageTime''' = in seconds Ex: c1m4_delay.nut {{todo|possibly finale or custom panic event specific}}
 
*'''MobMaxPending''' = Guessing it's the maximum mob size that can be pending for spawn.
 
*'''MobMaxSize''' = max mob size
 
*'''MobMinSize''' = min mob size
 
*'''MobRechargeRate''' = Guessing it's the speed at which a mob regenerates (ie next mob)
 
*'''MobSpawnMaxTime''' = max time in seconds for mob spawn
 
*'''MobSpawnMinTime''' = min time in seconds? for mob spawn
 
*'''MobSpawnSize'''
 
*'''MusicDynamicMobScanStopSize''' = When see fewer than this many of a mob, music stops
 
*'''MusicDynamicMobSpawnSize''' = ???Spawning a mob this large can play music
 
*'''MusicDynamicMobStopSize''' = When a mob gets to this size we think about stopping the music
 
*'''NumReservedWanderers''' = the number of infected that cannot be absorbed
 
*'''PanicForever''' * this seems to only work in gauntlets
 
*'''PanicWavePauseMax''' (float) {{todo|confirm category/working}}
 
*'''PanicWavePauseMin''' (float) {{todo|confirm category/working}}
 
  
*'''PreferredMobDirection''' = SPAWN_ABOVE_SURVIVORS, SPAWN_ANYWHERE, SPAWN_BEHIND_SURVIVORS, SPAWN_FAR_AWAY_FROM_SURVIVORS, SPAWN_IN_FRONT_OF_SURVIVORS , SPAWN_LARGE_VOLUME, SPAWN_NEAR_IT_VICTIM, SPAWN_NO_PREFERENCE
+
All Director Scripts are placed in the script scope <code>DirectorScript</code>
  
{{note|SPAWN_NEAR_IT_VICTIM does not exist before a finale and will cause an error, so I'm assuming the director picks someone as IT when the finale starts. SPAWN_LARGE_VOLUME is what makes you be a mile away on DC finale.}}
+
=== Entity Scripts ===
 +
;Automatic loading at map start
 +
:Uses the script set in the '''Entity Scripts''' KeyValue of the entity.
 +
;Manual loading
 +
:Using the <code>RunScriptFile</code> input.
  
*'''PreferredSpecialDirection '''
+
Entity Scripts are placed in the script scope <code>_<unique ID>_<entity name></code>
{{note|The same values for PreferredMobDirection appear to work, BUT I've also seen the following, I don't know if it's just redundancy or what.
 
SPAWN_SPECIALS_ANYWHERE
 
SPAWN_SPECIALS_IN_FRONT_OF_SURVIVORS}}
 
  
*'''PreTankMobMax''' = int {{todo|confirm category/working; possibly gauntlet specific}}
+
=== Global Scripts ===
*'''ProhibitBosses''' = true|false - prohibit tanks/witches
+
;Mode Specific Scripts
*'''RelaxMaxFlowTravel''' = 600
+
: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>.
*'''RelaxMaxInterval''' = 5
+
:They are placed in the script scope <code>g_ModeScript</code>
*'''RelaxMinInterval''' = 5
 
*'''ShouldAllowMobsWithTank''' = true|false
 
*'''ShouldAllowSpecialsWithTank''' = true|false
 
*'''ShouldConstrainLargeVolumeSpawn''' = true|false
 
*'''SmokerLimit''' = maximum number of smokers allowed
 
*'''SpecialInitialSpawnDelayMin'''
 
*'''SpecialInitialSpawnDelayMax'''
 
*'''SpecialRespawnInterval''' = time in seconds for special respawns
 
*'''SpitterLimit''' = maximum number of spitters allowed
 
*'''SurvivorMaxIncapacitatedCount''' = Maximum amount of survivor incapacitating before dying
 
*'''SustainPeakMaxTime''' = in minutes
 
*'''SustainPeakMinTime''' = in minutes
 
*'''TankHitDamageModifierCoop''' = float (mutation1.nut Last Man on Earth) {todo|confirm category}}
 
*'''TankHitDamageModifierVersus''' = float {{todo|confirm category}}
 
*'''TankLimit''' = maximum number of tanks allowed (for example, used in c7m3_port.nut)
 
*'''TankRunSpawnDelay''' = in seconds (mutation19.nut Taaannnkk!) {{todo|confirm category}}
 
*'''TempHealthDecayRate''' = 0.27 // pain_pills_decay_rate default, higher values equals quicker decay
 
*'''WanderingZombieDensityModifier''' = float {{todo|confirm category/working}}
 
*'''WitchLimit''' = maximum number of witches allowed (used in c7m3_port.nut)
 
*'''ZombieSpawnRange''' = How far away can zombies spawn?
 
*'''ZombieSpawnInFog''' = true|false
 
  
*'''function Update()'''
+
{{note|Adding a script for a mode will enable Scripted Mode on it.}}
:If you define an Update() function in your vscript, it will run repeatedly much like a Think() function, but ONLY a finale via [[trigger_finale]] is triggered, if you have multiple scripts that are running that define it, they all will be called. The use of Update() is also found in the Bleed Out mutation (mutation3.nut), but needs further testing to see see if it behaves the same way like during a finale.
 
  
=== Finale Specific/Related ===
+
;Map Specific Scripts (only available in Scripted Mode)
A normal finale consists of X number of stages. Some variables in DirectorOptions can only be used during finales.
+
: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>.
*'''A_CustomFinale_StageCount'''
+
:They are placed in the script scope <code>g_MapScript</code>
*'''A_CustomFinaleX''' = stage type (enumerated PANIC, ONSLAUGHT (AKA SCRIPTED), DELAY, TANK), where X is the stage number. Also used in scripted panic events.
 
*'''A_CustomFinaleValueX''' = Value depends on the stage type above. Also used in scripted panic events. Please see the example.
 
*'''A_CustomFinaleMusicX''' = [[Soundscript]] entry to play. For instance, <code>A_CustomFinaleMusic1 = "C2M5.BadManTank2"</code>. Note that c2m5_concert_finale.nut does not use this method and instead opted to use entities within the map instead. In the c2m5 script <code>A_CustomFinaleMusic4 = ""</code>, suggesting that no song is actually played automatically via script.
 
{{note|There is also a D_CustomFinale_StageCount, D_CustomFinaleX, etc. found in c3m4_plantation_finale.nut but the difference between A and D are unknown. B_, C_, and E_ are also available.}}
 
*'''EscapeSpawnTanks''' = true|false
 
*'''HordeEscapeCommonLimit''' = number of commons allowed when the escape vehicle has arrived
 
*'''function OnBeginCustomFinaleStage( num, type )'''
 
:If defined, will be called on every stage change with the number, and type, this is how you would change director options between stages (spawn directions, etc). <code>num</code> refers to the finale stage number passed by the director and <code>type</code> is the stage type (PANIC, TANK, etc.).
 
*'''function OnChangeFinaleMusic()''' {{todo|confirm category/working}}
 
  
A stage can be one of 4 types (other values will break the finale and go right to ESCAPE):
 
*PANIC - a panic event, the value is the number of them (ie 2 would be 2 panic events in a row)
 
*TANK - spawn a tank(s), the value is the number of tanks to spawn
 
*DELAY - a delay, the value is the number of seconds to wait before proceeding to the next stage
 
*ONSLAUGHT - The value should be the name of a vscript to call or "" (which will do nothing), any bad value here will crash you to the desktop. Your onslaught script is responsible for sending an EndCustomScriptedStage input to the director (a goal of your choice, like a certain trigger volume, timer, random value, etc.). Otherwise, the '''onslaught will not end.'''
 
  
An example custom finale script:
 
{{ScrollBox|<source lang=lua>
 
ERROR <- -1
 
PANIC <- 0
 
TANK <- 1
 
DELAY <- 2
 
ONSLAUGHT <- 3 // In some vscripts (c8m5_rooftop_finale), ONSLAUGHT is labeled as SCRIPTED
 
  
DirectorOptions <-
+
== Scripting environment ==
{
+
'''Please see [[List of L4D2 Script Functions]] for built in classes and functions.'''
//-----------------------------------------------------
 
CommonLimit = 10
 
A_CustomFinale_StageCount =
 
 
A_CustomFinale1 = PANIC
 
A_CustomFinaleValue1 = 2  // two panic events
 
 
A_CustomFinale2 = DELAY
 
A_CustomFinaleValue2 = 12  // delay for twelve seconds in addition to stage delay
 
 
A_CustomFinale3 = TANK
 
A_CustomFinaleValue3 = 3  // 3 tanks!
 
 
A_CustomFinale4 = DELAY
 
A_CustomFinaleValue4 = 12 // wait some more
 
 
A_CustomFinale5 = ONSLAUGHT
 
A_CustomFinaleValue5 = "my_onslaught_script.nut" // run our onslaught script
 
 
A_CustomFinale6 = DELAY
 
A_CustomFinaleValue6 = 15 // wait 15 seconds
 
 
A_CustomFinale7 = TANK
 
A_CustomFinaleValue7 = 1  // one more tank
 
  
A_CustomFinale8 = DELAY
+
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.
A_CustomFinaleValue8 = 10 // wait ten seconds ... rescue!
 
 
SpecialRespawnInterval = 25
 
  
//-----------------------------------------------------
+
=== Table structure ===
 +
<source lang=cpp>
 +
DirectorScript = // Base Director Scope.
 +
{
 +
DirectorOptions // Base DirectorOptions table.
 +
MapScript =  // Map Script scope.
 +
{
 +
BaseScriptedDOTable // Hardcoded DirectorOptions.
 +
ChallengeScript = // Mode Script scope.
 +
{
 +
MutationState // Initial values for SessionState.
 +
MutationOptions // Initial values for SessionOptions.
 +
}
 +
LocalScript = // Script Scope Director Scripts are placed in.
 +
{
 +
DirectorOptions // DirectorOptions for current Director Script (like onslaughts). Only availabe when a script is active.
 +
}
 +
MapOptions // Initial values for SessionOptions.
 +
MapState // Initial values for SessionState.
 +
}
 
}
 
}
 +
g_MapScript // Global reference to the Map Script scope (DirectorScript.MapScript).
 +
g_ModeScript // Global reference to the Mode Script scope (DirectorScript.MapScript.ChallengeScript).
 +
g_rr // Scope holding the Response Rule system.
 +
g_RoundState // TODO
 +
SessionOptions //Global Director options (Scripted mode only).
 +
SessionState  //State variables for game modes (Scripted mode only).
 +
</source>
  
function OnBeginCustomFinaleStage( num, type )
 
{
 
      printl( "Beginning custom finale stage " + num + " of type " + type );
 
      MapScript.DirectorOptions.CommonLimit = num * 10 // increase commons by 10 linearly with stages
 
}</source>}}
 
  
=== Gauntlet Specific/Related ===
+
=== Delegation ===
Most of these can be found in director_gauntlet.nut
+
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.
*'''CustomTankKiteDistance''' (3000 is the default) {{todo|confirm category/working}}
+
 
*'''GauntletMovementThreshold'''
+
The tables are delegated like this (parent tables on the right):
*'''GauntletMovementTimerLength'''
+
; The Director Scope
*'''GauntletMovementBonus'''
+
: <code>(DirectorScript.MapScript.ChallengeScript; DirectorScript.MapScript.LocalScript) < DirectorScript.MapScript < DirectorScript < ::</code>
*'''GauntletMovementBonusMax'''
+
;DirectorOptions
 +
:<code>DirectorScript.MapScript.LocalScript.DirectorOptions (When Director Script active) < DirectorScript.MapScript.ChallengeScript.DirectorOptions (Scripted mode only) < DirectorScript.DirectorOptions</code>
  
=== Mutation Specific/Related ===
+
== Entity Scripts ==
Some of these values are mutation specific values of the global ones (cm_CommonLimit,cm_MaxSpecials, etc.), so use them if you are making a mutation, incase any map scripts are changing the global values.
+
Use script scope <code>_<unique ID>_<entity name></code>
  
*'''ActiveChallenge'''
+
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.  
*'''cm_AggressiveSpecials'''
 
*'''cm_AllowPillConversion'''
 
*'''cm_AllowSurvivorRescue'''
 
*'''cm_AutoReviveFromSpecialIncap''' Used by "The Last Man On Earth" and "Lone Gunman" mutations (mutation1.nut and mutation17.nut)
 
*'''cm_BaseCommonAttackDamage'''
 
*'''cm_BaseSpecialLimit'''
 
*'''cm_CommonLimit'''
 
*'''cm_DominatorLimit'''
 
*'''cm_FirstManOut''' Used by the "Room For One" mutation (mutation10.nut)
 
*'''cm_frustrationTimer'''
 
*'''cm_HeadshotOnly'''
 
*'''cm_HealingGnome'''
 
*'''cm_InfiniteFuel''' (mutation7.nut Chainsaw Massacre)
 
*'''cm_MaxSpecials'''
 
*'''cm_NoRescueClosets'''
 
*'''cm_NoSurvivorBots'''
 
*'''cm_ProhibitBosses'''
 
*'''cm_ShouldHurry'''
 
*'''cm_SingleScavengeCluster''' Used for scavenge cans to spawn one-by-one
 
*'''cm_SpecialRespawnInterval'''
 
*'''cm_SpecialSlotCountdownTime'''
 
*'''cm_TankLimit'''
 
*'''cm_TankRun''' Used in Taaank! mutation (mutation19.nut)
 
*'''cm_TempHealthOnly''' Only temporary health
 
*'''cm_VIPTarget'''
 
*'''cm_WanderingZombieDensityModifier'''
 
*'''cm_WitchLimit'''
 
  
*'''function AllowWeaponSpawn()'''
+
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>.
:Returns true or false if the given classname is allowed to spawn, used by several mutations
 
*'''function ConvertWeaponSpawn()'''
 
:Converts a weapon spawn of given classname to another, used by several mutations
 
*'''function ConvertZombieClass()'''
 
:Converts one spawn into another, used by the tankss! mutation (mutation19.nut)
 
*'''function GetDefaultItem()'''
 
:ID starts from 0 and ends in an unknown point. Return a string of a weapon name to make it a default item for survivors. Used in several mutations
 
*'''function ShouldAvoidItem()'''
 
:Probably a bot related function or spawn related, not sure
 
  
=== Scavenge Specific/Related ===
+
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]].
*'''ScavengeClusterBonusTime''' = float {{todo|confirm category/working}}
 
*'''ScavengeRoundInitialTime''' = float {{todo|confirm category/working}}
 
*'''ScavengeScoreBonusTime''' = float (used in mutation13.nut Follow the Liter)
 
  
=== Survival Specific/Related ===
+
Some entities have additional script functionality:
*'''SurvivalSetupTime''' = (Used in mutation15.nut for Survival Versus with setup time of 90 seconds)
+
*[[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>.
 +
*[[point_template]]
 +
*[[env_entity_maker]]
 +
*[[info_item_position]]
  
== Squirrel in L4D2 ==
 
'''Please see [[List of L4D2 Script Functions]].''' {{todo|Merge!}}
 
{{merge|List of L4D2 Script Functions}}
 
  
The following are available in L4D2 by default.[http://forums.steampowered.com/forums/showthread.php?t=1238461][http://www.leeland.net/vscript-faq.html]
+
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.
{{Warning|}}NEVER use the = operator when trying to influence the director. Use <-. The difference is semantics. If you use =, it will throw an error if the table slot isn't defined (like if a previous script didn't define it). <-, on the other hand, will create the variable if it does not exist.
 
=== Variables ===
 
{{todo|Add Variables}}
 
=== Classes ===
 
==== CDirector ====
 
Game Instance: Director
 
*Class Methods
 
**.Clear() - Wipe Director Options
 
**.GetAveragedSurvivorSpan() - Get the distance between the lead and trailing survivors, smoothed over time
 
**.GetAveragedSurvivorSpeed() - Get the rate at which the lead survivor is moving along the flow, smoothed over time
 
**.GetCommonInfectedCount() - GetCommonInfectedCount (no longer is there a need to count another way)
 
**.GetFurthestSurvivorFlow() - Get the maximum distance along the flow that the survivors have reached
 
**.GetGameMode() -  Get the current game mode "versus", "coop", etc.
 
**.GetPendingMobCount() - Returns the number of infected waiting to spawn
 
**.HasAnySurvivorLeftSafeArea() - True when one or more survivors have left the starting safe area
 
**.IsAnySurvivorInCombat() - Returns true if any survivor recently dealt or took damage
 
**.IsPlayingOnConsole() - Returns true if player is running the client on a console like Xbox 360
 
**.IsSinglePlayerGame() - Return true if game is in single player
 
**.IsTankInPlay() - Returns true if any tanks are aggro on survivors
 
**.IsValid()
 
**.L4D1SurvivorGiveItem() - This makes l4d1 survivors give an item
 
**.PlayMegaMobWarningSounds() - Plays a horde scream sound and asks survivors to speak 'incoming horde' lines
 
**.ResetMobTimer() - Trigger a mob as soon as possible when in BUILD_UP (refer to <code>director_debug 1</code>)
 
**.UserDefinedEvent1()-.UserDefinedEvent4() - Generic "user defined script event" hook that can be fired from Squirrel and fires outputs on the director entity in the map, OnUserDefinedScriptEvent1-4. For an example, refer to c7m3_port_finale.nut and the [[info_director]] entity output list in c7m3_port.vmf.
 
*Director Enumerations {{note|These are (or some are) '''script specific''', hence the duplicate values.}}
 
**FINALE_CUSTOM_DELAY = 10
 
**FINALE_CUSTOM_PANIC = 7
 
**FINALE_CUSTOM_SCRIPTED = 9
 
**FINALE_CUSTOM_TANK = 8
 
**FINALE_FINAL_BOSS = 5
 
**FINALE_GAUNTLET_1 = 0
 
**FINALE_GAUNTLET_2 = 3
 
**FINALE_GAUNTLET_BOSS = 15
 
**FINALE_GAUNTLET_BOSS_INCOMING = 14
 
**FINALE_GAUNTLET_ESCAPE = 16
 
**FINALE_GAUNTLET_HORDE = 12
 
**FINALE_GAUNTLET_HORDE_BONUSTIME = 13
 
**FINALE_GAUNTLET_START = 11
 
**FINALE_HALFTIME_BOSS = 2
 
**FINALE_HORDE_ATTACK_1 = 1
 
**FINALE_HORDE_ATTACK_2 = 4
 
**FINALE_HORDE_ESCAPE = 6
 
**SPAWN_ABOVE_SURVIVORS = 6
 
**SPAWN_ANYWHERE = 0
 
**SPAWN_BEHIND_SURVIVORS = 1
 
**SPAWN_FAR_AWAY_FROM_SURVIVORS = 5
 
**SPAWN_IN_FRONT_OF_SURVIVORS = 7
 
**SPAWN_LARGE_VOLUME = 9
 
**SPAWN_NEAR_IT_VICTIM = 2
 
**SPAWN_NO_PREFERENCE = -1
 
**SPAWN_SPECIALS_ANYWHERE = 4
 
**SPAWN_SPECIALS_IN_FRONT_OF_SURVIVORS = 3
 
**SPAWN_VERSUS_FINALE_DISTANCE = 8
 
**ZOMBIE_TANK = 8
 
**ZOMBIE_WITCH = 7
 
  
==== CEntities ====
 
Game Instance: Entities
 
*Class Methods
 
**.FindByClassname (null|prev,classname) - Find entities by class name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search Continue an iteration over the list of entities, providing reference to a previously found entity
 
**.FindByClassnameNearest (classname, vector, radius) - Find the entity of a given class name nearest to a point. If radius is 0, searches the whole map.
 
**.FindByClassnameWithin (null|prev, classname, vector, radius) - Find entities by class name within a radius. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search. If radius is 0, simply returns FindByClassname()'s result.
 
**.FindByModel (null|prev, modelname) - Find entities by model name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search
 
**.FindByName (null|prev, entname) - Find named entities. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search.
 
**.FindByNameNearest (name, vector, radius) - Find the entity nearest to a given point. If radius is 0, searches the whole map.
 
**.FindByNameWithin (null|prev, name, vector, radius) - Find entities by name within a radius. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search. If radius is 0, simply returns FindByName()'s result.
 
**.FindByTarget (null|prev, targetname) - Find entities by target. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search
 
**.FindInSphere (null|prev, vector, radius) - Find entities within a radius. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search.
 
**.IsValid() - whether entity is valid
 
**.First() - Begin an iteration over the list of entities
 
**.Next(null|prev) - Returns the next entity in the Entities list
 
  
==== CBaseEntity ====
+
=== [[Inputs_and_Outputs|I/O system]] interaction ===
Game Instance: N/A
+
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.
*Class Methods
 
**.__KeyValueFromInt(key,int) - Sets a keyvalue from an integer, the keys available for all __KeyValue are from the DEFINE_KEYFIELD in baseentity.cpp (classname,rendermode, renderfx, etc.)
 
**.__KeyValueFromString(key,string) - Sets a keyvalue from a string, the keys available for all __KeyValue are from the DEFINE_KEYFIELD in baseentity.cpp (classname,rendermode, renderfx, etc.)
 
**.__KeyValueFromVector(key,vector) - Sets a keyvalue from a vector, the keys available for all __KeyValue are from the DEFINE_KEYFIELD in baseentity.cpp (classname,rendermode, renderfx, etc.)
 
**.ConnectOutput(outputname,functioname) - Adds an I/O connection that will call the named function when the specified output fires
 
**.DisconnectOutput(event) - Removes a connected script function from an I/O event
 
**.FirstMoveChild() - returns entity's first move child if exists
 
**.GetClassname() - returns classname
 
**.GetForwardVector() - returns Vector instance
 
**.GetHealth() - returns entity health
 
**.GetMoveParent() - If in hierarchy, retrieves the entity's parent
 
**.GetName() - returns targetname of entity (if entity is named)
 
**.GetOrigin() - returns origin vector
 
**.GetPreTemplateName - Get the entity name stripped of template unique decoration. ie myitem&0125 returns myitem
 
**.GetRootMoveParent() - If in hierarchy, walks up the hierarchy to find the root parent
 
**.GetScriptId() - Retrieve the unique identifier used to refer to the entity within the scripting system
 
**.GetScriptScope() - Retrieve the script-side data associated with an entity
 
**.GetVelocity() - returns velocity vector
 
**.IsValid() - whether entity is valid
 
**.NextMovePeer - returns next child entity
 
**.SetForwardVector(vector) - Set the orientation of the entity to have this forward vector
 
**.SetHealth(int) - sets entity health
 
**.SetOrigin(vector) - sets entity position in world
 
**.SetVelocity(vector) - sets entity velocity
 
**.ValidateScriptScope - Ensure that an entity's script scope has been created
 
;Functions
 
*function OnPostSpawn()
 
:If you declare a function OnPostSpawn() in your vscript, when the entity that is using the script is spawned, it will run this function automatically. You could use this to have an entity register itself with a master script or just do whatever needed to be down immediately after spawn.
 
  
==== CEnvEntityMaker ====
+
<source lang=cpp>
*Class Methods
+
EntFire( "church_bell_relay", "Trigger", 0 ); // Fires an output to the Trigger input of the named entity.
**SpawnEntity() - Create an entity at the location of the maker
 
**SpawnEntityAtEntityOrigin(handle) - Create an entity at the location of a specified entity instance
 
**SpawnEntityAtLocation(Vector, Vector) - Create an entity at a specified location and orientaton, orientation is Euler angle in degrees (pitch, yaw, roll)
 
**SpawnEntityAtNamedEntityOrigin(string) - Create an entity at the location of a named entity
 
  
==== CPointTemplate ====
+
player <- null;
{{note|These functions apparently work with [[point_template]]. In other words, designate a vscript in the entity KeyValues and include the function in the script.}}
+
while(player = Entities.FindByClassname(player, "player"))  // Iterate through the script handles of the players.
*function PostSpawn( entities )
 
:Called after the entity was spawned, you could use this to connect outputs or do whatever needs to be done after the entity was created.
 
<pre>
 
function PostSpawn( entities )
 
 
{
 
{
foreach( k, v in entities ) //name, ent ref
+
    DoEntFire("!self", "speakresponseconcept", "PlayerLaugh", 0, null, player); // Make each player laugh.
{
 
printl( k + ": " + v );
 
}
 
 
}
 
}
</pre>
+
</source>
 +
 
 +
 
 +
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.
 +
{{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 ==
 +
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.
 +
 
 +
{{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 ===
 +
Use script scope <code>g_ModeScript</code>
 +
 
 +
==== Tables ====
 +
;<code>MutationState</code>
 +
:Initial values for the <code>SessionState</code> table.
 +
;<code>MutationOptions</code>
 +
:Initial values for the <code>SessionOptions</code> table.
 +
 
 +
 
 +
=== Map Scripts ===
 +
Use script scope <code>g_MapScript</code>
 +
 
 +
==== Tables ====
 +
;<code>MapState</code>
 +
:Map specific values for the <code>SessionState</code> table.
 +
;<code>MapOptions</code>
 +
:Map specific values for the <code>SessionOptions</code> table.
  
*function PreSpawnInstance(entityClass, entityName)
 
:If this is defined, it will be called right before the entity is created, any key,values returned will be assigned to the entity.
 
<pre>function PreSpawnInstance( entityClass, entityName )
 
{
 
return {
 
  rendercolor = "0 255 0"
 
  targetname = "blah"
 
};
 
}</pre>
 
:You could use this to dynamically assign target names, colors, even models. Unfortunately, models don't work like you would think. Yes, you can change that gas tank into a football model, will even keep the weapon_gascan class, but it won't behave like one. Also tested this out on zombie spawners, but unfortunately, they don't use these hooks which is a shame, because how cool would it have been to have 3 tank models in play at once?
 
  
==== CBaseAnimating ====
+
== Glossary ==
'''Extends''' CBaseEntity
+
;DirectorOptions
*Class Methods
+
:A table of named variables that override the AI Director behavior.
**.__KeyValueFromInt(key,int) - Sets a keyvalue from an integer, the keys available for all __KeyValue are from the DEFINE_KEYFIELD in baseentity.cpp (classname,rendermode, renderfx, etc)
+
;Entity handle
**.__KeyValueFromString(key,string) - Sets a keyvalue from a string, the keys available for all __KeyValue are from the DEFINE_KEYFIELD in baseentity.cpp (classname,rendermode, renderfx, etc)
+
:Also known as EHANDLE. {{todo|Looks like some sort of pointer reference to an entity.}}
**.__KeyValueFromVector(key,vector) - Sets a keyvalue from a vector, the keys available for all __KeyValue are from the DEFINE_KEYFIELD in baseentity.cpp (classname,rendermode, renderfx, etc)
+
;Script handle
**.ConnectOutput(outputname,functioname) - Adds an I/O connection that will call the named function when the specified output fires
+
:An entity instance with accessors and mutators to the C++ entity object. Also known as HScript.
**.DisconnectOutput(event) - Removes a connected script function from an I/O event
+
;Script scope
**.FirstMoveChild() - returns entity's first move child if exists
+
:The table where the variables, functions and classes of a VScript are placed.
**.GetClassname() - returns classname
 
**.GetForwardVector() - returns Vector instance
 
**.GetHealth() - returns entity health
 
**.GetMoveParent() - If in hierarchy, retrieves the entity's parent
 
**.GetName() - returns named (if entity is named)
 
**.GetOrigin() - returns origin vector
 
**.GetPreTemplateName - Get the entity name stripped of template unique decoration. ie myitem&0125 returns myitem
 
**.GetRootMoveParent() - If in hierarchy, walks up the hierarchy to find the root parent
 
**.GetScriptId() - Retrieve the unique identifier used to refer to the entity within the scripting system
 
**.GetScriptScope() - Retrieve the script-side data associated with an entity
 
**.GetVelocity() - returns velocity vector
 
**.IsValid() - whether entity is valid
 
**.NextMovePeer - returns next child entity
 
**.SetForwardVector(vector)
 
**.SetHealth(int) - sets entity health
 
**.SetOrigin(vector) - sets entity position in world
 
**.SetVelocity(vector) - sets entity velocity
 
**.ValidateScriptScope - Ensure that an entity's script scope has been created
 
  
==== CNavMesh ====
 
Game Instance: NavMesh
 
*Class Methods
 
**.IsValid
 
**.UnblockRescueVehicleNav() - Removes the block for rescue vehicle. Normally is blocked before the finale is finished, but is necessary for bots to access like in the Atrium finale, c1m4_atrium.bsp.
 
  
==== CCallChainer ====
+
== Director options ==
Game Instance: N/A
+
'''Please see [[L4D2 Director Scripts#DirectorOptions|L4D2 Director Scripts]] for a table of available options.'''
*Class Methods
 
**.chains
 
**.constructor
 
**.PostScriptExecute
 
**.prefix
 
**.scope
 
==== CSimpleCallChainer ====
 
*Class Methods
 
**.Call
 
**.chain
 
**.constructor
 
**.exactMatch
 
**.PostScriptExecute
 
**.prefix
 
**.scope
 
==== regxp ====
 
{{todo|}}
 
Game Instance:
 
*Class Methods
 
==== Vector ====
 
Game Instance: None
 
*Class Methods
 
**.constructor
 
**.Cross
 
**.Dot
 
**.Length
 
**.Length2D
 
**.Length2DSqr
 
**.LengthSqr
 
**.Norm
 
**.ToKVString
 
  
=== Functions ===
 
*Assert(value, "optional message") - test value and if not true, throws exception, optionally with messsage
 
*ConnectOutputs(table) - sets output functions for entity by table TODO
 
*DebugDrawBox(Vector, Vector, Vector, int, int, int, int, float) - Draw a debug overlay box
 
*DebugDrawLine(Vector, Vector, int, int, int, bool, float) - Draw a debug overlay line
 
*Developer() - returns 1 or TRUE when in developer mode
 
*DoEntFire( target.tostring(), action, value, delay, activator, caller ) - Fire an event
 
*EntFire(target, action, value, delay, activator) - "ent_fire target event" - wrapper for DoEntFire() that sets activator and caller to null
 
*DoIncludeScript(string, caller) - Execute a script (internal)
 
*IncludeScript - Wrapper for DoIncludeScript
 
*GetFunctionSignature
 
*Msg("message here") - prints message to console
 
*printl("message") - prints message with carriage return
 
*RandomFloat() - Returns a random float
 
*RandomFloat(float, float) - Generate a random floating point number within a range, inclusive
 
*RandomInt() - Returns a random int between 0 and 32767
 
*RandomInt(int, int) - Generate a random integer within a range, inclusive
 
*RetrieveNativeSignature
 
*SendToConsole("string")- send a string to the console as a command
 
*ShowMessage("message") - Print a hud message on all clients
 
*Time() - Get the current server time
 
*DoUniqueString - Called by UniqueString, prob want to call that instead
 
*UniqueString() - Generate a string guaranteed to be unique across the life of the script VM, with an optional root string. Useful for adding data to tables when not sure what keys are already in use in that table.
 
  
{{sq}}Standard Squirrel library functions (consult official Squirrel language league for more details):
+
== Third party tools ==
abs,
 
acos,
 
array,
 
asin ,
 
assert,
 
atan ,
 
atan2,
 
ceil,
 
collectgarbage,
 
compilestring,
 
cos,
 
exp ,
 
fabs ,
 
floor,
 
format,
 
getconsttable,
 
getroottable,
 
getstackinfos,
 
log,
 
log10,
 
lstrip,
 
pow,
 
print,
 
rand,
 
rstrip,
 
setconsttable,
 
seterrorhandler,
 
setroottable,
 
type,
 
sin,
 
split,
 
sqrt,
 
srand,
 
strip,
 
suspend,
 
tan
 
  
=== Constants ===
+
===VSLib===
{{todo|Add Constants}}
+
'''VSLib''' (''VS''cript ''Lib''rary) 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 [http://steamcommunity.com/sharedfiles/filedetails/?id=214630948 Rayman1103's Admin System] and [http://steamcommunity.com/sharedfiles/filedetails/?id=157525096 Stranded]. Read more about [[VSLib]].
  
 
== See also ==
 
== See also ==
 
*[[L4D2 Vscript Examples]]
 
*[[L4D2 Vscript Examples]]
 
*[[List of L4D2 Script Functions]]
 
*[[List of L4D2 Script Functions]]
 +
*[[L4D2 EMS|Extended Mutation System]]
 
*[[L4D2_Level_Design/Boss_Prohibition|L4D2 Level Design/Boss Prohibition]]
 
*[[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]]
Line 548: Line 262:
 
*[[Logic_script|logic_script]]
 
*[[Logic_script|logic_script]]
 
*[[VScript|vscripts]]
 
*[[VScript|vscripts]]
 +
*[[VSLib]]
  
 
== External links ==
 
== External links ==
 +
;Alternative Tool
 +
* [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)]
 
* [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)]
 
* [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)]
**[http://www.leeland.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
 
**[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"
Line 564: Line 281:
 
* {{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.multiupload.com/OXO3T2S1YA Version 2.0.1.8 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}} = [[image:pnkhrt-16px.png]]</div>

Latest revision as of 08:04, 5 March 2019

简体中文 简体中文

<Squirrel Language><Left 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.


Uses

Director Scripts

The most common use of 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 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 scripting and modify global Director options for mutations, but can also be used in custom maps.

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 plain text .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: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.
  • 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.

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 also be manually loaded with the console command script filename

Director Scripts

Using the info_director entity using the following inputs
BeginScript <script name>
Executes a generic Director script, for example for onslaught events or changing spawning behavior.
EndScript
Ends the running script and resets the Director options to the map specific values.
BeginScriptedPanicEvent <script name>
Begins a Scripted Panic event.
Note:Scripts used with BeginScriptedPanicEvent 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 <map name>_finale.nut 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 ForceFinaleStart input.
To do: 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 DirectorScript

Entity Scripts

Automatic loading at map start
Uses the script set in the Entity Scripts KeyValue of the entity.
Manual loading
Using the RunScriptFile input.

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

Global Scripts

Mode Specific Scripts
Will automatically run the script with the same name as the game mode. For example, running a map map <map name> mutation12 will automatically load the Realism Versus script, mutation12.nuc.
They are placed in the script scope g_ModeScript
Note:Adding a script for a mode will enable Scripted Mode on it.
Map Specific Scripts (only available in Scripted Mode)
Per-map scripts can be created that run when the map is loaded in the specified game mode, using the syntax <map name>_<mode name>.nut, for example, c1m4_atrium_mutation12.nut.
They are placed in the script scope g_MapScript


Scripting environment

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

DirectorScript = 			// Base Director Scope.
{
	DirectorOptions 		// Base DirectorOptions table.
	MapScript =  			// Map Script scope.
	{
		BaseScriptedDOTable 	// Hardcoded DirectorOptions.
		ChallengeScript = 	// Mode Script scope.
		{
			MutationState 	// Initial values for SessionState.
			MutationOptions // Initial values for SessionOptions.
		}
		LocalScript =		// Script Scope Director Scripts are placed in.
		{
			DirectorOptions // DirectorOptions for current Director Script (like onslaughts). Only availabe when a script is active.
		}
		MapOptions 		// Initial values for SessionOptions.
		MapState 		// Initial values for SessionState.
	}
}
g_MapScript 	// Global reference to the Map Script scope (DirectorScript.MapScript).
g_ModeScript 	// Global reference to the Mode Script scope (DirectorScript.MapScript.ChallengeScript).
g_rr		// Scope holding the Response Rule system.
g_RoundState	// TODO
SessionOptions 	//Global Director options (Scripted mode only).
SessionState  	//State variables for game modes (Scripted mode only).


Delegation

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

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

The Director Scope
(DirectorScript.MapScript.ChallengeScript; DirectorScript.MapScript.LocalScript) < DirectorScript.MapScript < DirectorScript < ::
DirectorOptions
DirectorScript.MapScript.LocalScript.DirectorOptions (When Director Script active) < DirectorScript.MapScript.ChallengeScript.DirectorOptions (Scripted mode only) < DirectorScript.DirectorOptions

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: 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 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.

To do: 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 g_ModeScript 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.

To do: Does enabling Scripted Mode have any other consequences?

Shared Tables

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

Available Functions

To do: Document the available utility features.


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.


Glossary

DirectorOptions
A table of named variables that override the AI Director behavior.
Entity handle
Also known as EHANDLE. To do: 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

External links

Alternative Tool
Alternative Documentation
Deciphered Official Scripts
<Squirrel Language>+<Left 4 Dead 2> = Pnkhrt-16px.png