Thinking
An entity's Think() function is the root gateway for processing without external input. Some entities (such as CAI_BaseNPC
) think automatically when they are spawned, but others need prompting first.
This article describes all of the functions that play a part in thinking.
Creating a think function
A new think function:
- Must be
void
- Must be added to the entity's DATADESC with
DEFINE_THINKFUNC
- Should probably make a call to
SetNextThink()
Otherwise it is like any other function.

Think()
itself should include a call to BaseClass::Think()
, or you may find that SetThink()
breaks.SetNextThink()
- Defines when the entity next automatically thinks.
- Accepts a floating point value.
- New values override old.
void CMyEntity::Think() { Msg( "I think, therefore I am.\n" ); SetNextThink( gpGlobals->curtime + 1 ); // Think again in 1 second BaseClass::Think(); }
This code causes the entity to print a message to the console once per second. Note the use of gpGlobals->curtime
to make the NextThink time relative to now.

SetNextThink(0)
or SetNextThink(null)
will pause automatic thinking.
SetThink()
- Changes the active automatic think function
- Accepts a function pointer: add
&
in front and omit the parentheses. - New values override old.
void CMyEntity::Think() { Msg( "I think, therefore I am.\n" ); SetThink( &CMyEntity::Think2 ); // Think with this function next SetNextThink( gpGlobals->curtime + 1 ); BaseClass::Think(); } void CMyEntity::Think2() { Msg( "Variety is the spice of life.\n" ); SetThink( &CMyEntity::Think ); // Think with this function next SetNextThink( gpGlobals->curtime + 1 ); }
This code switches thinking between two functions. A real-world application is to change an entity between various life stages: consider a buildable gun turret. One think function would run while it waits to be unpackaged, another while it is being built, another while it is active, and a fourth when it dies. Creating think functions for each discrete stage increases code stability and aids debugging.
SetContextThink()
Fires a think function once, at a defined time. The third parameter is a "context", a string value that seems to be used to group multiple thinkfuncs under a given heading.
CAI_ActBusyQueueGoal
provides good examples, such as:
void CAI_ActBusyQueueGoal::MoveQueueUp() { // Find the node the NPC has arrived at, and tell the guy behind him to move forward if ( GetNextThink( QUEUE_MOVEUP_THINK_CONTEXT ) < gpGlobals->curtime ) { float flTime = gpGlobals->curtime + RandomFloat( 0.3, 0.5 ); SetContextThink( &CAI_ActBusyQueueGoal::MoveQueueUpThink, flTime, QUEUE_MOVEUP_THINK_CONTEXT ); } }
GetLastThink()
A utility function that returns the time of the entity’s last think as a float.
float dt = gpGlobals->curtime - GetLastThink(); SetAltitude( m_flAltitude + m_flBarnaclePullSpeed * dt ); // Change tongue altitude
This real-world think code for npc_barnacle modulates the speed of tongue movement, even if the frequency of thinking changes. dt
is short for “delta time”.

There are also:
float GetNextThink()
int GetNextThinkTick()
int GetLastThinkTick()
ClientThink()
Thinking can also occur on the client, but its effects are limited. Additionally, only one think function is supported for each entity.
void C_MyEntity::ClientThink() { Msg( "Don't put anything expensive in this function!\n" ); SetNextClientThink( CLIENT_THINK_ALWAYS ); // Think every frame }
Some examples of client-side thinking are:
- Visual effects / particles
- VGUI screen interaction
- Modifying player speed (calculated on the client as well as server to avoid lag)
- Striders’ legs snapping ropes (disabled by default)
SetNextClientThink()
Used to re-fire ClientThink()
. In addition to normal float values, it accepts:
- CLIENT_THINK_ALWAYS
- Think on the client once every frame. Use with caution!
- CLIENT_THINK_NEVER
- Pause all automated client thinking.