This article relates to the game "Counter-Strike: Global Offensive". Click here for more information.

CS:GO VScript Examples: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(Added 2 workarounds for running Think functions using timers.)
No edit summary
 
(15 intermediate revisions by 8 users not shown)
Line 1: Line 1:
{{csgo}} The following are example [[VScript|vscripts]] for [[Counter-Strike: Global Offensive]].
{{LanguageBar}}
{{Delisted|csgo}}
{{csgo}} The following are example [[VScript]]s for {{csgo|3}}.


===Find the closest player to a known entity===
===Find the closest player to a known entity===


<source lang=cpp>buttonReference <- Entities.FindByName( null, "button_01" ); // find the in-game entity "button_01" and store its targetname
{|
|<source lang=cpp>
// find an entity named "button_01" and store its handle (or null if not found)
button <- Entities.FindByName( null, "button_01" )
player <- Entities.FindByClassnameNearest( "player", buttonReference.GetOrigin(), 512 ); // find the nearest player within 512 hammer units to the button's origin and create a variable.
// find the nearest player within 512 hammer units to the button's origin and store their handle (or null if not found)
player <- Entities.FindByClassnameNearest( "player", button.GetOrigin(), 512 )
</source>
</source>
|}


===Turn Decoys into Nukes===
=== Functions to distinguish [[bot]]s and human [[player]]s ===


<source lang=cpp>//The following script needs to be attached to something like a logic_script,
To test players other than the activator, give the functions a parameter that replaces <code>activator</code>.
//but any other entity would work as the script will function regardless,
{{warning|Giving [[bot]]s a [[targetname]] will turn them into a [[player]], making the <code>cs_bot</code> loop fail.}}
//as long as the entity is alive and the think function is set to Think()
{|
|- style="vertical-align:top;"
| <source lang=cpp>
// returns true if the activator is a bot
function IsBot()
{
if (!activator) return false
local ent = null
while ( ent = Entities.FindByClassname(ent, "cs_bot") )
{
if (ent == activator) return true
}
return false
}
</source>
| <source lang=cpp>
// returns true if the activator is a human player
function IsHuman()
{
if (!activator) return false
local ent = null
while ( ent = Entities.FindByClassname(ent, "player") )
{
if (ent == activator) return true
}
return false
}
</source>
|- style="vertical-align:top;"
|colspan="2"| <source lang=cpp>
// returns true if the activator is a human player or a bot
function IsPlayer()
{
// both bots and human players have the classname "player" in this case
return activator && activator.GetClassname() == "player"
}
</source>
|}
{{note|If you need to avoid any exceptions, you might also want to check <code>typeof(activator) {{=}}{{=}} "instance" && activator.IsValid()</code> before calling <code>activator.GetClassname()</code>.}}
 
=== Equip players ===
A slightly modified version from <code>csgo/scripts/vscripts/warmup/[[Setting up 1v1 Warmup Arenas|warmup_arena]].nut</code>.
{|
|<source lang=cpp>
// equips the specified players with the specified weapon class
function GiveGun( weapon, playerarray )
{
local equipper = Entities.CreateByClassname( "game_player_equip" )


EXPLOSION_SOUND <- "c4.Explode"; //This can be found in hammer's sound picker
// set flags and keyvalues
equipper.__KeyValueFromInt( "spawnflags", 5 ) // "Use Only" and "Only Strip Same Weapon Type"
equipper.__KeyValueFromInt( weapon, 0 )
// equipper.__KeyValueFromInt( "weapon_knife", 0 )
// equipper.__KeyValueFromInt( "item_kevlar", 0 )


function Precache() //If this is defined it runs automatically when the script is created
equipper.ValidateScriptScope()
 
foreach (player in playerarray)
{
EntFireByHandle( equipper, "Use", "", 0, player, null ) // each player "Use"s the equipper
}
EntFireByHandle( equipper, "Kill", "", 0.1, null, null ) // equipper is no longer needed, so remove it
}
</source>
|}
 
===Iterating over all hostages===
On [[Hostage Rescue|hostage scenario]] maps, it is up to the mapper whether to use {{ent|hostage_entity}} or {{ent|info_hostage_spawn}} for their hostages. In VScript, using the function {{code|Entities.FindByClassname(''handle'', ''classname'')}} to iterate over all hostages requires two loops because both classnames must be searched for using that function. However, no matter how the handle of a hostage {{code|hostage}} was obtained, the following applies: {{code|hostage.GetClassname() {{=}}{{=}} "hostage_entity"}}. Using this fact, an iteration over all hostages can be done as seen in the following. In this example, a global function {{code|IsAnyHostageBeingCarried}} is defined that returns {{mono|true}} whenever there is a CT carrying a hostage.
{{note|A similar inconsistency exists with {{ent|player}} and {{ent|cs_bot}}; Each entity handle of both classnames yield {{code|ent.GetClassname() {{=}}{{=}} "player"}}. There may be more.}}
{|
|<source lang=cpp>
::IsAnyHostageBeingCarried <- function()
{
{
self.PrecacheScriptSound( EXPLOSION_SOUND );
for (local hostage = Entities.First(); hostage = Entities.Next(hostage); )
{
if (hostage.GetClassname() == "hostage_entity")
{
if (hostage.IsBeingCarried())
return true
}
}
return false
}
}
</source>
|}
=== Turn decoys into nukes ===
The following script is a think script, it can be attached to any entity.
The Think function will be executed as long as the entity is alive and has its <code>thinkfunction</code> keyvalue set to "Think".
{|
|<source lang=cpp>
// This can be found in hammer's sound picker
const EXPLOSION_SOUND = "c4.Explode"


//Every 0.1 seconds this checks if any decoy_projectiles exist on the map
// Called after the entity is spawned
//When found it compares the velocity of the projectile with a 0,0,0 vector
function Precache()
//If true the decoy stopped moving so we can run the rest of the script.
{
//An env_explosion is created and configured, it's moved to the decoy's
self.PrecacheScriptSound( EXPLOSION_SOUND )
//position and then triggered. The decoy is then killed.
}
 
// Every 0.1 seconds this function checks for decoy_projectiles in the map
// When found, it checks if the decoy is standing still
// If true create an env_explosion, trigger it and kill the decoy


function Think()
function Think()
{
{
ent <- null;
local decoy = null
while ((ent = Entities.FindByClassname(ent, "decoy_projectile")) != null)
while( ( decoy = Entities.FindByClassname( decoy, "decoy_projectile" ) ) != null )
{
{
if(ent.GetVelocity().Length() == Vector(0,0,0).Length())
if( decoy.GetVelocity().LengthSqr() == 0 )
{
{
owner <- ent.GetOwner();
local owner = decoy.GetOwner()
origin <- ent.GetOrigin();
local origin = decoy.GetOrigin()
 
exp <- Entities.CreateByClassname("env_explosion");
local explosion = Entities.CreateByClassname( "env_explosion" )
exp.__KeyValueFromInt("iMagnitude", 2000);
explosion.__KeyValueFromInt( "iMagnitude", 2000 )
explosion.SetOrigin( origin )
ent.EmitSound(EXPLOSION_SOUND);
explosion.SetOwner( owner )
 
exp.SetOrigin(origin);
EntFireByHandle( explosion, "Explode", "", 0.1, owner, owner )
exp.SetOwner(owner);
DispatchParticleEffect( "explosion_c4_500", origin, origin )
 
EntFireByHandle(exp, "Explode", "", 0.1, owner,owner);
decoy.EmitSound( EXPLOSION_SOUND )
ent.Destroy();
decoy.Destroy()
DispatchParticleEffect("explosion_c4_500", origin, origin);
}
}
}
}
}</source>
}</source>
|}


===Create a Timer to Fire Off an Assigned Think Function Independently===
=== Create a timer to call a function independently ===
{|
|<source lang=cpp>
timer <- null


<source>
function OnTimer()  
thinkTimer <- null;
 
//name <- function() has to be used here instead of function Think()
//when making a function to put into a different scope as a variable.
TimerThink <- function()  
{
{
//put your think function here
print(".")
//since this will be used the timer's scope self will be the timer handle.
//imagine as if this function is in a separate script that's attached to the timer.
print("Tick - ");
}
}


// Called after the entity is spawned
function OnPostSpawn()
function OnPostSpawn()
{
{
if(thinkTimer == null)
if( timer == null )
{
{
thinkTimer = Entities.CreateByClassname("logic_timer"); //create timer
timer = Entities.CreateByClassname( "logic_timer" )
thinkTimer.ValidateScriptScope(); //ensure it's scope is created
local timerScope = thinkTimer.GetScriptScope(); //get the scope
timerScope.Think <- TimerThink; //function Think in the timer scope is now a copy of TimerThink from this script scope
EntFireByHandle(thinkTimer, "AddOutput", "OnTimer !self:RunScriptCode:Think():0:-1", 0, null, null);
//ent_fire convention you can use in console or in hammer
//ent_fire name Addoutput "OutputName Target:Input:Delay:RepeatTimes"
thinkTimer.__KeyValueFromFloat("RefireTime", 0.1); //set the frequency of the timer. You get RefireTime when disabling smartedit in hammer.
EntFireByHandle(thinkTimer, "Enable", "", 0, null, null); //finally, start the timer
}
}


</source>
// set refire time
timer.__KeyValueFromFloat( "RefireTime", 0.1 )


===Attach a Think Function to an Entity at Runtime Using a Timer===
timer.ValidateScriptScope()
local scope = timer.GetScriptScope()
// add a reference to the function
scope.OnTimer <- OnTimer


<source>
// connect the OnTimer output,
thinkTimer <- null;
// every time the timer fires the output, the function is executed
timer.ConnectOutput( "OnTimer", "OnTimer" )


function OnPostSpawn()
// start the timer
{
EntFireByHandle( timer, "Enable", "", 0, null, null )
//Creates the timer and sets it up to run the function Think in this script.
if(thinkTimer == null)
{
thinkTimer = Entities.CreateByClassname("logic_timer"); //create timer
thinkTimer.ValidateScriptScope(); //ensure it's scope is created
local timerScope = thinkTimer.GetScriptScope(); //get the scope
timerScope.mainScriptScope <- self.GetScriptScope(); //save the scope of this script to a variable in timer's scope
timerScope.DoThink <- function() { mainScriptScope.Think() }; //create a DoThink function in the timer's scope to call the Think in this script
thinkTimer.ConnectOutput("OnTimer", "DoThink"); //Run DoThink on every timer tick
thinkTimer.__KeyValueFromFloat("RefireTime", 0.1); //set the frequency of the timer. You get RefireTime when disabling smartedit in hammer.
EntFireByHandle(thinkTimer, "Enable", "", 0, null, null); //finally, start the timer
}
}
}
}


//Think function the timer will run
function Think()
{
print("Tick - ");
}
</source>
</source>
 
|}
{{todo}}


==See also==
==See also==
*[[List of Counter-Strike: Global Offensive Script Functions]]
* [[logic_script]]
*[[Logic_script|logic_script]]
* [[VScript]]
*[[VScript|vscript]]
* [[VScript Fundamentals]]
* {{sq}} [[Squirrel]]
* [[List of Counter-Strike: Global Offensive Script Functions|List of CS:GO Script Functions]]


==External links==
==External links==
* [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://www.squirrel-lang.org/doc/squirrel2.html Squirrel Reference Manual]
[[Category:Counter-Strike:_Global_Offensive]]
{{Csgo topicon}}
[[Category:VScript examples]]
[[Category:Scripting]]
[[Category:Scripting]]

Latest revision as of 08:32, 27 February 2025

English (en)Русский (ru)中文 (zh)Translate (Translate)
Icon-delisted.png
This page documents information about a game or software, Counter-Strike: Global Offensive Counter-Strike: Global Offensive, that is no longer available for purchase or download digitally.
It is covered here for historical and technical reference.

Counter-Strike: Global Offensive The following are example VScripts for Counter-Strike: Global Offensive.

Find the closest player to a known entity

// find an entity named "button_01" and store its handle (or null if not found)
button <- Entities.FindByName( null, "button_01" )
	
// find the nearest player within 512 hammer units to the button's origin and store their handle (or null if not found)
player <- Entities.FindByClassnameNearest( "player", button.GetOrigin(), 512 )

Functions to distinguish bots and human players

To test players other than the activator, give the functions a parameter that replaces activator.

Warning.pngWarning:Giving bots a targetname will turn them into a player, making the cs_bot loop fail.
// returns true if the activator is a bot
function IsBot()
{
	if (!activator) return false
	
	local ent = null
	while ( ent = Entities.FindByClassname(ent, "cs_bot") )
	{
		if (ent == activator) return true
	}
	return false
}
// returns true if the activator is a human player
function IsHuman()
{
	if (!activator) return false
	
	local ent = null
	while ( ent = Entities.FindByClassname(ent, "player") )
	{
		if (ent == activator) return true
	}
	return false
}
// returns true if the activator is a human player or a bot
function IsPlayer()
{
	// both bots and human players have the classname "player" in this case
	return activator && activator.GetClassname() == "player"
}
Note.pngNote:If you need to avoid any exceptions, you might also want to check typeof(activator) == "instance" && activator.IsValid() before calling activator.GetClassname().

Equip players

A slightly modified version from csgo/scripts/vscripts/warmup/warmup_arena.nut.

// equips the specified players with the specified weapon class
function GiveGun( weapon, playerarray )
{
	local equipper = Entities.CreateByClassname( "game_player_equip" )

	// set flags and keyvalues
	equipper.__KeyValueFromInt( "spawnflags", 5 ) // "Use Only" and "Only Strip Same Weapon Type"
	equipper.__KeyValueFromInt( weapon, 0 )
//	equipper.__KeyValueFromInt( "weapon_knife", 0 )
//	equipper.__KeyValueFromInt( "item_kevlar", 0 )

	equipper.ValidateScriptScope()

	foreach (player in playerarray)
	{
		EntFireByHandle( equipper, "Use", "", 0, player, null ) // each player "Use"s the equipper
	}
	
	EntFireByHandle( equipper, "Kill", "", 0.1, null, null ) // equipper is no longer needed, so remove it
}

Iterating over all hostages

On hostage scenario maps, it is up to the mapper whether to use hostage_entity or info_hostage_spawn for their hostages. In VScript, using the function Entities.FindByClassname(handle, classname) to iterate over all hostages requires two loops because both classnames must be searched for using that function. However, no matter how the handle of a hostage hostage was obtained, the following applies: hostage.GetClassname() == "hostage_entity". Using this fact, an iteration over all hostages can be done as seen in the following. In this example, a global function IsAnyHostageBeingCarried is defined that returns true whenever there is a CT carrying a hostage.

Note.pngNote:A similar inconsistency exists with player and cs_bot; Each entity handle of both classnames yield ent.GetClassname() == "player". There may be more.
::IsAnyHostageBeingCarried <- function()
{
	for (local hostage = Entities.First(); hostage = Entities.Next(hostage); )
	{
		if (hostage.GetClassname() == "hostage_entity")
		{
			if (hostage.IsBeingCarried())
				return true
		}
	}
	return false
}

Turn decoys into nukes

The following script is a think script, it can be attached to any entity. The Think function will be executed as long as the entity is alive and has its thinkfunction keyvalue set to "Think".

// This can be found in hammer's sound picker
const EXPLOSION_SOUND = "c4.Explode"

// Called after the entity is spawned
function Precache()
{
	self.PrecacheScriptSound( EXPLOSION_SOUND )
}

// Every 0.1 seconds this function checks for decoy_projectiles in the map
// When found, it checks if the decoy is standing still
// If true create an env_explosion, trigger it and kill the decoy

function Think()
{
	local decoy = null
	while( ( decoy = Entities.FindByClassname( decoy, "decoy_projectile" ) ) != null )
	{		
		if( decoy.GetVelocity().LengthSqr() == 0 )
		{
			local owner = decoy.GetOwner()
			local origin = decoy.GetOrigin()

			local explosion = Entities.CreateByClassname( "env_explosion" )
			explosion.__KeyValueFromInt( "iMagnitude", 2000 )
			explosion.SetOrigin( origin )
			explosion.SetOwner( owner )	

			EntFireByHandle( explosion, "Explode", "", 0.1, owner, owner )
			DispatchParticleEffect( "explosion_c4_500", origin, origin )

			decoy.EmitSound( EXPLOSION_SOUND )
			decoy.Destroy()
		}		
	}
}

Create a timer to call a function independently

timer <- null

function OnTimer() 
{
	print(".")
}

// Called after the entity is spawned
function OnPostSpawn()
{
	if( timer == null )
	{
		timer = Entities.CreateByClassname( "logic_timer" )

		// set refire time
		timer.__KeyValueFromFloat( "RefireTime", 0.1 )

		timer.ValidateScriptScope()
		local scope = timer.GetScriptScope()
		
		// add a reference to the function
		scope.OnTimer <- OnTimer

		// connect the OnTimer output,
		// every time the timer fires the output, the function is executed
		timer.ConnectOutput( "OnTimer", "OnTimer" )

		// start the timer
		EntFireByHandle( timer, "Enable", "", 0, null, null )
	}
}

See also

External links