Main game structs


Description of gentity_t and gclient_t, the game module structs for game entities and game clients.



/* paste source text here */


struct gentity_s

This struct describes the properties of an "entity" in the game module. An entity may also be known as a "game object" in other contexts.

The Q3 engine knows nothing about the contents of a gentity_t, though it knows how large the struct is, via trap_LocateGameData(). The fields are specific to the game module, and are utilized solely by the code in the game module. The game module may still copy values into the members that the Q3 engine recognizes.

The trap trap_LocateGameData notifies the Q3 engine of the location of the array of game entities. The Q3 engine requires the beginning of each game entity struct to be a specific form, but the rest is left to the game module.

typedef struct gentity_s gentity_t;

struct gentity_s {
    entityState_t   s;              // communicated by server to clients
    entityShared_t  r;              // shared by both the server system and game


    struct gclient_s    *client;            // NULL if not a client

    qboolean    inuse;

    char        *classname;         // set in QuakeEd
    int         spawnflags;         // set in QuakeEd

    qboolean    neverFree;          // if true, FreeEntity will only unlink
                                    // bodyque uses this

    int         flags;              // FL_* variables

    char        *model;
    char        *model2;
    int         freetime;           // level.time when the object was freed

    int         eventTime;          // events will be cleared EVENT_VALID_MSEC after set
    qboolean    freeAfterEvent;
    qboolean    unlinkAfterEvent;

    qboolean    physicsObject;      // if true, it can be pushed by movers and fall off edges
                                    // all game items are physicsObjects,
    float       physicsBounce;      // 1.0 = continuous bounce, 0.0 = no bounce
    int         clipmask;           // brushes with this content value will be collided against
                                    // when moving.  items and corpses do not collide against
                                    // players, for instance

    // movers
    moverState_t moverState;
    int         soundPos1;
    int         sound1to2;
    int         sound2to1;
    int         soundPos2;
    int         soundLoop;
    gentity_t   *parent;
    gentity_t   *nextTrain;
    gentity_t   *prevTrain;
    vec3_t      pos1, pos2;

    char        *message;

    int         timestamp;      // body queue sinking, etc

    float       angle;          // set in editor, -1 = up, -2 = down
    char        *target;
    char        *targetname;
    char        *team;
    char        *targetShaderName;
    char        *targetShaderNewName;
    gentity_t   *target_ent;

    float       speed;
    vec3_t      movedir;

    int         nextthink;
    void        (*think)(gentity_t *self);
    void        (*reached)(gentity_t *self);    // movers call this when hitting endpoint
    void        (*blocked)(gentity_t *self, gentity_t *other);
    void        (*touch)(gentity_t *self, gentity_t *other, trace_t *trace);
    void        (*use)(gentity_t *self, gentity_t *other, gentity_t *activator);
    void        (*pain)(gentity_t *self, gentity_t *attacker, int damage);
    void        (*die)(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod);

    int         pain_debounce_time;
    int         fly_sound_debounce_time;    // wind tunnel
    int         last_move_time;

    int         health;

    qboolean    takedamage;

    int         damage;
    int         splashDamage;   // quad will increase this without increasing radius
    int         splashRadius;
    int         methodOfDeath;
    int         splashMethodOfDeath;

    int         count;

    gentity_t   *chain;
    gentity_t   *enemy;
    gentity_t   *activator;
    gentity_t   *teamchain;     // next entity in team
    gentity_t   *teammaster;    // master of the team

    int         kamikazeTime;
    int         kamikazeShockTime;

    int         watertype;
    int         waterlevel;

    int         noise_index;

    // timing variables
    float       wait;
    float       random;

    gitem_t     *item;          // for bonus items

An instance of entityState_t. The Q3 engine expects this struct in this location.
An instance of entityShared_t. Q3 engine expects this struct in this location. Yes, entityShared_t contains yet another entityState_t. Don't ask.
Pointer to a gclient_t, if this entity is a client (first 64 entities). NULL if not a client.
Boolean, whether this entity slot is used or not.
A name indicating this entity's type, or class, or category.
Spawn-time flags, for map entities (e.g. movers, triggers).
This entity slot should never be freed, but just unlinked instead. Used by body queue.
The level.time when this entity is freed.
Whether this entity is automatically freed after its event finishes.
Whether this entity is unlinked, but not freed, after its event finishes.
Whether this entity experiences physics-based motion (mainly fallling).
Bounce factor. Value of 1.0 is (an unrealistically) perfect reflection of kinetic energy. A value of 0.0 (also unrealistically) stops this entity fully -- for TR_LINEAR trajectory, the entity remains still midair; for TR_GRAVITY trajectory, the entity falls straight down.
Bitmask flags that indicate what brushes (XXX: correct word?) against which this entity clips.
For movers, the sound to play when the mover reaches its first position.
For movers, the sound to play when the mover leaves its first position.
For movers, the sound to play when the mover leaves its second position.
For movers, the sound to play when the mover reaches its second position.
Sound the play in a loop while the mover is moving.
Pointer to the head of a linked list of entities.
For train entities, the next train location after the current one.
For train entities, the previous train location before the current one.
For movers, its first position.
For movers, its second position.
For target_print entities, the message to print.
For corpses (body queue), the level.time when the corpse was made. For players, the level.time of last hurting from a hurt brush.
Angle for map entities. This is the direction the entity faces on map spawn. Expressed as a rotation around around the z axis (XXX: what's 0? x?).
For map entities in general, name of some other entity to activate at an "appropriate time". For portal entities, its camera object (the source of the portal's image). For camera entities, the direction to view? (otherwise aims towards portal?) For shooter entities, a target to actively target (moving aim as needed). For train entities, the next target (location) in the train. For give entities, a linked list of items to give to the activator? For laser entities, the entity to aim at (if any). For teleport entities, the teleport destination. For relay entities, the entity to activate.
For door entities, the remote button or trigger to open the door, otherwise acts in the usual Star Trek style (opens when a player is near). For plat entities (such as lifts), the remote button or trigger to activate the plat, otherwise activates if player is touching the plat.
Team name. Something about linking up all entities on a particular team. Movers that stay together are members of their own team?
XXX: Um... change shader on de/activate?
XXX: change shader on de/activate?
For proximity mines, pointer to the player entity it bounced off due to invulnerability.
For item entities, on respawn or pickup, zero for global sound, non-zero for local sound. For movers, the moving speed. For doors, the opening speed. For plats, the moving speed. For buttons, (XXX: ???). For trains, the new speed to use. For path corners, new speed to use. For rotation, rotation speed (left-handed geometry = positive number rotates clockwise when viewed from positive axis ("overhead" for z)). For bobbing, time in seconds to complete a full bob cycle. For pendulum, maximum swinging angle in degrees (degrees from vertical). For push targets, speed to push (as with jumppads).
For shooters, the direction to shoot if there's no target in particular. For proximity mines, (XXX: ???). For doors, the direction to move for opening/closing. For buttons, the direction to move for pressing/releasing. For lasers, the direction to shoot. For kamikaze explosions, (XXX: ???).
The level.time when this entity's think function runs again.
A function pointer to the entity's think function. This function is called when level.time exceeds nextthink. This function may cause the entity to destroy itself (e.g. time-delay bombs), or induce basic AI (e.g. homing missiles). In the latter case, the think function may again set nextthink to level.time+some_delay to re-run the think function shortly thereafter. One argument: the entity that is thinking (player, mover, shooter, button, etc.).
A function pointer to the entity's reach function. Used primarily for movers, this function runs when the mover reaches one of its destinations. One basic action is to send it right back to the other destination, although other actions are possible, such as killing someone randomly, activating a remote trigger, or jumping/teleporting back to another location (disappearing platforms). One argument: the entity that reached its destination (mover).
A function pointer to the entity's block function. Used primarily for movers, called when some other entity is blocking this entity. The usual action is to cause damage to the other entity and keep moving (squashing), or to bounce back to this entity's (the mover's) previous position. Two arguments: the entity being blocked (mover), the entity that caused the block (player, flag, item).
A function pointer to the entity's touch function. When this entity touches another entity, usually player-in-trigger (e.g. buttons, teleports). Three arguments: the entity being touched (teleport, door, button), the entity doing the touching (player, missile), the trace result that determined the entities are touching.
Function pointer, runs when entity is activated (such as player hitting button, or standing near door). Three arguments: the entity being used (item, button), ???, the entity that did the activating (player, target entity).
Function pointer, runs when entity receives damage. Three argument: entity receiving damage (player), the entity that dealt damage (player?), the damage amount. (XXX: can regen?)
Function pointer, runs when entity runs out of health. Five arguments: the entity that died (player, missile, door), the entity that delivered the damage (missile; NULL for hitscan?), the entity that attacked (player, shooter, world), damage amount, damage type.
The level.time when the pain sound event expires (new pain events do not generate a sound event during this time).
For push targets, the level.time when the "push" sound event expires (new push events do not generate a sound event during this time).
not used?
For players, their health level; this value is copied into playerState_t.stats[STAT_HEALTH]. For most game entities, some health value. For doors, non-zero value means the door must be shot to open (otherwise can open by being near or being shot). For buttons, non-zero value means the button must be shot to activate (otherwise can activate by being run into or being shot).
Whether this entity can receive damage (e.g. god mode, missiles, shootable doors) and call pain().
For missiles (grenades, rockets, plasma, BFG10K), amount of damage for a direct hit.
For missiles, amount of damage by splash damage.
Radius of splash damage. Entities beyond the radius are not damaged; entities within receive damage based on how close they are to the explosion.
A method-of-death (MOD) code number for a direct hit. This number indicates the type of missile, or, more specifically, the type of damage, from a direct hit. This number is used in obituaries to determine the obituary line ("JoeRandom ate JaneQ's rocket").
MOD code number for splash damage. ("JoeRandom almost dodged JaneQ's rocket")
For score targets, the score to give to the activator. For powerups, the amount of powerup time provided (uses item->quantity if zero). For ammo items, the amount of ammunition provided (uses item->quantity if zero). For armor items, the amount of armor provided (uses item->quantity if zero). For health items, the amount of health provided (uses item->quantity if zero). For weapon items, the amount of extra ammo provided (uses item->quantity if zero). For single player victory podium, the entity's rank (1, 2, or 3). For holdable portals, (XXX: ???). For doors, (XXX: ???). For proximity mines, whether it can currently attach to an player or not. For location entities, its location code number? For kamikaze explosion, the time counter?
For certain map entities, the entity (usually a player) that activated this entity. For kamikaze explosion, the entity (usually player) that... err... did the kamikaze.
Linked list of a team members. Movers that group together go in their own teams?
Pointer to the head of a team list. For movers, (XXX:...).
The liquid type the player is within (water or slime).
XXX: how much of the player's body is underwater?
For speaker entities, the sound index number (CONFIGSTRING) to play.
For movers, the amount of time (in seconds) to wait upon reaching a destination. For doors, amount of time (in seconds) to wait before closing again (or opening for start_open doors). For plats, amount of time (in seconds) to wait before returning to rest position? For buttons, amount of time (in seconds) to stay pressed before returning to rest position? For trains, amount of time (in seconds) to wait at the train before moving towards the next? For corners, amount of time (in seconds) to wait at the corner beofre moving to the next corner? For multiple triggers, (XXX: ???). For timer entities, amount of time (in seconds) to wait before triggering. For delay targets, amount of time (in seconds) to delay before firing targets. For speaker targets, amount of time (in seconds) to wait before auto-triggering. For items, amount of (in seconds) time before respawning.
For items, a random variance on wait. For shooters, randomize the firing direction a little. For delay targets, random variance on wait. For speaker targets, random variance on wait. For multiple triggers, random variance on wait. For timer entities, random variance on wait.
For items ("item instances"), a pointer to an gitem_t item descriptor ("item class").

struct gclient_s

This struct holds data particular to each client. A client is a (usually human) player, requiring a "feedback" mechanism (remote control).

typedef struct gclient_s gclient_t;

struct gclient_s {
    // ps MUST be the first element, because the server expects it
    playerState_t   ps;             // communicated by server to clients

    // the rest of the structure is private to game
    clientPersistant_t  pers;
    clientSession_t     sess;

    qboolean    readyToExit;        // wishes to leave the intermission

    qboolean    noclip;

    int         lastCmdTime;        // level.time of last usercmd_t, for EF_CONNECTION
                                    // we can't just use pers.lastCommand.time, because
                                    // of the g_sycronousclients case
    int         buttons;
    int         oldbuttons;
    int         latched_buttons;

    vec3_t      oldOrigin;

    // sum up damage over an entire frame, so
    // shotgun blasts give a single big kick
    int         damage_armor;       // damage absorbed by armor
    int         damage_blood;       // damage taken out of health
    int         damage_knockback;   // impact damage
    vec3_t      damage_from;        // origin for vector calculation
    qboolean    damage_fromWorld;   // if true, don't use the damage_from vector

    int         accurateCount;      // for "impressive" reward sound

    int         accuracy_shots;     // total number of shots
    int         accuracy_hits;      // total number of hits

    int         lastkilled_client;  // last client that this client killed
    int         lasthurt_client;    // last client that damaged this client
    int         lasthurt_mod;       // type of damage the client did

    // timers
    int         respawnTime;        // can respawn when time > this, force after g_forcerespwan
    int         inactivityTime;     // kick players when time > this
    qboolean    inactivityWarning;  // qtrue if the five seoond warning has been given
    int         rewardTime;         // clear the EF_AWARD_IMPRESSIVE, etc when time > this

    int         airOutTime;

    int         lastKillTime;       // for multiple kill rewards

    qboolean    fireHeld;           // used for hook
    gentity_t   *hook;              // grapple hook if out

    int         switchTeamTime;     // time the player switched teams

    // timeResidual is used to handle events that happen every second
    // like health / armor countdowns and regeneration
    int         timeResidual;

    gentity_t   *persistantPowerup;
    int         portalID;
    int         ammoTimes[WP_NUM_WEAPONS];
    int         invulnerabilityTime;

    char        *areabits;


A playerState_t struct. The Q3 engine expects this field at the beginning of the gclient_t struct.
Persistant data. This is data that does not reset across multiple respawns, but does reset on level change or team change.
Client session data. Data that remains with the client until disconnection or server shutdown. Preserved across level change (by use of cvars).
Whether client is "READY" to leave intermission (the "READY" mark on scoreboard).
Whether client is in "noclip" mode or not.
Time of the last command (usercmd_t) from the client. Can help indicate an impending connection loss. (XXX: what's this about pers.lastCommand.time?)
A bitmask of the currently pressed game buttons (+attack, +gesture, +button5).
A bitmask of the game buttons from the prior command (usercmd_t). Helps determine change of button state.
Stores buttons still held down (as opposed having been just pressed or released).
Amount of damage to armor.
Amount of damage to health.
Cumulative knockback force.
Direction of damage source.
Whether to ignore knockback or not (e.g. though lava is damage from the world, it doesn't knock the player back into the air).
Counter to keep track of railgun "Impressive" reward.
Number of shots fired.
Number of shots that hit someone.
Most recent client/player fragged by this one.
Most recent client/player to hurt this one (initialized 0).
Type of damage (means of death/damage) from most recent damage.
The level.time when the player is scheduled to respawn.
Scheduled level.time to kick player for inactivity. This timer is updated on each "activity" action to be level.time + some constant.
Whether or not inactivity warning has been given.
Scheduled level.time the overhead reward sprite expires.
Scheduled level.time for air expiration (drowning).
The level.time when player was most recently fragged.
Boolean flag to indicate constant firing for lightning gun and grappling hook.
Pointer to the hook entity/missile. This is the part that's flying. The line between the player and hook is implied, rendered client side.
Schedule level.time when the player may change teams. Intended to prevent team-switch spams.
Number of milliseconds since most recent 1-second boundary, for once-per-second effects (e.g. regeneration). This counter ensures once-per-second events happen after 1000 or more milliseconds passed. The counter is reset to zero on each once-per-second event.
Something to do with the AI bot?

struct clientPersistant_t

Persistant data is data preserved across respawns, but not on level change or team change. That sort of data is covered by clientSession_t.

// client data that stays across multiple respawns, but is cleared
// on each level change or team change at ClientBegin()
typedef struct {
    clientConnected_t   connected;
    usercmd_t   cmd;                // we would lose angles if not persistant
    qboolean    localClient;        // true if "ip" info key is "localhost"
    qboolean    initialSpawn;       // the first spawn should be at a cool locat
    qboolean    predictItemPickup;  // based on cg_predictItems userinfo
    qboolean    pmoveFixed;         //
    char        netname[MAX_NETNAME];
    int         maxHealth;          // for handicapping
    int         enterTime;          // level.time the client entered the game
    playerTeamState_t teamState;    // status in teamplay games
    int         voteCount;          // to prevent people from constantly calling
    int         teamVoteCount;      // to prevent people from constantly calling
    qboolean    teamInfo;           // send team overlay updates?
} clientPersistant_t;

Connection state of client. See also clientConnected_t.
??? (why would it lose otherwise?)
Whether client is local (one same machine as server). For example, single-player mode.
True if client has not yet spawned in the game.
Whether client wants item prediction?
(the "fixed" used here is the "not changing; not varying; no wiggle room" sense)
Player's name. MAX_NETNAME is 36 (defined in g_local.h).
Handicap value (initial (re)spawn health). Expert players can reduce their handicap (health) to give less-experienced players a more even playing field.
The level.time the client completely connected to the server (and able to chat, play, etc.).
team state information. See also playerTeamState_t.
Counter for number of callvotes initiated by this client.
Counter for number of team callvotes initiated by this client.
Whether client wants to receive team info or not (in consideration of bandwidth).

struct clientSession_t

A "session" for a client is the span of time and activity between the client's connect and the client's disconnect. A reconnect creates a new session (disconnect + connect). A session can span across multiple level (map) changes (connect, play, change map, play, change map, play, disconnect). Since the Q3VM and all memory within a .qvm are reset on map changes, the data in a clientSession_t (which is in the VM memory space) must be stored outside the VM to survive level changes. The most common form is cvars, although files are also feasible.

// client data that stays across multiple levels or tournament restarts
// this is achieved by writing all the data to cvar strings at game shutdown
// time and reading them back at connection time.  Anything added here
// MUST be dealt with in G_InitSessionData() / G_ReadSessionData() / G_WriteSessionData()
typedef struct {
    team_t      sessionTeam;
    int         spectatorTime;      // for determining next-in-line to play
    spectatorState_t    spectatorState;
    int         spectatorClient;    // for chasecam and follow mode
    int         wins, losses;       // tournament stats
    qboolean    teamLeader;         // true when this client is a team leader
} clientSession_t;

This client's team.
The level.time this client joined the tournmanet queue (lowest value goes next in tournament mode).
If spectator, spectating style. See also spectatorState_t.
If spectator, which client is being spectated (valid or not based on spectatorState).
Total number of wins for this client.
Total number of losses for this client.
Client is a team leader (XXX: only for MISSIONPACK?).

struct playerTeamState_t

A player's team-related status in a team game.

typedef struct {
    playerTeamStateState_t  state;

    int         location;

    int         captures;
    int         basedefense;
    int         carrierdefense;
    int         flagrecovery;
    int         fragcarrier;
    int         assists;

    float       lasthurtcarrier;
    float       lastreturnedflag;
    float       flagsince;
    float       lastfraggedcarrier;
} playerTeamState_t;

Player's relationship with a team. See also playerTeamStateState_t.
Index of the nearest target_location entity to this player (used in team overlay).
Number of objective (flag, skull) captures.
Number of times this player defended the base (Base Defense award).
Number of times this player defended a friendly flag carrier (Carrier Defense award).
Number of times this player recovered the flag (Flag Recovery award).
Number of times this player fragged the enemy flag carrier (Frag Carrier award).
Number of times this player assisted a flag capture(?) (Assist awards).
The level.time the player hurt an enemy flag carrier (used for what?).
The level.time the player returned the flag, used for Flag Recovery and Assist awards.
The level.time the player stole the enemy flag.
The level.time when the client fragged an enemy flag carrier (used for Assist awards).

enum clientConnected_t

Constants describing the connection state of a client in clientPersistant_t.connected.

typedef enum {
} clientConnected_t;

Client is gone; client slot not in use.
Client is fully connected and able to do game stuff.
Client is negotiating connection handshake (existence acknowleged, but unable to interact yet). Typically indicates the client is (still) loading game data/models/map.

enum playerTeamStateState_t

For playerTeamState_t. These values indicate the player's relation to a team at (re)spawn time.

typedef enum {
    TEAM_BEGIN,     // Beginning a team game, spawn at base
    TEAM_ACTIVE     // Now actively playing
} playerTeamStateState_t;

Player is spawning on this team for the first time.
Player has already been on this team.

enum spectatorState_t

Style of spectating for a spectator, clientSession_t.spectatorState. The field clientSession_t.spectatorClient may be used, depending on the particular handling of a spectator state.

typedef enum {
} spectatorState_t;

Not spectating/not a spectator.
Free movement.
Follow a client. The client to follow is specified in clientSession_t.spectatorClient.
Spectator at intermission (looking at scoreboad)

struct level_locals_t

Various level-wide variables.

typedef struct {
    struct gclient_s    *clients;       // [maxclients]

    struct gentity_s    *gentities;
    int         gentitySize;
    int         num_entities;       // current number, <= MAX_GENTITIES

    int         warmupTime;         // restart match at this time

    fileHandle_t    logFile;

    // store latched cvars here that we want to get at often
    int         maxclients;

    int         framenum;
    int         time;                   // in msec
    int         previousTime;           // so movers can back up when blocked

    int         startTime;              // level.time the map was started

    int         teamScores[TEAM_NUM_TEAMS];
    int         lastTeamLocationTime;       // last time of client team location update

    qboolean    newSession;             // don't use any old session data, because
                                        // we changed gametype

    qboolean    restarted;              // waiting for a map_restart to fire

    int         numConnectedClients;
    int         numNonSpectatorClients; // includes connecting clients
    int         numPlayingClients;      // connected, non-spectators
    int         sortedClients[MAX_CLIENTS];     // sorted by score
    int         follow1, follow2;       // clientNums for auto-follow spectators

    int         snd_fry;                // sound index for standing in lava

    int         warmupModificationCount;    // for detecting if g_warmup is changed

    // voting state
    char        voteString[MAX_STRING_CHARS];
    char        voteDisplayString[MAX_STRING_CHARS];
    int         voteTime;               // level.time vote was called
    int         voteExecuteTime;        // time the vote is executed
    int         voteYes;
    int         voteNo;
    int         numVotingClients;       // set by CalculateRanks

    // team voting state
    char        teamVoteString[2][MAX_STRING_CHARS];
    int         teamVoteTime[2];        // level.time vote was called
    int         teamVoteYes[2];
    int         teamVoteNo[2];
    int         numteamVotingClients[2];// set by CalculateRanks

    // spawn variables
    qboolean    spawning;               // the G_Spawn*() functions are valid
    int         numSpawnVars;
    char        *spawnVars[MAX_SPAWN_VARS][2];  // key / value pairs
    int         numSpawnVarChars;
    char        spawnVarChars[MAX_SPAWN_VARS_CHARS];

    // intermission state
    int         intermissionQueued;     // intermission was qualified, but
                                        // wait INTERMISSION_DELAY_TIME before
                                        // actually going there so the last
                                        // frag can be watched.  Disable future
                                        // kills during this delay
    int         intermissiontime;       // time the intermission was started
    char        *changemap;
    qboolean    readyToExit;            // at least one client wants to exit
    int         exitTime;
    vec3_t      intermission_origin;    // also used for spectator spawns
    vec3_t      intermission_angle;

    qboolean    locationLinked;         // target_locations get linked
    gentity_t   *locationHead;          // head of the location list
    int         bodyQueIndex;           // dead bodies
    gentity_t   *bodyQue[BODY_QUEUE_SIZE];
    int         portalSequence;
} level_locals_t;


Created 2002.09.21
Updated 2002.12.03
Updated 2003.11.10 - additions from cyrri.
Updated 2011.07.11 - change of contact e-mail.

PhaethonH < >