This article's documentation is for anything that uses the Source engine. Click here for more information.

Script: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(stuff)
Line 1: Line 1:
{{this is a|console command|name=script|notext=1|since=Left 4 Dead 2}}
{{This is a|console command|name=script|notext=1|since=Left 4 Dead 2}}


It is available in all games that have a {{sq|4}} implementation of [[VScript]], namely [[VScript#Squirrel|these]].
It is available in all games that have a {{sq|4}} implementation of [[VScript]], namely [[VScript#Squirrel|these]].
Line 10: Line 10:


== Limitations ==
== Limitations ==
Semicolons {{code2|;}} cannot be used for scripting needs when outside of quotes because the [[Developer Console|developer console]] treats them as a delimiter for console commands.
=== Semicolons ===
* Usage of {{code2|for}} statements is only possible by utilizing <code>compilestring</code> function as follows <code>script compilestring("for(local i = 0; i < 10; i++) printl(i)")()</code>
Semicolons {{code2|&semi;}} can be used for scripting needs only inside of quotes because the [[Developer Console|developer console]] otherwise treats them as a delimiter for console commands.
* Multiple script commands separated by semicolons will fail to parse correctly if there is a space between them due to Squirrel attempting to use the semicolon as a separator. For example, {{code2|script printl("print1"); script printl("print2")}} will throw a script error, but {{code2|script printl("print1");script printl("print2")}} will not.
* First way to use them is by enclosing whole code in quotes. In which case those 2 quotes are the only quote symbols allowed because the command is searching for the ending quote and it cannot be escaped in console
:<syntaxhighlight lang=js>script "local a = 666; for(local i; i < 10; i++) { printl(i + a) }"</syntaxhighlight>


* Other way to use them is possible if they are within quotes in a string.
:<syntaxhighlight lang=js>script printl("I can print ; but I now cannot use it inside for syntax or to separate local variable definition")</syntaxhighlight>
* Utilizing <code>compilestring</code> which compiles a string into a function it's possible to use <code>for</code> or <code>local</code> keywords while also having using quote symbols for strings
:<syntaxhighlight lang=js>script compilestring("for(local i = 0; i < 10; i++) printl(\"I can now do this: \" + i)")()</syntaxhighlight>


Quotes {{code2|"}} may cause problems.
* Separating non-statements without semicolons and methods above can be done using {{code2|,}} comma.  
* In games on the modern [[SDK 2013]] branch since 2025 ({{tf2}}{{css}}{{dods}}{{hl2dm}}{{hldms}}), the <kbd>RunScriptCode</kbd> input will automatically convert backticks {{code2|`}} in its parameter to quotes {{code2|"}}. Older VScript implementations don't have this ({{l4d2}}{{asw}}{{portal2}}{{csgo}}) but can still escape quotes instead e. g. {{code2|\"string\"}}. This way of escaping quotes is only possible in scripts and '''not''' in Hammer or {{cmd|ent_fire}}.
:<syntaxhighlight lang=js>script printl("i = 0"), i<-666, printl("i = " + i)</syntaxhighlight>


* Separating statements can be somewhat done using statement blocks.
:<syntaxhighlight lang=js>script function f() { {i<-0} while(i++<10) printl(i) }</syntaxhighlight>


Code referencing {{code2|activator}}, {{code2|caller}} or {{code2|self}} may cause an exception. These pre-defined variables normally don't exist and are only created if code is executed from an entity's script scope or in response to [[I/O]].
=== Command parsing ===
* One can use {{code2|RunScriptCode}} inputs to target these variables, e. g. {{code2|ent_fire player runscriptcode "printl(self)"}}
When script command is issued all the text from start of the command (including spaces) up to the ending semicolon is taken, first 6 characters from it are cut and the rest is run as a script. This in result means that if there is any space before script command it will cause errors.
* One can define the variables as needed temporarily, e. g. {{code2|script ::activator <- Entities.FindByClassname(null, "player")}}.
 
The following example shows script command issued with 3 spaces before it. <code>]</code> represents start of the console line.
:<syntaxhighlight lang=js>]  script printl(666)</syntaxhighlight>
 
:Command above will run the script {{code2|ipt printl(666)}} resulting in error.
:The same applies to multiple script commands separated by {{code2|&semi;}}. There must be no space between the ending semicolon and the start of next script command i.e. {{code2|script printl("print1"); script printl("print2")}} will throw a script error, but {{code2|script printl("print1");script printl("print2")}} will not.
 
=== Finding command issuer ===
* {{code2|activator}} or {{code2|caller}} which are automatically created during input accepting wouldn't make much sense in this context and aren't created by script command. Neither is {{code2|self}} which one could reasonably expect to contain the player running the script command. Getting the player running the command is not possible reliably and {{tf2branch|2}} games only allow the server to use script command in which case it could be issued by clients only via {{cmd|rcon}}.
 
* If client connected to a server and has an ability to issue this command they can figure out their player entity by checking {{cmd|status}} and using GetPlayerFromUserID function. In case of {{l4d2}} or {{portal2}} unique [[Targetname#Those_evaluated_by_other_means|special targetnames]] are available and usable by for example <code>Entities.FindByName(null, "!bill")</code>
 
* If the player is a host of the server they can find themselves using <code>Entities.FindByName(null, "!player")</code>
 
* Other means include using {{cmd|ent_fire}} and RunScriptCode input in which the issuer of the command is the activator and caller. [[Generic_Keyvalues,_Inputs_and_Outputs/Inputs#Vscript_inputs|Mind the limitations related to RunScriptCode]]


== Examples ==
== Examples ==

Revision as of 15:00, 11 May 2025

script is a console command available in all Source Source games since Left 4 Dead 2 Left 4 Dead 2.

It is available in all games that have a Squirrel Squirrel implementation of VScript, namely these.

Syntax

script <code>

Description

It executes Squirrel code from the root table. The code can contain spaces even without using quotation marks ".

Limitations

Semicolons

Semicolons ; can be used for scripting needs only inside of quotes because the developer console otherwise treats them as a delimiter for console commands.

  • First way to use them is by enclosing whole code in quotes. In which case those 2 quotes are the only quote symbols allowed because the command is searching for the ending quote and it cannot be escaped in console
script "local a = 666; for(local i; i < 10; i++) { printl(i + a) }"
  • Other way to use them is possible if they are within quotes in a string.
script printl("I can print ; but I now cannot use it inside for syntax or to separate local variable definition")
  • Utilizing compilestring which compiles a string into a function it's possible to use for or local keywords while also having using quote symbols for strings
script compilestring("for(local i = 0; i < 10; i++) printl(\"I can now do this: \" + i)")()
  • Separating non-statements without semicolons and methods above can be done using , comma.
script printl("i = 0"), i<-666, printl("i = " + i)
  • Separating statements can be somewhat done using statement blocks.
script function f() { {i<-0} while(i++<10) printl(i) }

Command parsing

When script command is issued all the text from start of the command (including spaces) up to the ending semicolon is taken, first 6 characters from it are cut and the rest is run as a script. This in result means that if there is any space before script command it will cause errors.

The following example shows script command issued with 3 spaces before it. ] represents start of the console line.

]   script printl(666)
Command above will run the script ipt printl(666) resulting in error.
The same applies to multiple script commands separated by ;. There must be no space between the ending semicolon and the start of next script command i.e. script printl("print1"); script printl("print2") will throw a script error, but script printl("print1");script printl("print2") will not.

Finding command issuer

  • activator or caller which are automatically created during input accepting wouldn't make much sense in this context and aren't created by script command. Neither is self which one could reasonably expect to contain the player running the script command. Getting the player running the command is not possible reliably and Team Fortress 2 branch Team Fortress 2 branch games only allow the server to use script command in which case it could be issued by clients only via rcon.
  • If client connected to a server and has an ability to issue this command they can figure out their player entity by checking status and using GetPlayerFromUserID function. In case of Left 4 Dead 2 or Portal 2 unique special targetnames are available and usable by for example Entities.FindByName(null, "!bill")
  • If the player is a host of the server they can find themselves using Entities.FindByName(null, "!player")

Examples

script printl( GetMapName() )

Prints the name of the current map in the console.

script player <- Entities.FindByClassname(null, "player");
script player.SetMaxHealth( 200 )

Using a variable, find the player with the lowest entity index then set their max health to 200.

script { player <- Entities.FindByClassname(null, "player") } { player.SetMaxHealth(200) }

The same code, but as a single console command, achieved by using curly braces to bypass semicolons. Note that in this example, one pair of curly braces would suffice; if there is no nesting, putting every other statement in curly braces is sufficient. Note also that the statement player <- ... despite the curly braces, creates a table slot in the root table that persists after the closing brace. If the player variable should be a local variable, its assignment statement must not stand alone inside curly braces, since its scope ends with the closing curly brace.

When executing multiple complicated commands repeatedly using the up and down arrow keys in the console it may even be useful to add a comment in the command, for example the following.

script /* SET MAX HEALTH 200 */ { player <- Entities.FindByClassname(null, "player") } { player.SetMaxHealth(200) } // SET MAX HEALTH 200

Squirrel will never see line comments starting with // because the developer console sees and removes them first. Block comments /* */ can also be used because Squirrel supports them!

See also