Quake DeveLS - THROW-UP GIB!

Author: SumFuka
Difficulty: Easy/Medium


Jarlaxe must've had meatballs for dinner

In tutorial 7 we made the quakedude throw up blood. Let's make him throw up some really chunky gibs. First open up g_misc.c and look at the ThrowGib function. We're going to copy this function and modify it so it does exactly what we want... throw up a very small red gib, and make it look like it comes out of the player's mouth. Let's call our new function ThrowVomit. Go to the very bottom of g_misc.c and enter the following code :

// STEVE added this function

void ThrowVomit (edict_t *ent, vec3_t mouth_pos, vec3_t forward, vec3_t right, vec3_t player_vel)
{
	edict_t *gib;

	gib = G_Spawn();

	gi.setmodel (gib, "models/objects/gibs/sm_meat/tris.md2");

	gib->solid = SOLID_NOT;
	gib->s.effects |= EF_GIB;
	gib->flags |= FL_NO_KNOCKBACK;
	gib->takedamage = DAMAGE_YES;
	gib->die = gib_die;

	gib->movetype = MOVETYPE_TOSS;
	gib->touch = gib_touch;

	// start the gib from out mouth, moving at a forwards velocity
	VectorCopy (mouth_pos, gib->s.origin);
	VectorScale (forward, 120 + crandom()*40, gib->velocity);
	VectorAdd (player_vel, gib->velocity, gib->velocity);

	// add a random left-right component to the vomit velocity
	VectorScale (right, crandom()*20, right);
	VectorAdd (right, gib->velocity, gib->velocity);

	gib->avelocity[0] = random()*600;
	gib->avelocity[1] = random()*600;
	gib->avelocity[2] = random()*600;

	gib->think = G_FreeEdict;
	gib->nextthink = level.time + 10 + random()*10;

	gi.linkentity (gib);
}
This function expects 5 parameters : the player that is throwing up (ent), the location of their mouth (mouth_pos), vectors forward and to the right of the player, and the player's velocity.

Spawning an entity in the world

That's exactly what the G_Spawn function does... it creates a new entity for us to play with. This new entity is 'blank' however and we must assign values to it's various parameters. The most important parameter is the model for the entity... in this case we are using a 'small meat' gib, located at "models/objects/gibs/sm_meat/tris.md2" in the pak file.

The next few lines set the various properties of the entity, for example, the solid property is 'SOLID_NOT', meaning it does not actually hinder the player's movement in the same way that a barrel does if you walk into it (you'd need a pretty big pile of gibs, but in theory you could block a whole hallway if you threw up a really BIG of 'em).

The other properties in capital letters are CONSTANTS, most of these are defined in q_shared.h. Look at line 503 in q_shared.h... EF_GIB and all the other entity effects are defined here. Have a look at the other types of constants in this file, the comments explain alot about what is available for you to program in the quake2 world.

The gib->die = gib_die line says that when the gib dies, the gib_die function (from g_misc.c) will be called. Similarly for gib_touch.

The VectorCopy line sets the origin of the gib entity to start at the player's mouth. The next VectorScale line gives the gib a velocity of 120 (plus a random amount plus or minus 40) directly forwards from the player. The VectorAdd line adds the player's velocity to the gib velocity, without this we could not do projectile vomiting (taking a runup and seeing how far you can throw your vomit.... yech.)

The second VectorScale line multiplies the 'right' vector by a random amount between -20 and +20. We add this to the gib vector to give it a sideways velocity.

Next we set the x,y,z components of the angular velocity for the gib (avelocity is a vector, so avelocity[0] is the x component). In case you haven't guessed already, crandom() returns a floating point number between -1 and 1 (centered random).

gib->think = G_FreeEdict; is an interesting line. It says that when the gib 'thinks' that it should call the G_FreeEdict function, and remove itself. And it thinks after 10 or so seconds from when it is created. Now remember that my code here is based on the ThrowGib function written (I assume) by John Carmack. Give him all the compliments for this awesome code !

the linkentity function puts the entity into the gameworld.

Let's use the ThrowVomit function !

First, lets add it to throwup.h. Edit throwup.h and make it look like this :

// THROWUP.H

// main function
void ThrowUpNow(edict_t *self);

// utility function in g_misc.c
void ThrowVomit (edict_t *ent, vec3_t mouth_pos, vec3_t forward, vec3_t right, vec3_t player_vel);
Now go to throwup.c, and edit the last few lines of ThrowUpNow so that it looks like this :

	// also do a spewing sound
	gi.sound (self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);

	// cough up some gibs.
	for (i = 0; i<3; i++) {
		ThrowVomit (self, mouth_pos, forward, right, self->velocity);
	}

	// every now and again, cough up MEGA vomit
	if (random() < 0.1)
	{
		for (i = 0; i<10; i++) {
			ThrowVomit (self, mouth_pos, forward, right, self->velocity);
		}
	}
}
Vomit, Chuck, Hurl.

Same drill as in tutorial 7 : to use this mod, compile the gamex86.dll and go into quake2. Now type this at the console :

	bind h "give throwup"

Now hit h and run around throwing up all over your friends... and this time you have chunky bits ! (no carrots though...)

Next week, let's do something less disgusting...

Tutorial by SumFuka


This site, and all content and graphics displayed on it,
are ©opyrighted to the Quake DeveLS team. All rights received.
Got a suggestion? Comment? Question? Hate mail? Send it to us!
Oh yeah, this site is best viewed in 16 Bit or higher, with the resolution on 800*600.
Thanks to Planet Quake for there great help and support with hosting.
Best viewed with Netscape 4 or IE 3