
Quake DeveLS - The Morgue
Author: SumFuka
Difficulty: Easy
Before we get to the real
fun, I'd like to mention a tip that Christian Wilson gave to me. In the process
of writing a Quake 2 mod, I find myself switching between the compiler and
quake2 quite often. His tip is that you can actually leave quake OPEN whilst
you recompile the gamex86.dll ! This saves lots of time. Here are the steps,
and we will be using a 'game' directory here as well.
Now that know how to
compile a gamex86.dll successfully in our own quake2 game directory and modify
one of the source files, lets do some serious more programming. Lets look at
the ClientObituary function in p_client.c (line 70).
void ClientObituary (edict_t *self, edict_t *inflictor, edict_t
*attacker)
What does
this mean ? When you get killed, this function is called. Three variables
(self, inflictor, attacker) are passed into the function, almost exactly like
the old QuakeC days ! (ahhhhh... I get all nostalgic...)
These variables are of a
certain type : "edict_t *"
edict_t *
???
Let's read "edict_t
*" as "a pointer to a world entity". Ok, so "self" is
a "pointer to a world entity". In other words, self is YOU (well, you
died right ?) in the quake2 world. "inflictor" is a pointer to
another entity in the world probably the rocket or bullet that finished you
off. And "attacker" is also an entity... most probably a player
entity (the dude who polished your ass). Get used to using
"edict_t"... everything in quake2 is based on an edict_t !
How do we use this
information ? Well all edict_t variables in quake2 have a classname. We can use
this, for example, to find out HOW we were killed. Lets change lines 81-86 of
p_client.c from this :
if (attacker && attacker->client) { gi.bprintf (PRINT_MEDIUM,"%s was killed by %s\n", self->client->pers.netname, attacker->client->pers.netname); attacker->client->resp.score++; return; }
to this :
if (attacker && attacker->client) { if (!strcmp(inflictor->classname, "grenade")) { // killed by grenade gi.bprintf (PRINT_MEDIUM,"%s plays 'catch the thermal detonator' with %s\n", self->client->pers.netname, attacker->client->pers.netname); } else if (!strncmp(3, inflictor->classname, "bfg")) { // killed by bfg gi.bprintf (PRINT_MEDIUM,"%s was made F.U.B.A.R by %s\n", self->client->pers.netname, attacker->client->pers.netname); } else if (!strcmp(inflictor->classname, "player")) { // killed by shotty gi.bprintf (PRINT_MEDIUM,"%s was blown away by %s\n", self->client->pers.netname, attacker->client->pers.netname); } else { // can't figure out how we were killed gi.bprintf (PRINT_MEDIUM,"%s was killed by %s\n", self->client->pers.netname, attacker->client->pers.netname); } attacker->client->resp.score++; return; }
String comparisons in C...
Ok string comparisons in c
are done using the strcmp function. strcmp returns "false" (0) if the
strings ARE the same, so we need to negate the result to determine when two
strings ARE the same by using the NOT (!) operator. So
!strcmp("steve","steve") returns "true" (1). And,
!strcmp(inflictor->classname, "grenade") determines if the
inflictor was a grenade.
Who killed
me ? HOW ?...
So the code above simply
looks at the classname of the inflictor and gives a different deathmessage
based on that. Simple ! Unfortunately, the laser weapons and the rocketlauncher
do not properly identify the inflictor (the inflictor classname is
"noname"). This may be fixed by John Carmack, or maybe there is
another attribute of the inflictor that we should be looking at ?
One way to tell if we were
killed by the rl or hyperblaster is to look at
attacker->client->pers.weapon->classname, but if someone fires a
rocket at you and switches to another weapon, it will say you were killed by
the weapon they are holding, not the weapon they fired. Oh well. I'll try and
hack the weapons fire functions so that laser bolts and rockets are properly
identified. Later maybe.
More
messages !
If you're really keen try
this out... first add two lines to the very start of your ClientObituary
function... (you must put new local variables at the start of the function in
C... this variable is "local" because we only need it for temporary
use within this function)
void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker){ double rnum; rnum = rand();
Now change
the death messages we just changed before to look like this :
if (!strcmp(inflictor->classname, "grenade")) { // killed by grenade if (rnum < 0.5) gi.bprintf (PRINT_MEDIUM,"%s plays 'catch the thermal detonator' with %s\n", self->client->pers.netname, attacker->client->pers.netname); else gi.bprintf (PRINT_MEDIUM,"%s ate %s's atomic apple.\n", self->client->pers.netname, attacker->client->pers.netname); } else if (!strncmp(inflictor->classname, "bfg", 3)) { // killed by bfg if (rnum < 0.33) gi.bprintf (PRINT_MEDIUM,"%s was made F.U.B.A.R by %s.\n", self->client->pers.netname, attacker->client->pers.netname); else if (rnum < 0.67) gi.bprintf (PRINT_MEDIUM,"%s bows to the almighty power of %s's BFG !\n", self->client->pers.netname, attacker->client->pers.netname); else gi.bprintf (PRINT_MEDIUM,"%s is taught to fear the color of green by %s\n", self->client->pers.netname, attacker->client->pers.netname); } else if (!strcmp(inflictor->classname, "player")) { // killed by shotty if (rnum < 0.5) gi.bprintf (PRINT_MEDIUM,"%s was blown away by %s\n", self->client->pers.netname, attacker->client->pers.netname); else gi.bprintf (PRINT_MEDIUM,"%s eats %s's lead\n", self->client->pers.netname, attacker->client->pers.netname); } else { // can't figure out how we were killed if (rnum < 0.5) gi.bprintf (PRINT_MEDIUM,"%s was killed by %s's %s\n", self->client->pers.netname, attacker->client->pers.netname, inflictor->classname); else gi.bprintf (PRINT_MEDIUM,"%s was put out of their misery by %s\n", self->client->pers.netname, attacker->client->pers.netname); }
That's it
! Go and frag with your friends... the messages should be remotely more
interesting...
STAY TUNED ! Next week....
WEAPONS ! (ah ah ah hah ah ahhhhh ! mmmm ! yummmy !)
Tutorial by SumFuka
|
This
site, and all content and graphics displayed on it, |