De/Thinking

Think-Funktionen erlauben Entities, Code geplant später ausführen zu lassen. Durch das konstante neuplanen eines Thinks, kann eine automatisierte Schleife erzeugt werden, die die Entity autonom macht.
== Planung („Scheduling“) ==
SetNextThink() wird verwendet, um einzustellen, wann der nächste Think einer Entity ausgeführt werden soll. Es nimmt -Werte an.
void CMyEntity::Spawn()
{
	BaseClass::Spawn();
	SetNextThink( gpGlobals->curtime ); // Think jetzt
}
void CMyEntity::Think()
{
	BaseClass::Think(); // Das muss immer gemacht werden, wenn Think() überschrieben wird
	Msg( "Ich denke, also bin ich.\n" );
	SetNextThink( gpGlobals->curtime + 1 ); // Think in 1 Sekunde nochmal
}
Beachte die Verwendung von gpGlobals->curtime, um den übergebenen Wert relativ zum ausführungszeitpunkt zu machen.
== Neue Think-Funktionen ==
eine Entity kann eine beliebige Anzahl zusätzlicher Think-Funktionen haben. Um eine neue zu registrieren:
# Man muss sichergehen, dass die Funktion void ist.
# Hinzufügen zur der Entity mit DEFINE_THINKFUNC().
# SetThink() aufrufen und den Pointer zur Funktion übergeben (siehe Beispiel unten).
# Man muss sichergehen, dass DECLARE_DATADESC(); in der eigenen Klasse ist.
BEGIN_DATADESC( CMyEntity )
	DEFINE_THINKFUNC( MyThink ), // Die neue Think-Funktion registrieren
END_DATADESC()
void CMyEntity::Spawn()
{
	BaseClass::Spawn();
	SetThink( &CMyEntity::MyThink ); // Einen Funktionszeiger übergeben
	SetNextThink(gpGlobals->curtime);
}
void CMyEntity::MyThink()
{
	Msg( "Ich denke, also bin ich.\n" );
	SetNextThink( gpGlobals->curtime + 1 );
}
Der Think-Code einer Entity kann in verschiedene Funktionen aufgeteilt werden, um es wechseln zwischen dem Operationsmodi zu vereinfachen.
== Kontexte verwenden ==
Es ist möglich, eine beliebige Anzahl an Think-Funktionen mit einem „Think-Kontext“ Seite an Seite zu planen. Um einen neuen Kontext zu erzeugen:
# RegisterThinkContext( ContextName) aufrufen
# SetContextThink(* Function, float NextThinkTime, string ContextName) aufrufen
# SetNextThink(float NextThinkTime, string ContextName) für nachfolgende Thinks aufrufen
BEGIN_DATADESC( CMyEntity )
	DEFINE_THINKFUNC( ContextThink ),
END_DATADESC()
void CMyEntity::Spawn()
{
	SetNextThink( gpGlobals->curtime ); // Standard Think-Schleife - kein Kontext
	
	RegisterThinkContext( "TestContext" );
	SetContextThink( &CMyEntity::ContextThink, gpGlobals->curtime, "TestContext" );
}
void CMyEntity::Think()
{
	BaseClass::Think();
	Msg( "Think\n" );
	SetNextThink( gpGlobals->curtime + .1 );
}
void CMyEntity::ContextThink()
{
	Msg( "Kontext-Think\n" );
	SetNextThink(gpGlobals->curtime + .2, "TestContext" );
}
Dies erzeugt 2 gleichzeitige Think-Schleifen, die beide mit unterschiedlicher Rate Konsolenausgaben machen.
== Utilities ==
Diese sollten selbsterklärend sein:
float	GetLastThink()
float	GetNextThink()
int	GetLastThinkTick()
int	GetNextThinkTick()
Die GetLast-Funktionen sind nützlich für die Kontrolle der Rate, in der etwas auftritt. 
Dieser Think-Code des moduliert die Deschwindigkeit der Zungenbewegung, auch wenn die Think-Häufigkeit sich ändert:
float dt = gpGlobals->curtime - GetLastThink(); // dt ist "delta time" ("Zeitunterschied")
SetAltitude( m_flAltitude + m_flBarnaclePullSpeed * dt ); // Ändern der Zungenhöhe
Damit diese nicht--Animation weich ist, muss der Code jeden Frame ausgeführt werden. Genau das Passiert, bis das Barnacle nicht mehr in der des Spieler ist, wonach die Rate verringert wird – wofür der obige Code nötig ist.
==ClientThink()==
Think kann ebenfalls auf der Clientseite auftreten, aber dessen Auswirkungen sind limitiert. Nur eine Think-Funktion wird für jede Entity unterstützt.
 void C_MyEntity::ClientThink()
 {
 	Msg( "Packe nichts in diese Funktion!\n" );
 	SetNextClientThink( CLIENT_THINK_ALWAYS ); // Think in jedem Frame
 }
Ein paar Beispiele für Clientseitige Thinks sind:
* visuelle Effekte / Partikel
* VGUI-Interaktionen
* Anpassung der Spielergeschwindigkeit (auf dem Client und auf dem Server, um probleme zu vermeiden)
* Fangseile der Strider (standardmäßig deaktiviert)
SetNextClientThink() wird zum Planen von ClientThink() verwendet. Es gibt 2 spezielle, akzeptierte Werte:
; CLIENT_THINK_ALWAYS
: Think auf Clientseite bei jedem Frame. Mit Vorsicht verwenden! 
; CLIENT_THINK_NEVER
: Pausiert automatisch alle Client-Thinks.