Looking at the Quake 3 Source -- Part 1
In case you're not aware (for example, you may have been living in a cave where the only internet is dial up access to a 3 month old backup of the google cache), the Quake 3 source is available for download, under the GPL. My initial impressions are good, given that when I looked at Q2 back in the day, I very nearly gave up hope of ever accomplishing anything. Things are for the most part well organized, categorized, and sensible. The id penchant for clumping a dozen header files into just one continues, but overall it's easy to find the code you're looking for. Hell, it took me 3 days to find the BSP code in Quake 2 because they had called it model_t or some such meaningless thing. I can see why Q3 was so popular for licensing, despite being in C. Is it perfect? Of course not. Naturally there are hacks here and there, and a few very weird design things...and the C versions of what would in C++ be inheritance and aggregation are hilarious. But it's not the horrible tangled mess we were all scared it could have been. Overall though, I think this code is going to go a lot farther than Q1 or Q2 source ever did. Compared to everything else out of id, this source is really quite nice. Most functions have documentation if it's not obvious what they do. All of the members of the major engine structs are well commented, for the most part. Now, there is still evidence of Carmack's "magic" at work. Long stretches of uncommented MMX assembly code. Really strange math code implementations at times, and occasionally stuff going on in the renderer that you have to stop and think about. Despite all that, the overall architecture is good. And I'll be poking around their architecture.
Before we go into the actual code, let's examine how Quake 3 is basically structured. No use looking at all the various structs if we don't know what they're for. So basically, every Quake and Quake based game since the beginning of time has revolved around the fundamental concept of an "entity". Everything in the game world is an entity. All the things you see -- the map, players, doors, items and weapons -- as well as plenty of things you don't see, are entities. Really, everything else that happens in the world is generated from the entities. All of the logic is controlled by interactions between the various entities. And when you're creating your own mods, the entities are what you'll really be working with the most. The core entity struct is the gentity_t, defined in code/game/g_local.h. I won't bother to replicate it here in its entirety, but let's take a look at what's in this thing. A quick glance through this struct will show that the lack of inheritance in C leaves its marks -- there are lots of things here that have no business being in a struct that represents every single object. That aside, I'll outline some of the most interesting members:
- classname -- Roughly speaking, the type of the object. It's basically a string that tells us what this is -- a player, a part of the map, etc.
- model, model2 -- The model (and alternate model) that this entity is rendered with. An invisible/non rendered entity wouldn't have an model associated with it.
- flags -- This variable contains a list of flags bit-ORed together to tweak behaviors. God mode, for example, is set here.
- physicsObject -- True if this is a movable object, false otherwise. The physics in Q3 is pretty damn simple, but there's great potential here (ODE or Novodex, somebody?).
- parent -- There's a crude scene hierarchy here; entities can be attached to other entities.
- speed, movedir -- This is our velocity. That's all we really need to update the object's position from frame to frame, since there's no real physics.
- health -- Well, straightforward, really. Not just for players; it can be used to destroy any entity you want when its health reaches 0.
- takedamage -- True if this is a thing that takes damage, dies, etc, false otherwise.
- item -- When you pick up a quad damage or other item, it goes here. Q3 had a weak item system...well, almost no item system at all. This is another location that might be useful to mess with.
- reached -- Happens when a "mover" entity reaches the end of its path.
- blocked -- Happens when an entity's path is blocked by something.
- touch -- Happens when an entity comes in contact with another entity. If you were writing a contact grenade or a rocket, you could use this to create an explosion.
- use -- Happens when the player presses the 'use' key on the entity. You could use this to create some sort of switch or button.
- pain -- Happens when the entity takes damage but isn't killed.
- die -- Happens when the entity gets killed.
- think -- Keep reading.
Anyway, I think that's quite enough for one blog post. Entities are the heart of Quake 3, and there's a lot to be gained by altering the base entity management. A lot of the code in code/game is concerned with working with entities; check out g_weapon.c for a lot of good examples of code that works with entities (specifically, weapon entities). Oh, and one last thing. If you're reading this, please, please leave a comment of some sort, preferably with suggestions of what to cover or what you did/didn't like. I'm a little unsure of where I'm going with this, and where people want me to go.