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
.
struct edict_s
{
qboolean free;
int serialnumber;
link_t area; // linked to a division node or leaf
int headnode; // -1 to use normal leaf check
int num_leafs; // How many leaves the entity occupies, shouldn't be more than MAX_ENT_LEAFS
short leafnums[MAX_ENT_LEAFS];
float freetime; // sv.time when the object was freed
void* pvPrivateData; // Alloced and freed by engine, used by DLLs; pointer to a HL SDK entity
entvars_t v; // Common entity variables
};
It's basically an entity dictionary, containing data such as whether the entity's memory is free, its "serial number", its link to a BSP leaf, a pointer to the game entity (an instance of an HL SDK entity class), and an entvars_t variable to hold common entity variables.edict_t
often. CBaseEntity
, there's a reference to this entvars_t
.
entvars_t *pev;
"pev" stands for "Pointer to Entity Variables", and it is essentially a group 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 push other entitiesMOVETYPE_NOCLIP
- not affected by gravity, passes through everythingMOVETYPE_FLYMISSILE
- same as MOVETYPE_FLY
but with extra size so it can hit monstersMOVETYPE_BOUNCE
- affected by gravity, bounces from the surface depending on pev->friction
MOVETYPE_BOUNCEMISSILE
- combination of FLYMISSILE and BOUNCEMOVETYPE_FOLLOW
- follows pev->aimentMOVETYPE_PUSHSTEP
- a combination of PUSH and STEP for brush entities, only works with SOLID_BSP
solid
- 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 flags. The constants are defined in const.h, and here are some of the more important ones:FL_SKIPLOCALHOST
- Tells the engine not to transmit the entity to the local hostFL_ONGROUND
- Indicates whether the entity is on the ground or not; can be overriddenFL_FAKECLIENT
- Indicates that this is a bot; set this while writing your own botsFL_FLOAT
- Tells the engine to apply buoyancy to the entity when in waterFL_ALWAYSTHINK
- Calls Think every frameFL_MONSTERCLIP
- Only collide with and block entities that have this flag setFL_ONTRAIN
- Ignore the player's movement commands; useful to set this when controlling a vehicleFL_WORLDBRUSH
- Tells the engine that this is an entirely static brush entity, almost as if it were worldspawnFL_KILLME
- Marks the entity to be deleted from memory; this is set by UTIL_Remove
FL_DORMANT
- Doesn't send updates to the client, thus saving on bandwidth; the entity cannot call Think if this is setedict_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
members. This is not a C string. Here is an example usage of the API:
// Allocating a string
string_t exampleString = ALLOC_STRING( "Example string" );
// Evaluating/reading a string
const char* exampleStringValue = STRING( exampleString );
If you're a beginner, you may get confused by it, since it's defined as an unsigned int
. So, here is an explanation: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 had a string_t
variable with a value of 11, in this very example, STRING
would return "func_wall".string_t
as a handle.
CBaseEntity
. We won't cover all of its methods and members, but we will go through the most important ones.
Spawn
FCAP_MUST_SPAWN
flag.Precache
method, it should be called from Spawn
. The engine will not automatically call Precache
except when loading a save game.
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; // This line is NOT needed if using Solokiller's Half-Life: Updated SDK!
}
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 saving and loading custom data fields across save files (the ones in the mod's SAVE
folder). In order for those to know what to save/load and what not to save/load, they need a "save/restore table". Needless to say that this is a requirement for singleplayer modifications (and not needed for multiplayer only ones).ObjectCaps
FCAP_CUSTOMSAVE
- unknown and unusedFCAP_ACROSS_TRANSITION
- the entity will transfer across level transitionsFCAP_MUST_SPAWN
- calls Spawn
instead of Precache
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 transitionsActivate
CBaseEntity
has a lot of overrideable methods, but some of these are modular - they can be changed dynamically at runtime.virtual void Think( void )
{
if ( m_pfnThink )
(this->*m_pfnThink)();
}
These methods actually call callbacks.
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 );
Keep in mind, however, that you don't really have to use these, and for simple entities, you can just override these methods without consequences.
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
ServerActivate
The game exports these to the engine when hl.dll
is loaded, after which the engine calls them for each edict_t
in its internal array of entities.
KeyValue(pkvd)
for each keyvalue for the entitySpawn()
Activate()
Precache()
is not called. If your entity has a custom Precache
function, you should call it from the Spawn
method.
ObjectCaps()
DispatchSave
to see if the entity has the FCAP_DONT_SAVE
flag, in which case Save
will not be called.Save()
ObjectCaps()
DispatchRestore
to see if the entity has the FCAP_MUST_SPAWN
flag, in which case Spawn
will be called instead of Precache
below.Restore()
Precache()
Activate()
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.