Contagion

Contagion

Not enough ratings
Basic VScript guide
By Rectus
This guide aims to demonstrate how to write simple VScripts for Contagion.
   
Award
Favorite
Favorited
Unfavorite
Introduction
VScripts are server-side scripts giving level designers access to various game functions. In Contagion, VScripts are written in the Squirrel programming language, and are used among other things, to control spawning of zombies and items, as well as sending objectives to the players cellphones.


Resources

Tutorial map download
[www.dropbox.com]
Creating and running scripts
VScripts are created using normal text files with the file extension .nut. For the game to find them, they are placed in the directory Steam\SteamApps\common\Contagion\contagion\scripts\vscripts, and scripts\vscripts when packerd in the add-on VPK.


In this example, our VScript is called example_script.nut.

We start by creating a new text file, and changing the file extention to .nut. Make sure to have file extensions enabled in explorer. Then we add this simple code to our example script using our favorite text editor.
// Prints a message to the developer console. "\n" is used to send a newline. Msg("\nHello world!\n\n");

Running the script
In Hammer, we add a logic_script entity to the map. This entity serves as a container for the VScript, and allows map entities to communicate with it.

In the entity properties, we add the script file name (without extension) to the VScripts keyvalue.



When we run the map, the script will automatically execute when the logic_script entity spawns, and print a Hello World message to the console.




Note that the message is printed before players have had time to load in or even spawn. For sending objectives to the players and spawning zombies, we will need a way to choose when to run the code.
Calling functions
To control when we run our code, we need to create functions, and then call them from the map when needed.

A function is made with the function keyword, followed by the function name, and a pair of parantheses with an optonal set of parameters between. Any code inside the function is wrapped between a pair of curly braces.

We make a function to be run after we load the map, and put it in the end of our script:
function InitializeMap() { // Sends an obective message to the players phones. ThePresident.SendObjective("Welcome to the tutorial."); // Sets the starting weapons for the survivors. ThePresident.SetSpawnWeapon(0, "weapon_ar15", 30, 30); ThePresident.SetSpawnWeapon(1, "machete", 0, 0); }


In the map, we create a logic_auto entity, an add an output to to our logic_script to run the function when them OnMapSpawn output fires.


After we compile and run the map, the function gets called by the logic_auto, and gives us some starting weapons, as well as a phone message.


Next, we'll naturally want some zombies to test our weapons on, so lets create a button for spawning them.

First we add a new function to our script:
function SpawnZombies() { // Spawns zombies even if there arean't any good out-of-view places to spawn them. ThePresident.CreateZombiesForced(3); // Sends a new message to the phone. ThePresident.SendObjective("Defend yourself!"); }

To call the function, we create a button out of brushes, and make it a func_button entity.



Now every time we press the button, we will have three zombes spawn in (make sure to have created a navigation mesh for your map, or the zombie will not spawn).
Objectives
In the Escape and Extraction game modes, we will need to create objectives for the survivors. Most of the work can be done either with normal entity logic in hammer, or with VScripts. However, we need to use a VScript to spawn zombies and sending messages to the survivors phones.

Messages
Phone messages are sent using two of the methods of The President: ThePresident.SendObjective(text) and ThePresident.SendObjectiveWithTarget(text, x, y ,z)

SendObjective takes a text string, and displays it on the phones as a message. SendObjectiveWithTarget also marks a position on the Extraction map, set by the x, y and z coordianates, as well as showing the distance to the position in other game modes.

We can also find the character name of the player closest to an entity, using the GetNearestPlayerName(entityName) function, allowing for more personalized messages. If we create a button like in the previous section, but give it the name mysterious_button and make it run the MysteriousButtonPressed() function, this code can be used to send a message with the button activators name.



function MysteriousButtonPressed() { // Finds the character name of the nearest player. local playerName = GetNearestPlayerName("mysterious_button"); ThePresident.SendObjective(playerName + ": Hi, I pressed this weird button."); }

Entity interaction
To get our button to do anything we have a few options, we can send outputs from it directly, but we can also do it from within the VScript, using the DoEntFire() function. The function allows us to fire an entity output the same way it's done in Hammer.

Lets make out mystery button open a metal shutter. For that we need two entities, a prop_dynamic with the shutter model, and a invisible func_door. We name the prop shutter_prop and the door shutter_door.





We then add entity outputs for opening the door and triggering the prop animation to our function:
function MysteriousButtonPressed() { // Finds the character name of the nearest player. local playerName = GetNearestPlayerName("mysterious_button"); ThePresident.SendObjective(playerName + ": Hi, I pressed this weird button."); // Calls entity inputs // Arguments: <entity name>, <input>, <parameter override>, <delay>, <caller>, <activator> DoEntFire("shutter_prop", "SetAnimation", "opening", 0, null, null); DoEntFire("shutter_door", "Open", "", 0, null, null); }
Spawning items and zombies
There are several different ways to spawn items and zombies, and they are all done through the ThePresident handle.

Default spawn items

The weapons players initially spawn with are set with the ThePresident.SetSpawnWeapon(<weapon slot number>, <weapon name>, < min random ammo>, <max random ammo>) method. The weapon slots are numbered from 0 to 3, and correspond to the four different weapons a player can carry at the same time. If the function is run multiple times with the same slot number, a weapon is randomly selected from the entries. The weapons to spawn are named the same as the corresponding entities, with the exception being the melee weapons, which are spawned without the weapon_ prefix.

Example:
// Spawns either a revolver or a 1911 in the first slot (slot 0). The weapons will have between 10 and 20 rounds of ammo. ThePresident.SetSpawnWeapon(0, "weapon_1911", 10, 20); ThePresident.SetSpawnWeapon(0, "weapon_revolver", 10, 20);

Spawning random items

Random weapons can be spawned with the ThePresident.CreateWeapon(<entity name>, <number to spawn>) method, to random info_random_weapon entities. Ammo and items can be spawn similarily with the ThePresident.CreateAmmo() and ThePresident.CreateItem() methods.

Example:
// Spawn between three to five hand grenades. ThePresident.CreateWeapon("weapon_grenade", RandomInt(3, 5)); // Spawn two boxes of 9mm ammo. ThePresident.CreateAmmo("item_ammo_9mm", 2); // Spawn one set of keys. ThePresident.CreateItem("weapon_key", 1);

Spawning zombies

There are a few methods of spawning zombies. The first one is ThePresident.CreateZombies(<amount of zombies>), that simply spawns the specified number of zombies in any valid area. To specify the spawn area, the ThePresident.CreateZombiesArea(<amount of zombies>, <spawn area name>).

These functions only spawn a set of zombies when the function is called, but continious spawning can be done as well, using the ThePresident.CreateZombiesConstant(<amount of zombies>) method. After it has been called, it will keep spawning in zombies as they are killed, so the total amount of them stays the number specified.

Example:
// Spawn two zombies anywhere. ThePresident.CreateZombies(2); // Spawn 2 to 4 zombies in the trigger_zombie_spawns named "basement_spawn area" ThePresident.CreateZombiesArea(RandomInt(2, 4), "basement_spawn area"); // Always keep 10 zombies in the map. ThePresident.CreateZombiesConstant(10);
Entity scripts
Even though the standard way to run scripts is through a logic_script entity, scripts can be run on any server-side entity. This feature is missing from the Hammer FGD file, so it is not visible in the keyvalue list by default. The keyvalues can be added manually with Smartedit turned off. The vscripts keyvalue sets the script file to use, and an optional thinkfunction keyvalue sets a function to be run every frame (0.1 seconds).

23 Comments
𓅃 スノ 𓅃 16 Feb, 2024 @ 12:59am 
I bought the game just to thumps us this guide.
Ϡ Ruza 11 May, 2016 @ 9:28am 
Alrighty ;)
Rectus  [author] 11 May, 2016 @ 9:26am 
Also, no problem. I don't mind getting asked questions. I'd suggest asking them in the Source SDK forum in the future though, there are other people that might have better ideas on how to solve issues.
Ϡ Ruza 11 May, 2016 @ 9:25am 
yup I got it foreach(object in myTable){ ... }
Thank you for your help Rectus ;)
Anyway do you mind if I add you to friends?
Rectus  [author] 11 May, 2016 @ 9:24am 
You can iterate though a table with a foreach statement:

foreach(player, time in myTable)
{
printl("Player: " + player + " time: " + time)
}
Ϡ Ruza 11 May, 2016 @ 9:22am 
I need to very thank you for showing me the table way. It looks like I reduce bunch of the code and finally it stops bugging XD :8bitheart:
And sorry if I had a lot of questions, I was just sad I could not find the help so long time ;)
Ϡ Ruza 11 May, 2016 @ 8:19am 
Could you show me how to search thru all indexes in this I guess its table example you showed me bellow?
myTable <- {}
myTable[<player_handle>] <- <time_spent_in_trigger>
:steamhappy:
Rectus  [author] 11 May, 2016 @ 7:59am 
I'm not sure if linked lists are that useful in Squirrel, since arrays and tables already have the same functionality you gain from them already built in.

If you really want a linked list, I'd recommend writing a class for it instead since Squirrel is object oriented and you can get a simpler interface out of it.

Ϡ Ruza 11 May, 2016 @ 7:38am 
Oh :(, In my opinion examples like making linked list and so on from C language in Squirrel might be pretty awesome.
By the way this is how linked list looks like:
http://www.cs.usfca.edu/~srollins/courses/cs112-f08/web/notes/linkedlists/ll2.gif
Rectus  [author] 11 May, 2016 @ 7:34am 
You can remove a player from the table with: delete myTable[<player_handle>]

I wish i could make examples for the functions, but it would be really time consuming.