entvars_t
vs. edict_t
vs. entity classesCBaseEntity
and a CFuncWall
. Instead, the engine only knows one form of entity. And that is edict_t
. edict_t
often. CBaseEntity
, there's an entvars_t
as well.
entvars_t *pev;
"pev" stands for "Pointer to Entity Variables", and it is essentially a set of variables that is common to all entities. entvars_t
is defined in progdefs.h
, and constants that can be used with variables from entvars_t are in const.h
.entvars_t
are:
classname
- entity's classnametargetname
- entity's nametarget
- target entity's nameorigin
- entity's current positionvelocity
- entity's current velocitymovedir
- entity's current movement directionangles
- entity's current anglesavelocity
- angular velocitymodel
- path to the modelnextthink
- next time the entity will call its think callbackmovetype
- movement type of the entity, which can be:MOVETYPE_NONE
- entity won't moveMOVETYPE_WALK
- entity will use walk physics (players only)MOVETYPE_STEP
- entity will use walk physics for monstersMOVETYPE_FLY
- entity not be affected by gravityMOVETYPE_TOSS
- affected by gravityMOVETYPE_PUSH
- entity can get pushedMOVETYPE_NOCLIP
- not affected by gravity, passes through everythingMOVETYPE_FLYMISSILE
- FLY but with extra size so it can hit monstersMOVETYPE_BOUNCE
- affected by gravity, bounces from the surface depending on pev->frictionMOVETYPE_BOUNCEMISSILE
- combination of FLYMISSILE and BOUNCEMOVETYPE_FOLLOW
- follows pev->aimentMOVETYPE_PUSHSTEP
- BSP model that doesn't move on its own, but can collide with other entitiessolid
- solidity mode of the entity, which can be:SOLID_NOT
- non-solid, everything passes through itSOLID_TRIGGER
- calls Touch, otherwise non-solidSOLID_BBOX
- uses its axis-aligned bounding box for collisions (this collision box cannot rotate, keep in mind), calls Touch when an entity touches one of its edges, can call BlockedSOLID_SLIDEBOX
- can only call Touch when on the ground, calls it when an entity touches one of its edgesSOLID_BSP
- uses BSP cliphulls of the brush model for collisions, Touch on edge and can call Blockedrendermode
- render mode of this entity, can be:kRenderNormal
- NormalkRenderTransColor
- ColorkRenderTransTexture
- TexturekRenderGlow
- GlowkRenderTransAlpha
- SolidkRenderTransAdd
- Additiverenderamt
- render amount of this entity (typically wrongly named in FGDs as "FX Amount")rendercolor
- render colourrenderfx
- render effect (look at const.h
, it's got many of them)spawnflags
- flags set in the map editor (in the Flags tab)flags
- temporary entity flagsedict_t
as a parameter, so you'll need to convert your CBaseEntity
or CFuncWall
or any entity class you're using into edict_t
. While there's no direct conversion, you can use the ENT
utility function to 'convert' an entvars_t
into an edict_t
. For example:
SET_MODEL(ENT(pev), STRING(pev->model));
We'll discuss utility functions later on.
string_t
string_t
type. This is not a C-string.string_t
, since it's essentially an unsigned int
, so I'll briefly explain it here.string_t
is in fact just an offset into that giant string.H e l l o w o r l d \0 f u n c _ w a l l \0
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
If we wanted to allocate a new string there via ALLOC_STRING
, like so:string_t something = ALLOC_STRING( "something" );
string_t
variable with a value of 11, STRING
would return 11. That is essentially what string_t is. Just an offset into the internal string.
CBaseEntity
. We won't cover all of its methods and members, but we will go through the most important ones.
Spawn
Precache
PRECACHE_MODEL
- precaches studio modelsPRECACHE_SOUND
- precaches audio filesPRECACHE_GENERIC
- precaches any file, you can even precache a whole .bsp if you wanted to
KeyValue
pkvd
- the data of one keyvalueif (FStrEq(pkvd->szKeyName, "myKeyvalue"))
{
m_myVariable = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue(pkvd);
We compare szKeyName
to all possible keyvalues this entity may have, and then convert the szValue
string into a value of the type we need.Save
& Restore
Save
and Restore
are the key methods for transferring custom data fields across savefiles. If an entity has its own members, but doesn't save/restore, then it is most likely to break while loading a savefile, or across level transitions.Save
and Restore
methods as well as declaring the save-restore table (TYPEDESCRIPTION
) as m_SaveData
like this:
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
Outside of the entity class, you define the save-restore table like this:
TYPEDESCRIPTION CPendulum::m_SaveData[] =
{
DEFINE_FIELD( CPendulum, m_accel, FIELD_FLOAT ),
DEFINE_FIELD( CPendulum, m_distance, FIELD_FLOAT ),
DEFINE_FIELD( CPendulum, m_time, FIELD_TIME ),
DEFINE_FIELD( CPendulum, m_damp, FIELD_FLOAT ),
DEFINE_FIELD( CPendulum, m_maxSpeed, FIELD_FLOAT ),
DEFINE_FIELD( CPendulum, m_dampSpeed, FIELD_FLOAT ),
DEFINE_FIELD( CPendulum, m_center, FIELD_VECTOR ),
DEFINE_FIELD( CPendulum, m_start, FIELD_VECTOR ),
};
IMPLEMENT_SAVERESTORE( CPendulum, CBaseEntity );
Note: Valve generally placed this near either the class declaration or the LINK_ENTITY_TO_CLASS
line, but it can be placed anywhere.DEFINE_FIELD
requires 3 parameters: the class being saved/restored, the attribute being saved/restored and its type. The following table contains all available types of variables you can save and restore. The types with an asterisk (*
) are the ones you will see and likely use very often in the HL SDK :
Type | Description |
---|---|
FIELD_FLOAT* | A floating point value (0.2 , 75.5 ) that is not related to time (use FIELD_TIME for that purpose) |
FIELD_STRING* | A string ID (string_t - often the result of ALLOC_STRING ) |
FIELD_ENTITY | An entity offset (EOFFSET ) |
FIELD_CLASSPTR* | An entity class pointer (like CBaseEntity * ) |
FIELD_EHANDLE* | An entity handle (EHANDLE ) |
FIELD_EVARS | An entity variables pointer (EVARS * ) |
FIELD_EDICT | An entity dictionary pointer (edict_t * ) |
FIELD_VECTOR* | A vector (Vector , vec3_t , array of 3 float ) |
FIELD_POSITION_VECTOR | A world coordinate (fixed up across level transitions "automagically") |
FIELD_POINTER | Arbitrary data pointer (scheduled to be removed by Valve but seems that isn't the case) |
FIELD_INTEGER* | An integer (5 , 3 ) or enum value. |
FIELD_FUNCTION | A class function pointer (like Think , Touch , Use ...) |
FIELD_BOOLEAN* | A "boolean" value (see the warning below as to why boolean is between quotes) |
FIELD_SHORT | A 2 byte integer value. |
FIELD_CHARACTER | A single byte value. |
FIELD_TIME* | Same as FIELD_FLOAT but for variables related to time (like weapons reload time), usually a floating point value that has a relation to the game time (gpGlobals->time ) |
FIELD_MODELNAME | An engine string that is a model's name (requires precaching). |
FIELD_SOUNDNAME | Same as previous one but for sounds. |
IMPLEMENT_SAVERESTORE
requires 2 parameters: the class being saved and its parent. It tells the save/restore code to take care of your entity variables as well as the parent's ones. This is handy because it avoids having to redefine every variable from the parent(s).
ObjectCaps
FCAP_CUSTOMSAVE
- unknown and unusedFCAP_ACROSS_TRANSITION
- the entity will transfer across level transitionsFCAP_MUST_SPAWN
- calls Spawn right after Restore, i.e. after loading a savefileFCAP_DONT_SAVE
- don't write into the savefileFCAP_IMPULSE_USE
- can be used by the playerFCAP_CONTINUOUS_USE
- can be held by the player (such as levers and valves)FCAP_ONOFF_USE
- can be toggled by the playerFCAP_DIRECTIONAL_USE
- receives +/- from the player, only used by func_tracktrainFCAP_MASTER
- entity can be used as a master (multisource has this cap)FCAP_FORCE_TRANSITION
- entity always goes across transitions
Active
void (CBaseEntity ::*m_pfnThink)(void);
void (CBaseEntity ::*m_pfnTouch)( CBaseEntity *pOther );
void (CBaseEntity ::*m_pfnUse)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void (CBaseEntity ::*m_pfnBlocked)( CBaseEntity *pOther );
This means that each can be changed at any time.
Think
SetThink
macro.pev->nextthink
variable.pev->nextthink = gpGlobals->time + 0.5; // think every 0.5 seconds
Touch
SetTouch
macro.pOther
- entity that touched this entityUse
SetUse
macro.pActivator
- entity that started the trigger sequencepCaller
- entity that actually fired this entityuseType
- type of usage: USE_TOGGLE, USE_ON, USE_OFF and USE_SETvalue
- the value sent from pCaller, typically used only in func_tracktrainBlocked
pOther
- entity that blocked this entityCreate
szName
- the classname itself, e.g. env_sprite, monster_zombie etc.vecOrigin
- the position at which it'll spawnvecAngles
- the angles it'll have after spawningpentOwner
- owner of the newly created entity (NULL by default)Instance
edict_t*
, entvars_t*
or entity indices into CBaseEntity*
.pent
- entity dictionary/edict to convert from (edict_t*
overload)pev
- entity variables to convert from (entvars_t*
overload)eoffset
- entity index to retrieve from (int
overload)DispatchSpawn
DispatchKeyValue
DispatchTouch
DispatchUse
DispatchThink
DispatchBlocked
DispatchSave
DispatchRestore
DispatchObjectCollsionBox
It locates their addresses when it loads hl.dll
, and then calls them for each edict_t
in its internal array of entities.
CWorld
- worldspawn entityCItem
- base item classCBaseDelay
- generic delay entity, can be spawned when an entity tries to trigger another entity with a delay
CBaseAnimating
- entity that supports studio model animations, provides utilities for submodels, setting controllers etc.CBasePlayerItem
- generic player itemCBasePlayerWeapon
- generic player weaponCBaseToggle
- generic toggleable entity, implements linear movement for trains, opening and closing mechanism for doors etc.CBaseMonster
- base monster classCBasePlayer
- player classYou must log in to post a comment. You can login or register a new account.