SteamVR/Environments/Scripting/Linking Lua with Hammer

From Valve Developer Community
Jump to: navigation, search

This tutorial shows how to link functions in a VScript Lua script to Hammer entity logic.

Scripts Called by Map Entities

If you would like entities in your map to call script functions (such as triggers), you’ll need to create another Lua script file to your scripts\vscripts directory.

Launch Hammer from the SteamVR Workshop Tools and create a new map from File > New.

Properties for the logic_script.

Create a logic_script with the Entity Tool (light bulb icon on the tools bar). The location does not matter, but it will be easy to find if you place it near the world origin. Double click on it to open its properties:

In the Name field, call it what you want. This is what other entities on your scene will reference it as.

Warning: Do not reference addon_game_mode.lua in the map entities or your script will run multiple times. If you have map entities that call script functions, you will need to create another Lua file that is not called addon_game_mode.lua.

Arcade Toss only has arcade_toss.lua (not an addon_game_mode.lua) for simplicity purposes.

Click on the + sign next to Misc and put the name of the Lua file you want to call (you will not need the .lua extension).

Create the basic map requirements such as the floor, an info_player_start, and a light_omni.

Create a trigger_multiple (again, you can use the Turret Tutorial for instructions on creating mesh entities). Open its properties by double-clicking on it or selecting it and pressing Alt+ Enter.

In the Outputs tab, add an output named "OnStartTouch". Set the logic_script as the target. The input should be "CallScriptFunction" and the parameter should be the name of the function you want to be called.

My Output Target Entity Target Input Parameter Delay Only Once
Io11.png OnStartTouch logic_script_name CallScriptFunction MyFunction 0.00 No

In your Lua file referenced by your logic_script, add a simple function to print a message in the console:

function MyFunction()
	print("Trigger has been activated")

Compile the map and you should now be able to walk into the trigger_multiple in the game and see the message printed in the console.

Example 1

Using the outliner to find entities in Hammer.

There’s a trigger_multiple that detects if a player has crossed the line to throw balls into the targets. It’s called “red_team_check”.

You can find it in the outliner in Hammer by typing “red_team_check” in the filter field:

The Outputs of the trigger_multiple.

If you double click on it and click on the Outputs tab, you can see it references the logic_script and uses CallScriptFunction with a parameter override of the name of the function you want to call in the Lua file.

You will then need to create a function in the Lua script that matches the one you are calling in the Entity I/O:

--Red Team
function RedTeamCheckStartTouch()
	--A player is over the line on the Red Team side
	red_team_counter = red_team_counter + 1

function RedTeamCheckEndTouch()
	red_team_counter = red_team_counter - 1

To create a function, you'll need to follow this same syntax with function MyFunction() and end to close it.

Tip:Two dash marks -- will tell Lua to ignore that line of text. This will comment out a line. This helps to organize your script so you can remember what each part does and will help other people see how you did it. You can also divide your script into different sections with comments as seen above.

In this example, there’s an integer variable in the script called red_team_counter and it starts at 0.

-- Global Variables
local red_team_counter = 0 -- Players behind the Red Team Line
local blue_team_counter = 0 -- Players behind the Blue Team Line

When a player touches the trigger, the number increases by 1. When a player is no longer touching the trigger, the number decreases by 1.

The think function shown in the Lua Scripting Intro checks every second if the counter is higher than 0. If so, no points are awarded and there’s a message displayed on the board.

This chunk in the Think function in Arcade Toss checks if any player is over the line:

	if red_team_counter > 0 then
    	print("Red Team is over the line!")

These functions are called if a player is over the line or if all players are in legal positions:

function RedTeamOverTheLine()
	bIsRedTeamBehindTheLine = false
	--Panel popup for notification
	DoEntFire( "red_team_check_panel", "AddCSSClass", "Activated", 0, self, self  )

function RedTeamBehindTheLine()
	bIsRedTeamBehindTheLine = true
	DoEntFire( "red_team_check_panel", "RemoveCSSClass", "Activated", 0, self, self  )

Example 2

The trigger_multiple for the green hole on the Team Blue side.

There's a trigger_multiple in each of the target holes for the balls to make contact with to tell the script when the player has scored.

Open the trigger_multiple in the green target hole on the Team Blue side (named “blue_team_hole_1”). Find this trigger in Hammer and double click on it or select it and press Alt+ Enter.

Expanding spawnflags.

Each of the fields that have a + mark beside it can be expanded:

The filter_activator_name.

It is set to trigger when Physics Objects touch it. It also has a filter (filter_activator_name) that says it will only trigger when an object named “blue_ball” touches it.

This is what the filter_activator_name looks like:

This tells it that it will only activate when a physics object named “blue_ball” collides with it.

The trigger_multiple's outputs.

The output of the trigger_multiple calls the CallScriptFunction in the logic_script file and in the parameter is the name of the function you want to call in the Lua script.

My Output Target Entity Target Input Parameter Delay Only Once
Io11.png OnStartTouch arcade_toss_script CallScriptFunction BlueHoopRow1 0.00 No

In the Lua file, you wil need to create any function you call in the entity logic. In this example, you’ll need to create a function called BlueHoopRow1.

Note: You don’t need to include the () in the Hammer I/O, just in the Lua function.

function BlueHoopRow1(trigger)
	--Calls another function for scoring with the parameters for the team and the number of points
	UpdateScoreboard(2, 5)
	--Specifies which info_particle_system to start for the scoring effects
	local hoop = "blue_trigger_bot_particle"
	HoopEffects(hoop, 2)

Spawning Entities

The settings icon in the prop_physics_override properties.

Many times you will need to spawn entities into the world.

For example, in Arcade Toss, the Think function checks every second to see how many red balls exist. If there are less than 4, it will spawn more unless red balls exist in the spawner locations.

See the BallReplenish function in the Arcade Toss script.

To spawn an object, you will need to create a table that contains the Raw Data for the entity you wish to spawn. To make this easier, you can place one of the entities you want to spawn in Hammer and then open its properties.

Click on the settings icon to view the Raw Data.

Raw Data enabled.

This is the properties box with Raw Data enabled:

From this, we know what to call the keys in the table:

function RedBallLeftSpawner()
	--print("Spawning a Red Ball")
	local ballTable = 
		origin = "224 128 24",
		targetname = "red_ball",
		model = "models/props_gameplay/red_ball001.vmdl"
	ballTable["spawnflags#6"] = "1"
	local redBall = SpawnEntityFromTableSynchronous( "prop_physics_override", ballTable )
	redBall:Attribute_SetIntValue( "objectID", 1 )
	EmitSoundOn( "ball_spawn", redBall )

You don’t need to include the keys and values for the default properties.

Note: For the prop_physics_override entity used in the example above, a change in the spawnflags was required. Because of Lua’s scripting syntax, the # symbol could not be read except as an insert later. To change a spawnflag, you will need to have a similar method with “1” being checked on and “0” being checked off.

Precaching Resources

If you spawn an entity that does not exist in your Hammer map, you will need to precache the resources. For example, spawning the red and blue balls in Arcade Toss needed this code in the arcade_toss.lua file:

function Precache( context )
	PrecacheModel( "models/props_gameplay/red_ball001.vmdl", context )
	PrecacheModel( "models/props_gameplay/blue_ball001.vmdl", context )

Other resources can be precached with these functions:

Function Signature Description
PrecacheModel ( string modelName, context ) Manually precache a single model.
PrecacheModelFolder ( string folderName, context ) Recursively precache models within a folder.
PrecacheParticle ( string particleName, context ) Manually precache a single particle.
PrecacheParticleFolder ( string folderName, context ) Recursively precache particles within a folder
PrecacheSoundFile ( string soundFileName, context ) Manually precache a single sound file