• Register

DarkPlaces is a Quake modification I have built over the course of 6 years on and off experimenting, it got somewhat of an overhaul when the Quake engine source code was released, and I began developing a custom OpenGL-only engine for it and other mods, which supports Windows WGL and Linux GLX, and has greatly improved graphics and image quality. It can not easily be described, as it is simply an improved Quake, not a total conversion (yet, anyway). The realism of shell casings falling to the floor, much improved bullet impacts, 32bit color alpha blended explosions, blood flying everywhere and sticking to the walls... Behind the scenes the code has changed a great deal, I was not content with the original QuakeC code, and I have greatly changed the engine while maintaining compatibility with normal quake modifications. LordHavoc

Post tutorial Report RSS Quake c - .think() and .nextthink

The quake-c entity .think() function pointer is an engine managed timing concept that is used on nearly every entity in the game.

Posted by on - Basic Server Side Coding

What is .think() ?

The quake-c definition is found in "defs.qc":

.void() think;
.float nextthink;

If you peruse: Moddb.com , you realize ".think()" is a per-entity stored pointer to some function call and ".nextthink" is a float number.

What do they do?

These variables are set by quake-c code, and controlled by the engine. The concept is simple, however, the effect on quake-c coding is profound.

A function call value is assigned to ".think". Then ".nextthink" is assigned some time value in the future.
The server accumulates the current time in seconds as a global variable "time". Each iteration (server tick) every entities ".nextthink" value is compared to "time". While ".nextthink" is greater than "time" nothing occurs.

When ".nextthink" becomes less than or equal to time (since time is always accumulating value), the engine causes the function in ".think()" to be called during the next quake-c operation.

Three things are required to use this timer concept:

1. A valid entity.
2. A valid function pointer stored in ".think()"
3. A time value greater than the current global "time" stored in ".nextthink"

Here is an example from "misc.qc":

void () misc_fireball =
{
precache_model ("progs/lavaball.mdl");
self.classname = "fireball";
self.nextthink = time + (random() * 5);
self.think = fire_fly;
if (!self.speed)
self.speed = 1000; // Cataboligne 9.17.3 - fixed this compiler warning
};

"misc_fireball" is a map spawn function. It creates a lavaball launcher. These are often found in lava pools. The quake start map has a couple in the hall leading to episode 3.

What this code does is tells the server to make a function call to "fire_fly" with the launcher entity assigned to the "self" pointer in current "time" + 0 - 5 seconds. The launcher then fires off a lava ball and reloads ".nextthink" with some future time value. This think continues until the map is ended.

If you look through quake-c code you will find many instances of ".think()" used to control elements of game flow. It is not necessary to have an entity that is visible in game. Non model entities can be set up as timers (like the example above, the launcher is invisible, having no model assigned. The precache is so the lavaball model can be used for launches later.)

".think()" is used for monster ai, mega health rot, environmental effects, artifact countdown, and many other game elements.

The possibilities of this timer control method are almost limitless in quake-c. The brilliance of the ".think()" concept is code can be run exactly when needed and continuous loops and constant checks are not needed every quake-c operation.

The biggest code fault associated with ".think()" is failing to assign ".nextthink" a proper value:

self.nextthink = 10; // this will only happen at 10 seconds after map load. It does not add 10 seconds to "time"

self.nextthink = time + 10; // this will cause a ".think()" to happen every 10 seconds

You are now ready to code up some "thinking" entities!

Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: