Player Identification Function

I have wanted to put together a player identification function for some time but the recent inquiries as to how to accomplish this seemed to have bumped it up on my priority list so I looked into it to see what it would take. Well, it wasn't that hard and really has alot of good uses!

How it works:

The player hits their aliased key and toggles their player ID to be 'enabled'. A message on their HUD lets them know that this has been enabled for them.. (This function remains enabled until they hit their aliased key again). So, you hit the same key ON/OFF.

Once enabled, all players will be identified which are 'infront' of the player's current position and within a 500 unit searching radius (which is pretty far!).
Once identified, useful information about that player will appear on your HUD like this:

WildMAN (88) at 378 units

Where 'WildMAN' is the player's name, (88) is their current health, and the '378 units' is their distance from you!
Good stuff to know if a frag fight (especially how healthy the other player is!). You can add other stuff to be displayed too! Whatever you think is information which is important given your particular mod's setup.
Okay, let's get started..

Add in the blue code and take out the pink code.
First, we need to add a new variable to your gclient_s struct.
So, at the bottom of that struct, add this:

int id_on; // 1=ON, 0=OFF

This will be used to toggle the ID Function ON/OFF.
Okay, go into InitClientPersistant() function in your p_client.c file and add this line near the bottom:

client->id_on=0; // default to OFF.

This will set the default to OFF each time the player enters the game..
Also in your p_client.c file, go into Player_Die() function and add this line to the bottom:

self->client->id_on=0; // Turn OFF.

This will turn off all the player's ID function when he dies..
Open up your g_cmds.c file and go near the bottom of your ClientCommand() function and add the following as shown by example.. Your selection of commands may differ, but just be sure to stick this one in there somewhere.

    else if (Q_stricmp(cmd, "decoy") == 0 )
        SP_Decoy(ent);
    else if (Q_stricmp(cmd, "drone") == 0 )
        Cmd_LaserDrone_f(ent);
    else if (Q_stricmp(cmd, "teleport") == 0)
        Cmd_Teleport_f(ent);
    else if (Q_stricmp(cmd, "id_on") == 0)
    {
        ent->client->id_on=abs(ent->client->id_on-1);
        ent->->touch_debounce_time = level.time + 5.0;
        gi.centerprintf(ent,"PLAYER ID %s!\n", ent->client->id_on<1 ? "OFF":"ON");
    }
    else if .....

This will toggle the ID function with a single stroke of
the player's aliased key and print a message to your HUD.

Lets open you g_weapons.c file and add these helper routines
and the baton's source code somewhere near the top of the file.

NOTE: I've used these helper routines in many of my previous
tutorials so you may already have them someplace in your source.
If you already do have them, then you don't need them anymore.
Your compiler should warn you that you've already got these
functions previously defined..

Okay, add the following text to the top of your g_weapons.c file.

//======================================================
// True if Ent is valid, has client, and edict_t inuse.
//======================================================
qboolean G_EntExists(edict_t *ent)
{
    return ((ent) && (ent->client) && (ent->inuse));
}

//======================================================
// True if ent is not DEAD or DEAD or DEAD (and BURIED!)
//======================================================
qboolean G_ClientNotDead(edict_t *ent)
{
    qboolean buried = true;
    qboolean b1 = ent->client->ps.pmove.pm_type!=PM_DEAD;
    qboolean b2 = ent->deadflag != DEAD_DEAD;
    qboolean b3 = ent->health > 0;
    return (b3||b2||b1) && (buried);
}

//======================================================
// True if ent is not DEAD and not just did a Respawn.
//======================================================
qboolean G_ClientInGame(edict_t *ent)
{
    if (!G_EntExists(ent))
        return false;
    if (!G_ClientNotDead(ent))
        return false;

    return (ent->client->respawn_time + 5.0 < level.time);
}

//======================================================
// True if start and end are within radius distance.
//======================================================
qboolean G_Within_Radius(vec3_t start, vec3_t end, float rad)
{
    vec3_t eorg = {0,0,0};
    int j;

    for (j=0; j<3; j++)
        eorg[j]=abs(start[j]-end[j]);
   
    return (VectorLength(eorg) < rad);
}

Lastly, open your p_client.c file and find your ClientThink() function..
At a point just above the ClientThink() function add this new function:

//=========================================================
void Player_Identification(edict_t *self)
{
    int i;
    int distance;
    edict_t *player;
    vec3_t forward;

    // Allow scanning to occur ONLY every 5 seconds..
    if (self->touch_debounce_time > level.time) return;

    // Don't allow Dead/Respawning players to enable ID..
    if (!G_ClientInGame(self))
    {
        self->client->id_on=0; // Turn OFF
        return;
    }

    for (i=0; i < game.maxclients; i++)
    {
        player = g_edicts + i + 1;

       
if (!G_ClientInGame(player))
            continue;
        if (self == player)
            continue;
        if (!G_Within_Radius(self->s.origin, player->s.origin, 500))
            continue;
        if (!infront(self, player))
            continue;

        VectorSubtract (self->s.origin, player->s.origin, forward);
        distance = (int)VectorLength(forward);
        gi.cprintf (self, PRINT_HIGH,"%s (%d) at %d units\n", player->client->pers.netname, player->health, distance);
    } // end for

    // Don't want to be a resouce hog for ClientThink!!
    self->touch_debounce_time = level.time + 5.0;
}

This routine will do the searching and identification processing.
Now, inside of you ClientThink() function we need to add a few lines as indicated:

void ClientThink(edict_t *ent, usercmd_t *ucmd)
{
    gclient_t *client;
    edict_t *other;
    int i, j;
    pmove_t pm;

    level.current_entity = ent;
    client = ent->client;

    if (level.intermissiontime)
    {
        client->ps.pmove.pm_type = PM_FREEZE;
        // can exit intermission after five seconds
        if (level.time > level.intermissiontime + 5.0 && (ucmd->buttons & BUTTON_ANY) )
            level.exitintermission = 1;
        return;
    }

    if (ent->client->id_on)
        Player_Identification(ent);

This will activate your player ID function if you've got your id_on enabled. Since this will happen each time the ClientThink() function is called for you (just about every couple of frames) I needed to put a debounce_timer at the top of the Player_Identification() function (as shown above) so that the ID'ing would not drain computer processing and lag the system!!

Lastly..
Be sure to add the following to your Autoexec.cfg file as shown by example..

bind i "id_on"

That's it!! Enable your new ID function and ID THE BASTARDS
BEFORE YOU KILL'EM!

Have Fun!!

Maj.Bitch