An Introduction to VScripts - Part 1

A Tutorial for Source Engine

Members see zero ads. Signup for free

“ A well presented/structured and in depth explained tutorial covering Vscripts and their usage to script and code/modify various aspects of the Source Engine. It is also the best presented tutorial across all categories. The writing and flow are smooth and allow for easy following even for the folks that aren't very familiar with coding/scripting. This tutorial has great potential since it allows the creation of new gamemodes in the Source engine, at the discretion of the mapper without the need for third party software code. ”

A (not so) brief introduction to the powerful tool that is VScripts



VScripts are wonderful things. You've probably already heard of, or even played, one of the many custom gamemodes that exist for the Source engine - assassination, gungame, free-for-all, you name it. All of those gamemodes currently require a server-side modification such as SourceMod to function properly, giving very little control to the mapper. All this changes with VScripts though.



But what is a VScript, you may ask? Well, to put it shortly, a VScript is a small piece of code that is directly implemented into your map, effectively acting as a bridge between your map entities and the inner workings of the game. This can be incredibly powerful, and allows you to do many things that have been impossible earlier.

To go into a bit more detail, VScripts are written in a language called Squirrel. It's a fairly simple language with many of the same dynamic mechanics as Lua, while keeping a traditional syntax akin to that of C++ or Java. VScripts have been used extensively for L4D2, where it allows mappers to interact with the director (the part of the code that handles spawning of zombies), but they are available in all recent Source games (which currently only covers L4D2, Nuclear Dawn, Alien Swarm, Portal 2 and CS:GO).

The unique thing about VScripts is that it exists entirely inside your .bsp. This means that you, the mapper, is given full control over what you want the VScripts to do, instead of having to rely on SourceMod plugins (that may not even be present when a user plays the map), and that no one can mess around with it after you're done. This also means that you'll be able to do all new things, however minor (or major), that would not previously be possible - we'll be starting off by creating (and implementing) one of those scripts.

Unfortunately for us, the documentation is close to non-existant for VScripts, and nothing but a simple function list and a number of Valve's own scripts exist. This tutorial will therefore mainly reference existing L4D2 scripts, as well as guide you through the creation of a free-for-all gamemode using VScripts. With that said, let's begin!



I'll be splitting this tutorial up in two sections - the mapping side, which is everything that's going on inside your .VMF, and the coding side, which is the actual .nut script. These two will obviously merge together somewhere down the line, but for now, we'll be focusing on scripting.

First thing we need to do is figure out what we want to do, though! Since this tutorial will be focusing on the power of VScripts, specifically how it can be used to replace SourceMod for gamemodes, why don't we try recreating an existing gamemode - such as hide 'n' seek (or prophunt, if you wish to call it that). For anyone who doesn't know, hide 'n' seek consists of two teams, the props and the seekers. The props (the terrorists) are transformed into a random prop, and are then given a set amount of time to hide. After this amount of time, the seekers (the counter-terrorists) are sent out to find them. Fairly simple stuff, but, given a simple map without vscripts, it requires SourceMod to transform players into models. We'll do something about that!

So, open up your favourite text editor (you may use Notepad if you so wish. It's as good as anything. All it lacks is syntax highlighting), and create a completely empty file. This file will be our script file, and will be where we write all of our code. Save the file (remember to switch the type to "All files", and name it with .nut at the end. This'll make it a .nut file, which will be read as a Squirrel script by CS:GO) - where you do so doesn't really matter, but I'd suggest using the same directory that all the official scripts are located in: Steam\SteamApps\common\Counter-Strike Global Offensive\csgo\scripts\vscripts. Alright, setup is out of the way! Before we start getting into our 1337 hax0ring, we should do a little planning to understand exactly what we need the script to do. We'll be making a small list of those that we can then tick off once we're done:

- On round start, transform all players on T into a random prop.

Well, that doesn't sound too bad, does it? I mean, it's only one thing. Stripping weapons, locking CTs in place, all of that stuff can be handled completely through the map with a little entity work (which this tutorial won't cover). Guess there isn't much to say, other than let's get started!

This tutorial will assume that you have none, or barely any, prior programming experience, and will be explaining some of the fundamentals of programming. Since it's a simple tutorial, however, it won't be as in-depth as I'd like to, and you might therefore need to google a few things providing my explanation is not enough - which it likely won't be. The first thing I'll be introducing you to is this wonderful thing called "functions". You see, programming is kind of special in that it's very definitive. The thing you write is _exactly_ what happens - the computer is never wrong and all that jazz. However, this also means that you can't just write down what you'd expect to say to, for instance, another human being. If you want to find all players on the terrorist team, you can't just write "Computer, please find all terrorists" - it'd have no idea what to do! Hell, it doesn't even know what a terrorist is, much less where to look for one. Instead, you have to break down what you want into small steps.

In this example, you could search through every player with a certain model (the terrorist model), and put them into a list. But that takes quite a few lines of code, which might just bloat up your script if you have to do it multiple times. And this is where functions come in. You see, the best way to describe functions is to say that they are small collections of code, that can be called a simple name. In this instance, you might create a function that's called "findTerrorists", and all it does is find every player with the terrorist model, and puts them into a list. Every time you want to update this list, all you'd have to do is say "Computer, findTerrorists", and this code would be run! Saves a ton of repetitive code, and works great for what we'll be doing next.
You see, what we want to do now is create a function that's called every single round. For now, all we'll need is for this function to write "A new round has just started!" to console - you know, just to check that it works. In order to do that, we'll use the following code:

function startRound() {
printl("A new round has just started!");
}

Three lines long. Let's break it down.

function startRound() {

This is our very first line, and is where we tell the computer that what is to follow is a function. We do this using a very specific syntax. First word on the line is "function". This tells the computer that what is to follow is exactly that, a function. Next word is where we actually tell the computer something specific to this function - its name. The word directly following "function" is the name of it, and is what its referred to as in the code. You can think of it as naming an entity. Quite simple stuff.

Now, something you might have noticed that might have struck you as a little odd is the two parantheses at the end of this name. All functions have those. They're sometimes used to allow values from outside the function to be passed to the code inside the function, but right now they're empty. All it really does is point out how the name is a function - not a variable (which we'll cover later). The most important thing is what's next; the curly brackets. These curly brackets define the _start_ and the _end_ of the function. Everything between these two curly brackets is the code that's run when the function is called. In short, the syntax for creating a function is "function (< optional values\>) { }".

printl("A new round has just started!");

Is some of this code. This code is fairly simple too. Remember how I told you that parantheses were used to pass on values from outside a function to the code inside - and to point out that what we were talking about actually was a function? Well, the sharp ones of you will notice that what we have here is a function, called "printl". What you see here is how you "call" a function - how you ask the computer to run the code inside it. You write the name of the function, followed closely by a parantheses and - in this case - a value to pass on to it. Printl just so happens to be one of the default functions, a function that can be called from anywhere, and all it does is write whatever value you pass on to it to the console. In this case, what we passed on is "A new round has just started!". The quotation marks are very important (!), in that they tell the computer "this text isn't code!". Anything in between quotation marks is read as what is know as a string - a piece of text that is just that - text. Another important thing is the semi-colon at the end. All lines of code that should not continue onto the next line _need_ to have this at the end. It makes it a lot easier to debug, and many languages (including Squirrel) have not made it required. If you forget this, the computer will throw a nasty error at you.

}

This is simply the closing curly bracket for the function, meaning that the function ends here. Anything after this point is not part of the function, and should not be run when the function is called.

Simply by reading through this 3 lines long example, you'll notice that nothing in programming is random. Everything you write has its own meaning, down to the smallest symbol, and writing the wrong symbol (or forgetting to write one all together) can make your code crash the game (so be careful about that). There should be no problem with this code, though, so let's get to the mapping part (where we'll implement it).



Grab the map you wish to use for this experiment, and add in two new entities - a logic\_auto (assuming you do not already have one), and our most important entity - the logic\_script. You should already be familiar with the logic\_auto entity, but the logic\_script entity should be all new to you. Although VScripts can be run from almost any entity, the logic\_script entity is the _main_ entity. It allows for a variety of different inputs, all somehow talking with, or loading, the script specified. The entity has three different KeyValues (that we need to actually edit - the EntityGroups are none of our business as of yet) - name, entity script and script think function. The name is fairly self explanatory; it's the name that other entities refer to it by, just like it is with any other entity (please do set this, as we'll be controlling the script through inputs). The interesting part is the two next KeyValues.

First off, our entity script file. This is the .nut file that we just created above. If you followed my instructions, it'll be saved in "Steam\SteamApps\common\Counter-Strike Global Offensive\csgo\scripts\vscripts" - I saved mine as "hns.nut". Clicking the "Manage..." button will pop up a list of all the script files you've added. It should be empty, since you haven't added any yet - which you'll do by clicking the "+" button. Hit it, navigate to your .nut file, and open it. This'll add it to the list. Click its entry in the list (highlighting it. Forgetting to do so will leave the entity script keyvalue empty when clicking ok), and hit "Ok". You should now see the name of the file in the entity script key value. For now, that's all we really need to do when it comes to the logic\_script entity.

Onto the logic\_auto it is then! For those of you that haven't figured it out yet, this is the entity that we'll use to run the function we just wrote at the very start of each round. Disable the "Remove on fire" flag, and jump into the "Outputs" tab. Create a new output, set output name to "OnMultiNewRound" and set the target to our logic\_script entity. The input should be "RunScriptCode". What this input does is, it runs a single line of code exactly as if it was written inside the .nut file. Due to a bug in Hammer, using quotation marks will corrupt the VMF, but if that wasn't the case, we could simply write "printl("A new round has just started!")" and be done with it. We can't, though, so we'll have to call our own function (startRound()) instead.

Remember how we called the "printl" function by typing "printl()"? We'll do exactly the same in order to call the startRound function (except without the string). Therefore, set the parameter override to "startRound()". This tells the computer to "find the function named startRound, and run it". That's really all there is to it! Compile the map and run it. I did, and guess what - the simple message "A new round has just started!" appeared in my console. Great!

What does this tell us? Well, we now know that our startRound function is being called every round start, which is great! Time to edit it so that it transforms all players on T into random props! Before we do that though, you might want to take a short break. Learning programming is tough, and even though this is pretty simple, it's made worse by the fact that I'm a terrible teacher and explaining it can take time. A 5 minute break will do wonders, trust me.



Alright! Time to explain the next programming term then! This time we've gotten to variables. Variables are fairly simple. A nice analogy would be drawers, with a tiny note pinned to the outside. You might have a drawer called "banking", in which you put all your banking papers, or you may have a drawer called "cables" where you keep whatever cables you've managed to collect over the years. Variables in programming follow much of the same principle - you have a variable with a name, that has something inside of it. By simply saying "cables", you are referring to the cables _inside_ the cables drawer. By creating a variable called "modelName" and setting it to "models/player/tm\_phoenix.mdl", you can simply say "modelName", and the computer will instantly know that you actually mean "models/player/tm\_phoenix.mdl". Hell, you can even change what's inside the drawer without changing the name of it, which can be useful in many cases.

Variables are created using the syntax "local = " - for instance "local squareOfFour = 16". The local keyword basically says "we're creating a new variable, and it can only be read from inside this script", while the name is pretty self-explanatory. The interesting part is what's behind the equal sign. Many different kinds of variables exist. What you just saw above is what's known as an integer. A whole number, such as 16, that is nothing more than that. If you want decimals (such as 16.25), you'd be working with a float, which works almost the same. Other common types of variables are strings (which we talked about earlier - it's simple text, which is always encapsuled in quotation marks, telling the computer that it's a string and not code), booleans (which are either true or false), and arrays (which are lists of variables. For instance, you can create an array of the first 5 numbers in the Fibonacci sequence by typing "local fib = [0,1,1,2,3]". Note how the list starts and ends with a square bracket, and how each seperate value is split with a comma). Another interesting thing to note is that a variable that has nothing in it, has the content of "null".

Back to our VScript we go! Your code should look something like this right now:

function startRound() {
printl("A new round has just started!");
}

What we'll be working on now is finding all players on the terrorist team, and making them into a random prop.

In order to do this, we need to have a quick look at the _function list_ of VScripts in CS:GO. This is a list of all _global functions_ - functions that are available everywhere in your code, and that you don't need to write first before using. Specifically, we want to have a look at the FindByModel() function. If you have a look, you'll see that it says this about the FindByModel() function:

CEntities::FindByModel(handle, string)

But what does this mean? Let's break it down.

CEntities::

Every function has a parent; in our case, the startRound() function has our hns.nut script as its parent. It just so happens that FindByModel has "Entities" as its parent. If we want to refer to a function that's outside our own script (such as this one is), we'll have to tell the computer exactly where to look for it. This is done using the syntax of ".", with the full stop indicating that whatever is before it is the parent of whatever is after it. Simple stuff, but quite important if we want the computer to be able to find the function (and not throw us a nasty error).

FindByModel

This is simply our function name, as we learned earlier. By now, we know that in order to find this specific function, we need to write "Entities.FindByModel()".

(handle, string)

Ah, this is where it gets interesting. What we have here is the two values that we're passing on to the FindByModel() function - a handle and a string. We already talked about strings (which is programming-ish for text), but handles is a new thing. A handle isn't as much of a variable as it's a reference to something. Variables can be incredibly advanced (for instance, we can save a whole player to a variable. This player would simply have its own sub-variables, such as velocity, model, size, etc.), but the more advanced they are, the more space they take up.

Therefore, it's often useful to simply save a new variable that says "here's where you can find what I'm referring to", instead of copying the existing variable. This is exactly what's happening here. After a bit of testing (and reading up on the Valve Developer Wiki), I found that the handle references entities. When you call the FindByModel() function, it's obvious that there may exist more than one entity with a specific model, and therefore we need a way to run through every single one of those.

Due to limitiations with the programming language, it's not possible for the function to simply say "Here's an array of all entities with this model" - it can only answer with one entity at a time. Valve have decided to work around this in a very simple way. The handle you pass on can either be null (nothing), or reference an entity. If it's null, the function simply gives you the very first entity in the array. If it's a reference to an entity, however, the function finds this entity in the array, and gives you the next one instead!

This is a rather abstract idea, so it might be better to give a practical example of it. Say we want to find every player that has the default terrorist player model (models/player/tm\_phoenix.mdl). First thing we do is ask the function to find the first entity that has this model by typing "Entities.FindByModel(null, "models/player/tm\_phoenix.mdl")". This'll give us our first player. But what now, when we also need to know the second player? Well, that's fairly simple. All we need to do is save a reference to the first player (for instance by saying "local first = Entities.FindByModel(null, "models/player/tm\_phoenix.mdl")". The computer reads the function name as the answer the function gives, and sets the variable "first" to this answer - which just so happens to be the first player). We then write "Entities.FindByModel(first, "models/player/tm\_phoenix.mdl")", telling the function to start with the first player, and take the next one in the array. How can we translate this into code?

local ply = null;

ply = Entities.FindByModel(ply, "models/player/tm_phoenix.mdl");

All we have to do is keep in calling the second line, and we'll start with the first player, and move all the way up to the last (when calling the FindByModel() function with a handle refering to the last player, we'll be given an answer of "null", since no more players exists. Calling it again with a handle of "null" will start it all over again - effectively making it loop). The programming way to write this looks like this:

local ply = null;

while (Entities.FindByModel(ply, "models/player/tm_phoenix.mdl") != null) {
ply = Entities.FindByModel(ply, "models/player/tm_phoenix.mdl");
printl("A player with the terrorist model was found!");
}

Let's break it down.

local ply = null;

By now, you should know this. It's simply creating a new variable called "ply" (short for "player"), and sets its value to null (or nothing).

while (Entities.FindByModel(ply, "models/player/tm_phoenix.mdl") != null) {

Now, this here is interesting. Let's simplify it a bit:

while () {

That makes it a lot easier to read, huh? What you see here is a while loop. As the name suggest, it's a loop - something that runs again and again. What's so special about the while loop is that it runs for as long as what's written inside the parantheses is true. When the code inside the while loop has been run, it returns to the top of the while loop again. It then checks if the conditional is still correct, in which case it runs the code again. If it's incorrect, it skips to the end of the while loop and never looks back.

How can we use this? Well, as we saw earlier, repeatedly running the FindByModel() function will take us through every single entity that has said model. When it reaches the end, it returns "null". Running the function again, with a handle of "null", starts everything all over. We don't want this to happen. Therefore, what we do is simple: we check if the answer from the FindByModel() function is null, and if it is, then we stop running the code (the "!=" comparison means "not equal to". The computer reads the conditional as "while ( is not equal to null)", meaning that the code will be run for as long as the answer is something else than null).

ply = Entities.FindByModel(ply, "models/player/tm_phoenix.mdl");
printl("A player with the terrorist model was found!");

This is fairly simple. It saves the answer from the FindByModel() function in our ply variable, meaning that the next time we call the function, it'll find the next model in the array. It then prints the text "A player with the terrorist model was found!" to console. This is the code that's run again and again, until every single player with the terrorist model has been through it. This means that the text will be printed the exact same number of times as there are players with the terrorist model. Try it out, save the following code and see for yourself! (it should be noted that the "!= null" was shortened away from the conditional - the computer reads certain things, including "null", "0" and other similar values meaning "nothing" as false, meaning that the computer still reads it the same)

function startRound() {
printl("A new round has just started!");

local ply = null;

while (Entities.FindByModel(ply, "models/player/tm_phoenix.mdl") != null) {
ply = Entities.FindByModel(ply, "models/player/tm_phoenix.mdl");
printl("A player with the terrorist model was found!");
}
}

When I did, with 5 players on each team, it wrote the following to console (with 5 players on each team):

A new round has just started!

A player with the terrorist model was found!

A player with the terrorist model was found!

A player with the terrorist model was found!

A player with the terrorist model was found!

A player with the terrorist model was found!

Success! We now know that we can do something to every terrorist player on round start! Awesome!

Let's have a look into the function list to see how we can edit the model of the player then! I did, and found this:

SetModel(string)

That looks pretty much exactly like what we need, doesn't it? So, what would we do if we wanted to turn every terrorist player into, let's say, an antenna ("models/props/de\_dust/du\_antenna\_a.mdl")?

function startRound() {
printl("A new round has just started!");

local ply = null;

while (Entities.FindByModel(ply, "models/player/tm_phoenix.mdl") != null) {
ply = Entities.FindByModel(ply, "models/player/tm_phoenix.mdl");
ply.SetModel("models/props/de_dust/du_antenna_a.mdl");
printl("A player with the terrorist model was found!");
}
}

As you can see, this simple line of code was added:

ply.SetModel("models/props/de_dust/du_antenna_a.mdl");

So, what does this do? Well, every single entity in Source has a function called "SetModel". What we do here is simply call said function of every player, with a value of "models/props/de\_dust/du\_antenna\_a.mdl". This should set the players model to the model of the antenna, which we can then later change so that it picks a model at random. Let's test it!

Oh noes! The game crashed! Dear lord, what have we done to make you hate us so much?

Taking a look at the error message the game gives us ("2/ - player: UTIL\_SetModel: not precached: models/props/de\_dust/du\_antenna\_a.mdl"), we can kind of, sort of, figure it out. How so, you may ask? Well, to answer that, we need to take a look at how the Source engine handles models. Whenever a map is loaded, Source looks through the map and finds every model that's needed. This includes player models, props in the map, any model that may be used somewhere. It reads the data for all of those models from your harddisc, and saves it in your RAM - a process known as precaching. Since RAM is many times faster than your harddisc, this means that Source is able to create new copies of this model much, much faster, which improves load time dramatically. Neat for general use, but not so great for us.

Unfortunately, no function exists to precache a model using VScripts, so we'll have to resort to getting a bit hacky. To do so, we need to open up Hammer again.



So, we know that Source precaches every model found in the map. We can abuse this slightly, by simply placing an entity (let's use prop\_dynamic for this example - it should be noted that prop\_static does not seem to work) with the same model inside our map, forcing Source to precache it! For hide 'n' seek, this shouldn't be much of a problem, seeing how all the props the player should be transformed into should already be present on the map (it'd be kind of easy to find the cs\_office crate hiding in de\_dust, for instance), but for our little example map, we need to make sure we already have every prop we use in the map somewhere. We don't want these template models to be visible to the players though, so we'll create a tiny no-draw room outside the map, in which we'll place the models in (this is to avoid the models leaking. Otherwise, we could simply place them inside the map if aesthetics were no concern, or if we were creating an actual map, where they would fit in).

You can see an example of such a room in the example map linked under the resources, or you could simply create a 64x64 room with the nodraw texture yourself, and place all models in there. Make sure that the prop\_static entity you placed has the exact model you want ("models/props/de\_dust/du\_antenna\_b.mdl" won't do, for instance, if we want to set the player model to "models/props/de\_dust/du\_antenna\_a.mdl"). Recompile the map, and try again. Guess what, it works!



That'll end part 1 of this tutorial, since it has gotten this insanely long. In part 2, which you can find here, we'll be focusing on having the script pick a random model for each terrorist, so it isn't quite that easy to find them. I hope you've learnt something, despite me being a horrible teacher.

If you need a run-down of what we learnt this tutorial:

VScripts are implemented through the logic\_script entity, which allows us to run code directly inside our map, manipulating things that would otherwise not be possible. We've created a script that's run on round start, that searchs through all entities with the default terrorist model, and sets their model to the antenna model from de_dust. This is done using functions, while loops and variables.

All resources and useful links can be found below. Have fun!



- Example map
- VDF Page on VScripts
- Nicely formatted list of L4D2 VScript functions
- CS:GO specific list of VScript functions

1-10 of 18
1
Pages
  • 1
  • 2
Go to page:
  • Xx MAHA xX avatar
    Xx MAHA xX Joined 3y ago
    Offline
    129 points Ranked 61811th
    18 medals 4 rare
    • Received thanks 50 times Medal icon
    • Thanked 50 submitters Medal icon
    • Returned 1000 times Medal icon
    • 8-14 Entries! GameBanana’s Christmas Giveaway 2017 Medal icon
    • One month a member Medal icon
    • Reached 1,000 Points Medal icon
    1y
    It is c++ language. Thanks for sharing it. Now I know how to create custom actions.
    Maha.troy98@gmail.com
    URL to post:
  • I don't understand I copied your nut file but it won't work for the while loop part, do you know what to do?
    Bananite
    URL to post:
  • 3axap avatar
    3axap Joined 2y ago
    Offline
    967 points Ranked 40724th
    2y
    Example dont work. I hoped to do this example replace hostage model. Someone can help me? Thank you.
    Bananite
    URL to post:
  • birjolaxew avatar
    birjolaxew username pic Joined 8y ago
    Offline
    4,325 points Ranked 1494th
    2 medals 1 legendary
    • 1st Place - Tutorial Contest Medal icon
    • Received thanks 5 times Medal icon
    6y
    > **Posted by GiantGiga** > [Snip] True. VScripts acts more like a more advanced way to trigger outputs than anything else. There are very few, if any, things that VScripts can do, that are not already possible in Hammer. Instead, VScripts should be thought of as an easier, more sophisticated way to create highly complicated logical systems. For instance, hide-n-seek could probably be created using purely entities too - have some team-filtered trigger\_multiple's call a logic\_case that sets the players model. However, this would be complicated, difficult to customize, and heavy on entities. With VScripts, you basically have a plug-and-play hide-n-seek system, that can easily be customized by the mapper.
    URL to post:
  • GiantGiga avatar
    GiantGiga Joined 6y ago
    Offline
    6y
    Great tutorial on vscripts. I recently found out about vscripts and this tut is great example to start with.
    I was expecting the vscripts itself to be more powerfull when it comes to customization of aspects of the game itself like changing armor to specific values. The values you can change with vscripts are usually defined variables with descriptions in the game source code and because they have this descriptions this variables can also be changed in hammer using a simple trigger_multiple for example put the trigger_multiple where terrorists spawn, give it a filter to only be activated by terrorists if you want, add an output:
    OnTrigger
    !activator
    AddOutput
    health 200
    this will give 200 hp to the player and this works cause the memory that stores the player hp has a description word that can be used by hammer in the source code is like this:
    DEFINE_KEYFIELD( m_iHealth, FIELD_INTEGER, "health" )
    same thing exists for other variables like the one that stores the model for example:
    DEFINE_GLOBAL_KEYFIELD( m_ModelName, FIELD_MODELNAME, "model" )
    the problem is not every variable that the entities got have this description word like armor for example:
    DEFINE_FIELD( m_ArmorValue, FIELD_INTEGER )
    and you can't simply use the variable name m_ArmorValue cause hammer does not recognise that and vscripts usally also has no functions to change this variables.
    In the end Vscripts is very usefull when it comes to do stuff in the map that requires some logic programing but if it's only to change some stuff like player hp or player model mappers can get away simply using my example and geting the word(if exists) for the variable they want to change so nothing new about vscripts there.
    Bananite
    URL to post:
  • birjolaxew avatar
    birjolaxew username pic Joined 8y ago
    Offline
    4,325 points Ranked 1494th
    2 medals 1 legendary
    • 1st Place - Tutorial Contest Medal icon
    • Received thanks 5 times Medal icon
    6y
    > **Posted by Fibbs** > Welp, it is just the start of the round. Might be worth testing to see if it hits performance that hard (and testing the behaviour of FindByClassname properly). Thing is, once you've changed their model and want to find them again, what do? You'll find props too. I suppose you could store the players in an array while looping through them if you wanted to reference them later. Yeah, hadn't thought about the fact that FindByClassname likely loops through all entities anyway... I haven't played around much with VScripts as of lately, but I used to save the players in arrays at the start of each round. I see your point though, and it'd definitely allow for way more customizability to simply loop through every entity. I'll test it sometime tomorrow.
    URL to post:
  • Fibbs avatar
    Fibbs username pic Joined 11y ago
    Offline
    32,089 points Ranked 140th
    24 medals 1 rare
    • 6 years a member Medal icon
    • Prefaber of the Month, June 2012 Medal icon
    • MiPper of the Month, June 2012 Medal icon
    • Prefaber of the Month, March 2013 Medal icon
    • Texturer of the Month, July 2014 Medal icon
    • Became a Studio Leader Medal icon
    6y
    > **Posted by birjolaxew** > > **Posted by Fibbs** > > > Then try looping through every entity and check that the classname is player (and their team is 1 etc). > > That's an option, of course, but I find it to be an unbalanced trade off of performance for slightly clearer code. Having to run through _every single entity on the server_ might add up to quite a lot on larger maps, and it's rare that you would need to do more than change the model searched for when implementing the script, possibly add 3-4 more models to search for, but that's it. Welp, it is just the start of the round. Might be worth testing to see if it hits performance that hard (and testing the behaviour of FindByClassname properly). Thing is, once you've changed their model and want to find them again, what do? You'll find props too. I suppose you could store the players in an array while looping through them if you wanted to reference them later.
    URL to post:
  • birjolaxew avatar
    birjolaxew username pic Joined 8y ago
    Offline
    4,325 points Ranked 1494th
    2 medals 1 legendary
    • 1st Place - Tutorial Contest Medal icon
    • Received thanks 5 times Medal icon
    6y
    > **Posted by Fibbs** > Then try looping through every entity and check that the classname is player (and their team is 1 etc). That's an option, of course, but I find it to be an unbalanced trade off of performance for slightly clearer code. Having to run through _every single entity on the server_ might add up to quite a lot on larger maps, and it's rare that you would need to do more than change the model searched for when implementing the script, possibly add 3-4 more models to search for, but that's it.
    URL to post:
  • Fibbs avatar
    Fibbs username pic Joined 11y ago
    Offline
    32,089 points Ranked 140th
    24 medals 1 rare
    • 6 years a member Medal icon
    • Prefaber of the Month, June 2012 Medal icon
    • MiPper of the Month, June 2012 Medal icon
    • Prefaber of the Month, March 2013 Medal icon
    • Texturer of the Month, July 2014 Medal icon
    • Became a Studio Leader Medal icon
    6y
    > **Posted by birjolaxew** > > **Posted by Fibbs** > > > Yeah that's what I mean, loop through all "player" entities (FindByClassname) and check if their team is the right number (GetTeam() == 1), if so change their model etc. > > In which case we'd again run into the fact that searching for the "player" classname seems to skip some players - or, bots at least. Haven't had the opportunity to test with actual players. Then try looping through every entity and check that the classname is player (and their team is 1 etc).
    URL to post:
  • birjolaxew avatar
    birjolaxew username pic Joined 8y ago
    Offline
    4,325 points Ranked 1494th
    2 medals 1 legendary
    • 1st Place - Tutorial Contest Medal icon
    • Received thanks 5 times Medal icon
    6y
    > **Posted by Fibbs** > Yeah that's what I mean, loop through all "player" entities (FindByClassname) and check if their team is the right number (GetTeam() == 1), if so change their model etc. In which case we'd again run into the fact that searching for the "player" classname seems to skip some players - or, bots at least. Haven't had the opportunity to test with actual players.
    URL to post:

Embed

Share banner
Image URL
HTML embed code
BB embed code
Markdown embed code

Credits

Author
birjolaxew
Writer
Contributors
:) :) :) :)
CS:GO function list (on SteamForums)
UNREA1
Pushed me to learn VScripts
Se7en_
Pushed me to learn VScripts

Submitter

birjolaxew avatar
birjolaxew username pic Joined 8y ago
Offline
4,325 points Ranked 1494th
2 medals 1 legendary
  • 1st Place - Tutorial Contest Medal icon
  • Received thanks 5 times Medal icon
birjolaxew avatar
birjolaxew

Creator
Sign up to access this!
Sign up to access this!
Sign up to access this!

Game

Sign up to access this!

Category

Details

Difficulty Level
Advanced

Attributes

Share

  • Share on Reddit
  • Share on Twitter
  • Share on Facebook
  • Share on Google+
  • 4
  • 16.0k
  • 18
  • 6y
  • 1y

More from Submitter

More Mapping Tutorials