The VScript Book

Chapter 2.4: Running Code with Entity I/O

Your scripts don't have to just run once. You can trigger code to run at any time using the game's built-in Input/Output (I/O) system.

All entities have these special VScript Inputs:

  • CallScriptFunction: Looks for a function by name within the entity's script and runs it. Best for calling pre-defined functions without arguments.
  • RunScriptCode: Executes its parameter as a single line of Squirrel code. Best for simple commands or for calling functions that need arguments.

Example

Imagine a button (func_button) and a door (prop_dynamic). The door has a script attached to it called door_logic.nut.

door_logic.nut:

// Define a function inside the door's script scope.
function OpenTheDoor() {
    printl("The OpenTheDoor function was called!")
    EntFireByHandle(self, "Open", "", 0, null, null) // An example of what you might do.
}

function OpenTheDoorDelay(delay) {
    EntFireByHandle(self, "Open", "", delay, null, null) 
}

In Hammer, you would create an output on the button's OnPressed event. You have two options:

  1. Target the door and use the input CallScriptFunction with a parameter of OpenTheDoor. This is clean and simple.
  2. Target the door and use the input RunScriptCode with a parameter of OpenTheDoorDelay(3). This allows you to pass data directly into a function.

When the player presses the button, the corresponding function in your script runs.


The Actors: self, activator, and caller

When code is run via the I/O system, VScript provides special variables that tell you *who* is involved in the action.

  • self: The entity whose script is currently running. In the example above, `self` is the door.
  • activator: The entity that initiated the entire chain of events. This is most often the player.
  • caller: The entity that fired the *specific input* that triggered your script.

Visualizing the Chain

Imagine this setup: A player presses a **button**. The button's output targets a **trigger**. The trigger's output targets a **door**, which has a script on it.

(The one who started it all)
[Player]
activator
▼ Fires output to
[Button]
▼ Fires output to
(The one who fired the input)
[Trigger]
caller
▼ Fires output to
(The one executing the code)
[Door w/ Script]
self
(script context)
// Inside the door's script function
function AnalyzeSignal() {
    printl("I am the door: " + self.GetName()) // self is the door
    printl("The signal came from: " + caller.GetClassname()) // caller is the trigger
    printl("This was all started by: " + activator.GetClassname()) // activator is the player
}

Understanding this chain is vital for creating logic that correctly identifies who or what is interacting with your scripted entities.