PlanetQuake | Code3Arena | Articles | Article 1 | Next >>


  • Home/News
  • ModSource
  • Compiling
  • Help!!!
  • Submission
  • Contributors
  • Staff
  • Downloads

    < Index >
    1. Mod making 101
    2. Up 'n running
    3. Hello, QWorld!
    4. Infinite Haste
    5. Armor Piercing Rails
    6. Bouncing Rockets
    7. Cloaking
    8. Ladders
    9. Favourite Server
    10. Flame Thrower
    11. Vortex Grenades
    12. Grapple
    13. Lightning Discharge
    14. Locational Damage
    15. Leg Shots
    16. Weapon Switching
    17. Scoreboard frag-rate
    18. Vortex Grenades II
    19. Vulnerable Missiles
    20. Creating Classes
    21. Scrolling Credits
    22. Weapon Dropping
    23. Anti-Gravity Boots
    24. HUD scoreboard
    25. Flashlight and laser
    26. Weapon Positioning
    27. Weapon Reloading
    28. Progressive Zooming
    29. Rotating Doors
    30. Beheading (headshot!)
    31. Alt Weapon Fire
    32. Popup Menus I
    33. Popup Menus II
    34. Cluster Grenades
    35. Homing Rockets
    36. Spreadfire Powerup
    37. Instagib gameplay
    38. Accelerating rockets
    39. Server only Instagib
    40. Advanced Grapple Hook
    41. Unlagging your mod

    < Index >
    1. Entities
    2. Vectors
    3. Good Coding
    4. Compilers I
    5. Compilers II
    6. UI Menu Primer I
    7. UI Menu Primer II
    8. UI Menu Primer III
    9. QVM Communication, Cvars, commands
    10. Metrowerks CodeWarrior
    11. 1.27g code, bugs, batch


  • Quake3 Files
  • Quake3 Forums
  • Q3A Editing Message Board
  • Quake3 Editing


  • SumFuka
  • Calrathan
  • HypoThermia
  • WarZone

    Site Design by:
    ICEmosis Design

    by SumFuka

    This is the first in a series of 'articles' explaining various things about the quake3 game world. Every wondered how you interact with the game world ? This is the first question we're going to tackle... by working from the ground up. Quake's design hasn't changed much from quake1 thru to quake3... the most basic thing in the world is - yes, an entity !


    Virtually anything you can name in the game world is an entity. A rocket ? That's a simple example of an entity. An ammo pack ? An entity. A player ? Again, that's an entity (albeit a special one). Let's take an example... urm... ummm... let's fire a rocket ! Here's how it works.
    1. You press the fire button
    2. An empty entity slot is chosen (i.e. a slot that is not inuse)
    3. A rocket entity is created in that slot
    4. The rocket settings are defined (positioned just in front of you, aimed in a certain direction, moving at 900 units/second, etc)
    5. The rocket moves through the world until an event is triggered :
      • If the rocket hits something damageable (e.g. a player or a wall) then it explodes and the entity is removed
      • If the rocket doesn't hit anything within 10 seconds, it explodes and the entity is removed
      • If the rocket hits the sky then the entity is removed (no explosion).
    6. Once the entity is removed, the slot is marked not inuse and may be re-used
    As you can see, a rocket's life is relatively short ! You might be thinking, is there a limit to the number of rockets that can simultaneously be flying around the map ? Well, yes.


    Time to do some sleuth work. By the way, when we refer to the quake 'world', we mean the game world and everything in it (not 'quakeworld'). What's in the quake world ? Lots of things... like a map, like the players, and like... ENTITIES ! Jump into MSVC and do a "Find in Files" on 'g_entities'. In g_main.c at line 17 we can find :
     gentity_t		g_entities[MAX_GENTITIES];
    This line says that there exists a finite array of entities in the game world. This array is called 'g_entities' and is MAX_GENTITIES long. So what is the constant MAX_GENTITIES ?? Do a "Find in Files" on MAX_GENTITIES and we find q_shared.h line 718 (and 717) to be quite interesting :
     #define	GENTITYNUM_BITS		10		// don't need to send any more
    Ok, Carmack is exhibiting some guru-level C syntax here. Take my word that (x << y) means to double x y times. Given that ENTITYNUM_BITS is 10, MAX_GENTITIES is therefore 2 to the power of 10, or 1024. In other words, there is room in the world for approximately 1024 rockets, players, weapons, armors etc at any one time.


    What would happen if you sat at one end of a very long space map with the RL and held down the fire button ? Assuming that your rockets fly for the full ten seconds, you can have about 10 rockets in the air at once. (Remember that when a rocket explodes the entity can be re-used by the next rocket virtually right away). If you start a 32 player game with your mates and you all sit and fire into space, there would be about 320 rockets flying through the air at any one time. We still haven't run out of entities...

    There is a certain number of entities that are permanently used during the whole game (for example, players, weapons and items). All other non-permanent entities follow the cycle create - live a short life - reuse. This is something to think about when you're coding mods - If you make a cluster grenade that splits into 100 mini grenades, then one idiot could quickly run your world out of entities by firing a bunch of cluster grenades in quick succession.

    What happens if your world runs out of entities ? Assume the worst-case scenario, that your server will crash. If an entity is going to exist for a relatively long time, make sure that it isn't possible for huge numbers of them to exist at the same time.


    Let's look at g_local.h, starting at line 49 :
    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;
    	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 w/o 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		watertype;
    	int		waterlevel;
    	int		noise_index;
    	// timing variables
    	float		wait;
    	float		random;
    	gitem_t		*item;	// for bonus items
    	qboolean	botDelayBegin;
    Right up the top there is some important stuff - an entityState_t and entityShared_t... these bits include general stuff like the location of the entity, the type of entity it is, the size of the bounding box, etc.

    Next comes struct gclient_s *client; - this is a pointer to additional information, if the entity is a 'client' (i.e. player or bot). If the entity is not a client, then this bit is NULL (unused).

    Further down we can see heaps of interesting fields - classname, speed, movedir, target, team etc. Not all of these fields are used with all entities... a red armor would not use the 'damage' fields, for example (wheras a rocket would). Most of these are pretty self-explanatory.


    Lines 110-116 in g_local.h define function pointers. The names of these are think, reached, blocked, touch, use, pain, die. Although the syntax here is very hardcore (remember, Carmack is a codecutting God), it's quite easy to explain with an example.

    We want our rockets to explode after 10 seconds. Remember, from g_missile.c :

    	bolt->nextthink = level.time + 10000;
    	bolt->think = G_ExplodeMissile;
    This means that after 10 seconds, the rocket 'thinks' and the function G_ExplodeMissile is called on the rocket entity. Similarly, a grenade explodes after 2.5 seconds. Can you find the code for this ? (Answer : g_missile.c line 294). 'Thinking' is a nice "fire and forget" mechanism - we create an entity, define what it does at some future time, and then forget about it - the game engine takes care of the entity from then on.

    10 times a second, the server checks if each entity is due to 'think'. If yes, the 'think' function is run for that entity. Similarly, other entity functions are called in response to certain events. If a player is killed, then the player_die function is called (see g_client.c line 921). The same goes for touch, blocked, pain, etc.


    In q_shared.h we see that the maximum number of clients (players or bots) - MAX_CLIENTS - is 128. By definition, the first MAX_CLIENTS entities in g_entities are reserved for clients. Arrays in C are numbered from 0, so g_entities[0] is reserved for client 0, g_entities[1] for client 1... up to g_entities[127] for player 127.

    Just as there exists an array of entities in the world, there also exists an array of 'client information' structures - see line 18 in g_main.c :

     gclient_t		g_clients[MAX_CLIENTS];
    Here we have an array of 128 gclient_t's (client information structures). And each of the first 128 g_entities point to a corresponding g_client[x]. For example, g_entities[0]->client points to g_clients[0], etc. We'll have a look at what's in the client information structure another time.

    Well, entities really do make the world go round (well, they actually go around the world, kinda... anyway...). Another time we'll talk about temporary entities (rail trails, blood spurts and similar effects). Till then, remember... "West Side."

    PlanetQuake | Code3Arena | Articles | Article 1 | Next >>