Source Engine: CS:GO and game_text

January 12, 2017

Update 19/03/2017: After a CS:GO update yesterday, and some research on my part, gametext now has basic functionality, including multiline, which I proved possible here: [Reddit: gametext works for CS:GO, including multiline](

I will add a comprehensive breakdown of the new entity and what works and doesn’t work at a later date.


If you have never worked with any source engine game besides CS:GO (not unreasonable), then this may come as a suprise to you. Anyway, today I’m here to talk about game_text, largely in context of porting older maps that utilise it extensively.

As I’m sure you’re aware, the SDK (Hammer) includes an entity named game_text. A quick look at the entity keyvalues (or the sparse SDK wiki) should immediately explain what this entity is meant to do. In games prior to CS:GO, it simply draws some predefined text to screen, at x/y co-ordinates of your choice, in a colour you choose for a set duration. You’ll also notice that in CS:GO, it simply does not work. That’s just swell..

Fortunately, the advent of Left 4 Dead has brought us a usable, but unsuitable replacement in env_instructor_hint. This entity displays text with an icon at a location in the world, OR on a players screen. Sounds familiar? Good, because its the best replacement we have when porting game_text usage CS:GO.



There are 2 fatal issues with using envinstructorhint as a replacement for game_text:

  • Gametext supports “channels”, or multiple texts at once. envinstructor_hint does not.
  • You can’t read just any keyvalue from an entity. This is a real problem, because you can’t get the current message that a game_text is using. There is a solution to this, which I will explain below


Single channel support only, whilst being a real bummer, can be worked around with some consideration. The most effective way would be attaching a VScript that combines the values of all active gametexts into a single string to be displayed. e.g. 2 gametexts that read “Hold the doorway”, and “0m 17s” (aka. an instruction with a countdown) could be combined with some clever scripting into a single string: “Hold the doorway - 0m 17s remaining”.

The second problem, involving reading the current message can be solved in several ways, but first a small amount of background. Most common uses of game_text involve the following logic:

OnX game_text:AddOutput:message <message_text>:0:-1
OnX game_text:Display:0:0.01:-1

Basically, we force a new text into game_text then immediately afterwards call a redisplay. This is useful for timers as representing minutes in seconds would take a large number of entities otherwise. By considering this issue, there are 2 viable solutions I came up with, both involving VScript. The first is much easier, but a little less “cool”. We have a VScript will all the possible strings we want to display, and set the current string using an index we pass using the RunScriptFunction output.

sample lookup vscript

The latter option we can do involves exploiting Source’s lack of proper entity checks. I mentioned above that we cannot read gametext’s message keyvalue. But, VScript has the function getModelName(), which just so happens to simply return the value of the model keyvalue. No checks performed. So how do we use this? Well, instead of AddOutputting a message keyvalue, we output a model keyvalue: `OnX gametext:AddOutput:model <message_text>:0:-1`

From VScript we can actually read that text right in into script, with no negative effects (except a few extra bytes in the entdata shared between the clients/server). This is particularly useful for porting older maps to cs:go, because it means no redesigning of systems, you just repoint (or duplicate) addoutputs from message to model, and add a script in.


Ultimately Valve/Hidden Path have to fix their issues if they want creativity for CS:GO the likes of which earlier Source games could manage. VScript is great, but pleasant additions and bitter subtractions can’t help but leave a sour taste. In the meantime though, with a little creative thought, many problems can be worked around, and most importantly, avoided entirely for entirely original content. It’s those who wish to update, improve and revitalise their or others abandoned content that must suffer the most.