This article was recovered from an archive and needs to be reviewed
- The formatting may be incorrect as it was automatically converted to WikiCode from HTML, it needs to be revised and reformatted
- Some information may be out of date as it was written before Half-Life was available on Steam
- After the article is re-formatted and updated for Steam HL, remove this notice
- Please do not remove the archive notice from the bottom of the article.
- Some archive articles are no longer useful, or they duplicate information from other tutorials and entity guides. In this case, delete the page after merging any relevant information into other pages. Contact an admin to delete a page.
Almost all entities in Half-Life have at least two of the three primary functions: Think, Touch, and Use. These functions are key to how an entity works.
The Use Function
The Use function is used whenever an entity can be triggered. Most of the effects entities, such as an env_sprite, have a use function. So, let's break down a Use function.
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
The first parameter is
CBaseEntity *pActivator
. When the Use function is called, this parameter identifies the entity which activated this particular Use function. It does not have to be the entity which actually called this entity's Use function. For example, if a player walks into a trigger_once, it calls its target's Use function and passes the player pointer as the activator.
*pCaller
is the entity which called the particular
Use
function. From the
Use
function, you can modify the variables and call more functions to perform actions on those entities as you see fit.
The third parameter is the use type. There are three major use types:
USE_ON
,
USE_OFF
, and
USE_TOGGLE
. You can check what
useType
is and then perform different actions based on its value.
Parameter four is basically unused in most entities. It's just a simple value that you can assign when the entity is fired. It may be used for special cases or something.
Ok, now we will learn one of the key things about these three functions. If you are declaring a Use, Touch, or Think function and its name is not
Use
,
Touch
, or
Think
, you must put
EXPORT
between the function type and function name.
void EXPORT UseFunction( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
If you forget the
EXPORT
, the function will not be remembered between level changes or level saves. It is vitally important that you check to make sure all your functions have this.
Now, the reason you would want to name it something other than
Use
is if you have multiple Use functions. The particular Use function that will be called is determined by using the
SetUse( functionname );
command.
SetUse( UseFunction );
If you only have one Use function, just keep it named
Use
and it will automatically be set, no
SetUse
needed. To fire an entity's Use function, use the
FireTargets
function in an entity; this will fire its
pev->target
's Use function (assuming it has one).
So we can set up a use function right, but what if we want to remove one? Well, that's easy. In a case where you have a specific event happen and you don't want an entity to be usable any more, just throw in one simple line:
SetUse( NULL );
Bam! No more use function for it. And of course if you want it back, you can just call
SetUse
with an actual function instead of
NULL
.
The Touch Function
The Touch function is used whenever an entity is touched. Its primary use is for triggers like a trigger_once or trigger_multiple, but it also has many others. The other major uses include tracking when an entity hits a wall, bounces, reflects, etc. When an entity touches another, the engine calls the
DispatchTouch
function which in return calls the touched entity's Touch function with the pointer of the toucher.
void Touch( CBaseEntity *pOther );
CBaseEntity *pOther
is the entity which touched the entity with the Touch function. Again, you can modify it however you like. The Touch function shares many of the same properties as the Use function. You MUST have
EXPORT
between the function type and name:
void TouchFunction( CBaseEntity *pOther );
If the name of the function is
Touch , you do not need to use the
SetTouch
function either. Otherwise, you must use the
SetTouch
command in the same manner as the
SetUse
function.
SetTouch( TouchFunction );
Again like use functions you can also remove a touch function from being set. One simple line:
SetTouch( NULL );
The Think Function
Of the three primary functions, the Think function is the most important. A Think function is called every x seconds and executes code that gives the impression of "thinking." Almost every entity has a Think function: monsters, players, weapons, effects entities, all of them. Some Think functions call other functions while they think, giving a branching effect. For example, the apache flies around and hunts players using the
HuntThink
function. But, within the
HuntThink
function is called the
Flight
function, which controls the dynamic physics to tilt the chopper in the appropriate direction as it flies. Here is what a basic Think function looks like:
void Think( void );
Pretty plain. Now let's look at a Think function's actual body:
void CYourClass::Think( void ){ ALERT(at_console, "I am thinking!
"); pev->nextthink = gpGlobals->time + 0.1;}
Ok, time to detail. The first line with the
ALERT
is just a simple alert to tell us that our Think function is being called. Now the second line is extremely important in any Think function.
pev->nextthink
is a variable that stores the time value for the engine to use. The engine uses this number to know when to trigger the think function again. In this case, we're taking the current global time (
gpGlobals->time
) and adding 0.1 seconds to that. Right, so we'll get the message "I am thinking!" about 10 times a second. It's a simple Think function and serves no practical purpose, but it is indeed a Think function.
Again, Think functions work like the Use and Touch functions. Generally, you'll use a
SetThink
call within an entity's Spawn function, such as:
SetThink( ThinkFunction );
Followed by:
pev->nextthink = gpGlobals->time + X.X;
Again, that tells the engine at what time to call our Think function. If it is just named Think, there is no need for a SetThink, but you still must set the
pev->nextthink
variable to a time value.
You can stop an entity from thinking in two manners. First, just like use and touch, you can do:
SetThink( NULL );
But, you can also set nextthink to something
before the current global time, for example:
pev->nextthink = 0;
If set before the global time, the engine will never call the function again because that time has already passed. This is useful if you want to keep the think function attached to the entity, but might not want to think in specific cases.
Put It to Use!
Time to put what we've learned to use in a small example. Attached to this tutorial is a small example utilizing all of these functions in the code for a projectile entity. Read the comments to understand how it all comes together. You'll want to create the projectile with
CBaseEntity::Create
and set its angles to whatever. I hope you've learned just how important the Think, Touch, and Use functions are in creating everything and anything in Half-Life.
This article was originally published on the
Valve Editing Resource Collective (VERC).
TWHL only archives articles from defunct websites. For more information on TWHL's archiving efforts, please visit the
TWHL Archiving Project page.