3794 lines
81 KiB
C
3794 lines
81 KiB
C
|
|
#include "g_local.h"
|
|
#include "m_player.h"
|
|
|
|
#include "voice_punk.h"
|
|
#include "voice_bitch.h"
|
|
|
|
//------------------------------------------------------------------------------------
|
|
|
|
edict_t *ban_target, *ban_source, *ban_thinker;
|
|
int ban_count;
|
|
char ban_ip[MAX_QPATH]; // make sure we don't kick a different user
|
|
float last_ban_time;
|
|
char ban_id; // so we only allow each person to vote once per ban
|
|
char last_kick_ip[MAX_QPATH];
|
|
int ban_player_count=0;
|
|
|
|
void Cmd_Players_f (edict_t *ent);
|
|
|
|
qboolean BanEnoughVotes(void)
|
|
{
|
|
edict_t *trav;
|
|
int need;
|
|
|
|
trav = &g_edicts[1];
|
|
|
|
while (trav <= &g_edicts[(int)maxclients->value])
|
|
{
|
|
if (trav->inuse && trav->client /*&& (trav != ban_target)*/
|
|
&& (!teamplay->value || !ban_target->client || !ban_target->client->pers.team || (ban_target->client->pers.team == trav->client->pers.team)))
|
|
{
|
|
ban_player_count++;
|
|
}
|
|
|
|
trav++;
|
|
}
|
|
|
|
// if (teamplay->value)
|
|
// need = (int)floor(ban_player_count / 2);
|
|
// else
|
|
need = (int)ceil(ban_player_count / 2);
|
|
|
|
if (need < 3)
|
|
need = 3;
|
|
|
|
return (ban_count >= need);
|
|
}
|
|
|
|
void BanThink(edict_t *ent)
|
|
{
|
|
char *ip;
|
|
|
|
if (!ban_target || !ban_target->inuse || !ban_target->client)
|
|
{
|
|
ban_target = NULL;
|
|
G_FreeEdict(ent);
|
|
return;
|
|
}
|
|
|
|
if (ban_id != ent->count)
|
|
{
|
|
// another ban has formed
|
|
G_FreeEdict(ent);
|
|
return;
|
|
}
|
|
|
|
// check the IP is the same
|
|
ip = Info_ValueForKey( ban_target->client->pers.userinfo, "ip" );
|
|
if (ip && ip[0])
|
|
{
|
|
if (strcmp(ip, ban_ip))
|
|
{
|
|
ban_target = NULL;
|
|
G_FreeEdict(ent);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if we have enough, cancel the kick request
|
|
if (!BanEnoughVotes())
|
|
{
|
|
if (ban_source->inuse)
|
|
gi.cprintf( ban_source, PRINT_HIGH, "Vote did not succeed.\n" );
|
|
ban_target = NULL;
|
|
G_FreeEdict(ent);
|
|
return;
|
|
}
|
|
|
|
// kick them
|
|
gi.bprintf( PRINT_HIGH, "%s was kicked by unanimous vote (next time they will be banned).\n", ban_target->client->pers.netname );
|
|
|
|
if (!strcmp(ban_ip, last_kick_ip))
|
|
{ // ban them
|
|
gi.bprintf( PRINT_HIGH, "Blocking %s from returning to game.\n", ban_target->client->pers.netname );
|
|
gi.AddCommandString(va("sv addip %s\n", ban_ip));
|
|
}
|
|
|
|
gi.AddCommandString(va("kick %i\n", (int)(ban_target - g_edicts - 1)));
|
|
|
|
strcpy( last_kick_ip, ban_ip );
|
|
|
|
ban_target = NULL;
|
|
G_FreeEdict(ent);
|
|
}
|
|
|
|
void Cmd_Response_f (edict_t *ent)
|
|
{
|
|
char *ip;
|
|
|
|
if (!ban_target)
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "Nothing to \"%s\" with.\n", gi.argv(0) );
|
|
return;
|
|
}
|
|
|
|
if (ent == ban_target)
|
|
return;
|
|
|
|
if (ent->client->resp.ban_id == ban_id)
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "You've already voted once.\n" );
|
|
return;
|
|
}
|
|
|
|
if (!ban_target->inuse || !ban_target->client)
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "The player has already left.\n" );
|
|
ban_target = NULL;
|
|
return;
|
|
}
|
|
|
|
if (teamplay->value && ban_target->client->pers.team && (ban_target->client->pers.team != ent->client->pers.team))
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "You cannot vote, %s is not on your team.\n", ban_target->client->pers.netname );
|
|
return;
|
|
}
|
|
|
|
// don't let us vote if we were just kicked
|
|
ip = Info_ValueForKey( ent->client->pers.userinfo, "ip" );
|
|
if (ip && ip[0])
|
|
{
|
|
if (!strcmp(ip, last_kick_ip))
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "You cannot vote.\n" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
ip = Info_ValueForKey( ban_target->client->pers.userinfo, "ip" );
|
|
if (!ip)
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "%s has an unknown IP address\n", ban_target->client->pers.netname );
|
|
ban_target = NULL;
|
|
return;
|
|
}
|
|
if (strcmp(ip, ban_ip))
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "The player has left or been replaced with another player\n" );
|
|
ban_target = NULL;
|
|
return;
|
|
}
|
|
|
|
if (!strcmp(gi.argv(0), "no"))
|
|
{
|
|
if (ban_source->inuse)
|
|
gi.cprintf( ban_source, PRINT_HIGH, "The vote did not succeed.\n" );
|
|
|
|
gi.cprintf(ent, PRINT_HIGH, "Objection noted.\n" );
|
|
|
|
ent->client->resp.ban_id = ban_id;
|
|
ban_count--;
|
|
return;
|
|
}
|
|
|
|
ent->client->resp.ban_id = ban_id;
|
|
ban_count++;
|
|
|
|
if (BanEnoughVotes())
|
|
{
|
|
ban_thinker->think(ban_thinker);
|
|
}
|
|
else
|
|
{
|
|
gi.cprintf(ent, PRINT_HIGH, "Vote recorded, awaiting votes from other players.\n" );
|
|
}
|
|
|
|
}
|
|
|
|
void Vote_Ban( edict_t *ent, char *name )
|
|
{
|
|
edict_t *target;
|
|
int i;
|
|
char *ip;
|
|
|
|
if (ent->client->resp.last_ban && (ent->client->resp.last_ban > (level.time - 60)))
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "You can only VOTE once per 60 seconds\n" );
|
|
return;
|
|
}
|
|
|
|
if (last_ban_time)
|
|
{
|
|
if (last_ban_time > level.time)
|
|
{
|
|
last_ban_time = 0;
|
|
}
|
|
|
|
if (last_ban_time > (level.time - 20))
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "Only one VOTE per 20 seconds allowed\n" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
// find the player
|
|
if (((i = atoi(name)) > 0) && i <= maxclients->value)
|
|
{
|
|
if (!g_edicts[i].inuse || !g_edicts[i].client)
|
|
{ // fail
|
|
gi.cprintf( ent, PRINT_HIGH, "\nUnable to match id '%i' with a current player.\n\nValid player id's are:\n\n", i );
|
|
Cmd_Players_f(ent);
|
|
return;
|
|
}
|
|
|
|
target = &g_edicts[i];
|
|
}
|
|
else // scan for the name
|
|
{
|
|
for (i=1; i<=maxclients->value; i++)
|
|
{
|
|
target = &g_edicts[i];
|
|
|
|
if (!target->inuse)
|
|
continue;
|
|
if (!target->client)
|
|
continue;
|
|
|
|
if (!Q_strcasecmp( target->client->pers.netname, name ))
|
|
break;
|
|
}
|
|
|
|
if (i>maxclients->value)
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "\nUnable to match '%s' with a current player.\n\nTry using a player id from the following list (eg. 'vote ban 4'):\n\n", name );
|
|
Cmd_Players_f(ent);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// can't kick someone on the other team
|
|
if (teamplay->value && target->client->pers.team && (target->client->pers.team != ent->client->pers.team))
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "You cannot kick a member of the other team.\n" );
|
|
return;
|
|
}
|
|
|
|
|
|
// vote for them
|
|
ip = Info_ValueForKey( target->client->pers.userinfo, "ip" );
|
|
if (!ip || !ip[0])
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "%s has an unknown IP address\n", name );
|
|
return;
|
|
}
|
|
if (!strcmp(ip, "loopback"))
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "%s is running the server, cannot BAN host\n", name );
|
|
return;
|
|
}
|
|
|
|
strcpy( ban_ip, ip );
|
|
|
|
ent->client->resp.ban_id = ++ban_id;
|
|
ent->client->resp.last_ban = level.time;
|
|
last_ban_time = level.time;
|
|
ban_count = 1;
|
|
|
|
ban_source = ent;
|
|
ban_target = target;
|
|
|
|
gi.cprintf( ent, PRINT_HIGH, "You have voted to kick/ban %s.\nAwaiting responses from other players.\n", ban_target->client->pers.netname );
|
|
|
|
gi.dprintf( "%s formed a vote to kick/ban %s.\n", ent->client->pers.netname, ban_target->client->pers.netname );
|
|
|
|
// start the thinker
|
|
target = G_Spawn();
|
|
target->owner = ban_target;
|
|
target->think = BanThink;
|
|
target->nextthink = level.time + 15;
|
|
target->count = ban_id;
|
|
|
|
ban_thinker = target;
|
|
|
|
BanEnoughVotes();
|
|
|
|
// now tell everyone except this player
|
|
for (i=1; i<=(int)maxclients->value; i++)
|
|
{
|
|
if (!g_edicts[i].client)
|
|
continue;
|
|
if (!g_edicts[i].inuse)
|
|
continue;
|
|
if (&g_edicts[i] == ent)
|
|
continue;
|
|
if (&g_edicts[i] == ban_target)
|
|
continue;
|
|
if (teamplay->value && ban_target->client->pers.team && (ban_target->client->pers.team != g_edicts[i].client->pers.team))
|
|
continue;
|
|
|
|
gi.cprintf( &g_edicts[i], PRINT_CHAT, ">> %s has voted to BAN %s. Type 'yes' in the consol if you agree, 'no' if you disagree. %i votes required.", ent->client->pers.netname, ban_target->client->pers.netname, ban_player_count );
|
|
}
|
|
}
|
|
|
|
void Cmd_Vote_f (edict_t *ent)
|
|
{
|
|
char *cmd, *name;
|
|
|
|
cmd = gi.argv(1);
|
|
|
|
if (!strcmp( cmd, "ban" ))
|
|
{
|
|
name = gi.argv(2);
|
|
|
|
if (!name[0])
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "You must supply a name\n" );
|
|
return;
|
|
}
|
|
|
|
Vote_Ban( ent, name );
|
|
}
|
|
else
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "Unknown voting command.\n" );
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------
|
|
|
|
// BEGIN: Xatrix/Ridah/Navigator/23-mar-1998
|
|
int showpath_on=false;
|
|
edict_t *showpath_ent;
|
|
|
|
void Cmd_NavDebugDest_f (edict_t *ent)
|
|
{
|
|
if (deathmatch->value)
|
|
{
|
|
gi.cprintf(ent, PRINT_HIGH, "This command only available when deathmatch = 0\n");
|
|
return;
|
|
}
|
|
|
|
if (!showpath_ent)
|
|
{ // spawn it
|
|
showpath_ent = G_Spawn();
|
|
showpath_ent->s.modelindex = 255;
|
|
}
|
|
|
|
VectorCopy( ent->s.origin, showpath_ent->s.origin );
|
|
gi.linkentity(showpath_ent);
|
|
}
|
|
|
|
void Cmd_NavDebugShowPath_f (edict_t *ent)
|
|
{
|
|
if (deathmatch->value)
|
|
{
|
|
gi.cprintf(ent, PRINT_HIGH, "This command only available when deathmatch = 0\n");
|
|
return;
|
|
}
|
|
/*
|
|
if (!ent->nav_build_data)
|
|
{
|
|
gi.cprintf(ent, PRINT_HIGH, "nav_dynamic 1 must be set to use this command\n");
|
|
return;
|
|
}
|
|
*/
|
|
if (!(showpath_on))
|
|
{ // enable path
|
|
|
|
// if (!ent->nav_build_data->debug_dest)
|
|
{ // create it
|
|
Cmd_NavDebugDest_f (ent);
|
|
}
|
|
|
|
showpath_on = true;
|
|
// ent->nav_build_data->flags |= NBD_SHOWPATH;
|
|
}
|
|
else // disable path
|
|
{
|
|
showpath_on = false;
|
|
// ent->nav_build_data->flags &= ~NBD_SHOWPATH;
|
|
|
|
// kill the destination entity
|
|
G_FreeEdict(showpath_ent);
|
|
showpath_ent = NULL;
|
|
}
|
|
}
|
|
|
|
// Clears the nav_data for the current level
|
|
void Cmd_NavClear_f ( edict_t *self )
|
|
{
|
|
if (deathmatch->value)
|
|
{
|
|
gi.cprintf(self, PRINT_HIGH, "This command only available when deathmatch = 0\n");
|
|
return;
|
|
}
|
|
|
|
// clear the current nodes
|
|
level.node_data->modified = false;
|
|
NAV_PurgeActiveNodes ( level.node_data );
|
|
|
|
// create the node data structure
|
|
level.node_data = gi.TagMalloc (sizeof (active_node_data_t), TAG_GAME);
|
|
NAV_InitActiveNodes ( level.node_data );
|
|
NAV_WriteActiveNodes ( level.node_data, level.mapname );
|
|
|
|
gi.AddCommandString( "echo \necho Cleared Navigational Data, closing down server.\necho \ndisconnect\n" );
|
|
}
|
|
|
|
// END: Xatrix/Ridah/Navigator/23-mar-1998
|
|
|
|
//--------------------------------------------------------
|
|
// TEAMPLAY commands
|
|
extern void ClientBeginDeathmatch (edict_t *ent);
|
|
|
|
void Cmd_Spec_f (edict_t *self)
|
|
{
|
|
if (!teamplay->value)
|
|
{
|
|
gi.cprintf(self, PRINT_HIGH, "This command only available when teamplay is enabled\n");
|
|
return;
|
|
}
|
|
|
|
if (!self->client->pers.team)
|
|
return;
|
|
|
|
self->client->pers.team = 0;
|
|
|
|
self->flags &= ~FL_GODMODE;
|
|
self->health = 0;
|
|
meansOfDeath = MOD_SUICIDE;
|
|
player_die (self, self, self, 1, vec3_origin, 0, 0);
|
|
|
|
ClientBeginDeathmatch( self );
|
|
}
|
|
|
|
void Cmd_Join_f (edict_t *self, char *teamcmd)
|
|
{
|
|
int i;
|
|
char str1[MAX_QPATH], varteam[MAX_QPATH];
|
|
|
|
if (!teamplay->value)
|
|
{
|
|
gi.cprintf(self, PRINT_HIGH, "This command only available when teamplay is enabled\n");
|
|
return;
|
|
}
|
|
|
|
strcpy( varteam, teamcmd );
|
|
|
|
// search for the team-name
|
|
|
|
if (varteam && varteam[0])
|
|
{
|
|
for (i=1; team_names[i]; i++)
|
|
{
|
|
strcpy(str1, team_names[i]);
|
|
kp_strlwr(str1);
|
|
kp_strlwr(varteam);
|
|
|
|
if (strstr( str1, varteam ) == str1)
|
|
{ // found a match
|
|
|
|
if (self->client->pers.team == i)
|
|
{
|
|
gi.cprintf( self, PRINT_HIGH, "Already a member of %s\n", team_names[i] );
|
|
}
|
|
else
|
|
{
|
|
// kill us if currently in game
|
|
if (self->client->pers.team)
|
|
{
|
|
self->flags &= ~FL_GODMODE;
|
|
self->health = 0;
|
|
meansOfDeath = MOD_SUICIDE;
|
|
player_die (self, self, self, 1, vec3_origin, 0, 0);
|
|
}
|
|
|
|
if (!Teamplay_ValidateJoinTeam( self, i ))
|
|
{
|
|
gi.cprintf( self, PRINT_HIGH, "Unable to join %s\n", team_names[i] );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
gi.cprintf( self, PRINT_HIGH, "Un-matched team: %s\n", varteam );
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
|
|
void Cmd_GetTexture_f (edict_t *self)
|
|
{
|
|
vec3_t start, end;
|
|
vec3_t fwd;
|
|
trace_t tr;
|
|
|
|
if (deathmatch->value)
|
|
{
|
|
gi.cprintf(self, PRINT_HIGH, "This command only available when deathmatch = 0\n");
|
|
return;
|
|
}
|
|
|
|
// trace a line and print the texture we hit
|
|
AngleVectors( self->client->v_angle, fwd, NULL, NULL );
|
|
VectorCopy( self->s.origin, start );
|
|
start[2] += self->viewheight;
|
|
|
|
VectorMA( start, 2048, fwd, end );
|
|
|
|
tr = gi.trace( start, NULL, NULL, end, self, MASK_SOLID - CONTENTS_MONSTER );
|
|
|
|
if (tr.fraction < 1 && tr.surface && tr.surface->name)
|
|
{
|
|
if (tr.surface->value > ((int)(level.time*10) - 3))
|
|
{
|
|
gi.cprintf( self, PRINT_HIGH, "Saving texture: %s\n", tr.surface->name );
|
|
|
|
{
|
|
cvar_t *game_dir, *base_dir;
|
|
char filename[MAX_QPATH], dir[MAX_QPATH];
|
|
FILE *f;
|
|
|
|
game_dir = gi.cvar("game", "", 0);
|
|
base_dir = gi.cvar("basedir", "", 0);
|
|
|
|
// dir, eg: .\main\maps
|
|
strcpy( dir, base_dir->string);
|
|
strcat( dir, DIR_SLASH);
|
|
|
|
strcat( dir, "source");
|
|
strcat( dir, DIR_SLASH);
|
|
strcat( dir, "ref_gl");
|
|
|
|
// filename, eg: .\main\maps\skidrow.pnt
|
|
strcpy( filename, dir);
|
|
strcat( filename, DIR_SLASH);
|
|
strcat( filename, "specular_textures.h");
|
|
|
|
// try and open the file for writing
|
|
f = fopen ( filename, "a+b");
|
|
if (!f)
|
|
{
|
|
gi.cprintf ( self, PRINT_HIGH, "Couldn't open %s for writing.\n", filename);
|
|
return;
|
|
}
|
|
|
|
fprintf( f, "\"%s\",\n", tr.surface->name );
|
|
|
|
fclose( f );
|
|
|
|
gi.cprintf ( self, PRINT_HIGH, "Saved.\n" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gi.cprintf( self, PRINT_HIGH, "Hit texture: %s\n", tr.surface->name );
|
|
}
|
|
|
|
tr.surface->value = (int)(level.time*10);
|
|
}
|
|
}
|
|
|
|
void Cmd_GearUp_f (edict_t *self)
|
|
{
|
|
vehicle_t *vehicle;
|
|
|
|
if (!self->vehicle_index)
|
|
{
|
|
gi.cprintf( self, PRINT_HIGH, "You aren't in a vehicle, can't change gears.\n");
|
|
return;
|
|
}
|
|
|
|
vehicle = &global_vehicles[self->vehicle_index - 1];
|
|
|
|
vehicle->gear++;
|
|
if (vehicle->gear == vehicle->def->gearbox->num_gears)
|
|
vehicle->gear--;
|
|
|
|
}
|
|
|
|
void Cmd_GearDown_f (edict_t *self)
|
|
{
|
|
vehicle_t *vehicle;
|
|
|
|
if (!self->vehicle_index)
|
|
{
|
|
gi.cprintf( self, PRINT_HIGH, "You aren't in a vehicle, can't change gears.\n");
|
|
return;
|
|
}
|
|
|
|
vehicle = &global_vehicles[self->vehicle_index - 1];
|
|
|
|
vehicle->gear--;
|
|
if (vehicle->gear < 0)
|
|
vehicle->gear = vehicle->def->gearbox->num_gears - 1;
|
|
}
|
|
|
|
// Saves the current LightPaint data
|
|
void Cmd_BurnSave_f (edict_t *self)
|
|
{
|
|
cvar_t *game_dir, *base_dir;
|
|
char filename[MAX_QPATH], dir[MAX_QPATH];
|
|
int i;
|
|
FILE *f;
|
|
|
|
if (deathmatch->value)
|
|
{
|
|
gi.cprintf(self, PRINT_HIGH, "This command only available when deathmatch = 0\n");
|
|
return;
|
|
}
|
|
|
|
game_dir = gi.cvar("game", "", 0);
|
|
base_dir = gi.cvar("basedir", "", 0);
|
|
|
|
// dir, eg: .\main\maps
|
|
strcpy( dir, base_dir->string);
|
|
strcat( dir, DIR_SLASH);
|
|
|
|
if (strlen(game_dir->string) == 0)
|
|
strcat( dir, "main");
|
|
else
|
|
strcat( dir, game_dir->string);
|
|
|
|
strcat( dir, DIR_SLASH);
|
|
strcat( dir, "maps");
|
|
|
|
// filename, eg: .\main\maps\skidrow.pnt
|
|
strcpy( filename, dir);
|
|
strcat( filename, DIR_SLASH);
|
|
strcat( filename, level.mapname);
|
|
strcat( filename, ".pnt");
|
|
|
|
// try and open the file for writing
|
|
f = fopen ( filename, "a+b");
|
|
if (!f)
|
|
{
|
|
gi.cprintf ( self, PRINT_HIGH, "Couldn't open %s for writing.\n", filename);
|
|
return;
|
|
}
|
|
|
|
for (i=0; i<num_lpbuf; i++)
|
|
{
|
|
fwrite( lpbuf[i], LP_SIZE, 1, f );
|
|
|
|
free( lpbuf[i] );
|
|
}
|
|
|
|
num_lpbuf = 0;
|
|
|
|
fclose( f );
|
|
|
|
gi.cprintf ( self, PRINT_HIGH, "Saved LightPaint to %s.\n", filename);
|
|
}
|
|
|
|
#if 0 // turn this off once we have the tables (not used by actual game code)
|
|
|
|
//-------------------------------------------------------------
|
|
// Ridah, only used to calculate the new x_anorms.h
|
|
void Cmd_Anorms_f (void)
|
|
{
|
|
#define NUM_PITCH_STEPS 8
|
|
|
|
vec3_t angles;
|
|
int step, yawstep;
|
|
int step_sections[9] = {32,28,24,20,16,12,8,4};
|
|
|
|
vec3_t out_normals[256];
|
|
int count=0;
|
|
|
|
if (maxclients->value > 1)
|
|
return;
|
|
|
|
VectorClear( angles );
|
|
|
|
// do the positive pitch step
|
|
for (step=0; step < NUM_PITCH_STEPS; step++)
|
|
{
|
|
|
|
angles[PITCH] = ((90.0 / NUM_PITCH_STEPS) * (float)step);
|
|
|
|
// go around the Z axis
|
|
|
|
for (yawstep=0; yawstep < step_sections[step]; yawstep++)
|
|
{
|
|
|
|
angles[YAW] = ((360.0 / step_sections[step]) * (float)yawstep);
|
|
|
|
AngleVectors( angles, out_normals[count++], NULL, NULL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// do the negative pitch step
|
|
for (step=1; step < NUM_PITCH_STEPS; step++)
|
|
{
|
|
|
|
angles[PITCH] = ((90.0 / NUM_PITCH_STEPS) * (float)(-step));
|
|
|
|
// go around the Z axis
|
|
|
|
for (yawstep=0; yawstep < step_sections[step]; yawstep++)
|
|
{
|
|
|
|
angles[YAW] = ((360.0 / step_sections[step]) * (float)yawstep);
|
|
|
|
AngleVectors( angles, out_normals[count++], NULL, NULL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gi.dprintf( "Anorm calculation completed, %i normals produced\n", count );
|
|
|
|
{
|
|
char filename[MAX_QPATH];
|
|
int i;
|
|
char str[256];
|
|
FILE *f;
|
|
|
|
// filename, eg: .\gamedir\routes\map01.nav
|
|
strcpy( filename, "\\kingpin\\source\\ref_gl\\x_anorms.h");
|
|
|
|
// try and open the file for writing
|
|
f = fopen ( filename, "wb");
|
|
if (!f) gi.error ("Couldn't open %s for writing.", filename);
|
|
|
|
for (i=0; i<count; i++)
|
|
{
|
|
sprintf( str, "{%f, %f, %f},\n", out_normals[i][0], out_normals[i][1], out_normals[i][2] );
|
|
|
|
fwrite( str, strlen(str), 1, f );
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
gi.dprintf( "%s saved\n", filename );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#define NUM_ANORMS 162 // old table only has 162
|
|
|
|
vec3_t anorms[NUM_ANORMS] = {
|
|
#include "../client/anorms.h"
|
|
};
|
|
|
|
void Cmd_Adots_f (void)
|
|
{
|
|
int i, j;
|
|
float adots[NUM_ANORMS][NUM_ANORMS];
|
|
|
|
for (i=0; i<NUM_ANORMS; i++)
|
|
{
|
|
for (j=0; j<NUM_ANORMS; j++)
|
|
{
|
|
adots[i][j] = DotProduct( anorms[i], anorms[j] );
|
|
}
|
|
}
|
|
|
|
gi.dprintf( "Adot calculation completed.\n" );
|
|
|
|
{
|
|
char filename[MAX_QPATH];
|
|
int i;
|
|
char str[256];
|
|
FILE *f;
|
|
|
|
// filename, eg: .\gamedir\routes\map01.nav
|
|
strcpy( filename, "\\kingpin\\source\\ref_gl\\x_adots.h");
|
|
|
|
// try and open the file for writing
|
|
f = fopen ( filename, "wb");
|
|
if (!f) gi.error ("Couldn't open %s for writing.", filename);
|
|
|
|
sprintf( str, "{\n" );
|
|
fwrite( str, strlen(str), 1, f );
|
|
|
|
for (i=0; i<NUM_ANORMS; i++)
|
|
{
|
|
|
|
sprintf( str, "{" );
|
|
fwrite( str, strlen(str), 1, f );
|
|
|
|
for (j=0; j<NUM_ANORMS; j++)
|
|
{
|
|
if (j > 0)
|
|
{
|
|
sprintf( str, ", " );
|
|
fwrite( str, strlen(str), 1, f );
|
|
}
|
|
|
|
sprintf( str, "%f", adots[i][j] );
|
|
fwrite( str, strlen(str), 1, f );
|
|
}
|
|
|
|
sprintf( str, "},\n" );
|
|
fwrite( str, strlen(str), 1, f );
|
|
|
|
}
|
|
|
|
sprintf( str, "}\n" );
|
|
fwrite( str, strlen(str), 1, f );
|
|
|
|
fclose(f);
|
|
|
|
gi.dprintf( "%s saved\n", filename );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
#endif
|
|
|
|
// Ridah
|
|
extern void ED_CallSpawn (edict_t *ent);
|
|
|
|
// Caution: if using this to spawn an entity that hasn't been precached, this will cause problems
|
|
void Cmd_Spawn_f (edict_t *ent)
|
|
{
|
|
edict_t *spawn;
|
|
char *name;
|
|
vec3_t forward;
|
|
|
|
spawn = G_Spawn();
|
|
|
|
name = gi.args ();
|
|
spawn->classname = gi.TagMalloc(sizeof(name)+1, TAG_LEVEL);
|
|
strcpy( spawn->classname, name );
|
|
|
|
AngleVectors( ent->s.angles, forward, NULL, NULL);
|
|
VectorScale( forward, 64, forward );
|
|
forward[2] += 16;
|
|
|
|
VectorAdd( ent->s.origin, forward, spawn->s.origin );
|
|
VectorCopy( ent->s.angles, spawn->s.angles );
|
|
|
|
ED_CallSpawn (spawn);
|
|
}
|
|
|
|
//-------------------------------------------------------------
|
|
|
|
void P_ClearProfanity ( edict_t *ent )
|
|
{
|
|
ent->owner->profanity_level = 0;
|
|
|
|
G_FreeEdict( ent );
|
|
}
|
|
|
|
void Cmd_Speech_f (edict_t *ent, edict_t *other, char *cmd)
|
|
{
|
|
static float speechtime=0;
|
|
edict_t *best=NULL;
|
|
cast_memory_t *mem;
|
|
|
|
if (deathmatch->value)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "No speech in deathmatch\n");
|
|
return;
|
|
}
|
|
|
|
if (speechtime > (level.time - TALK_OTHER_DELAY) && speechtime < level.time)
|
|
return;
|
|
|
|
if (Q_stricmp (cmd, "key1") == 0) // NEUTRAL
|
|
{
|
|
// JOSEPH 4-FEB-99
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_POSITIVE;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
// END JOSEPH
|
|
|
|
if ((other->svflags & SVF_MONSTER) && (other->cast_info.talk))
|
|
best = other;
|
|
|
|
if (best)
|
|
{
|
|
mem = level.global_cast_memory[best->character_index][ent->character_index];
|
|
|
|
if (!mem)
|
|
{
|
|
AI_RecordSighting( best, ent, VectorDistance( best->s.origin, ent->s.origin ) );
|
|
}
|
|
|
|
// if (strcmp (best->classname, "cast_bitch") == 0)
|
|
// Voice_Random( ent, best, f_neutral_talk_player, F_NUM_NEUTRAL_TALK_PLAYER );
|
|
// else
|
|
// Voice_Random( ent, best, neutral_talk_player, NUM_NEUTRAL_TALK_PLAYER );
|
|
Voice_Random( ent, best, neutral_talk_player, 5 );
|
|
|
|
|
|
// character should turn to us
|
|
best->cast_info.last_talk_turn = level.time;
|
|
best->cast_info.talk_ent = ent;
|
|
|
|
AI_CheckTalk( best );
|
|
}
|
|
else
|
|
{
|
|
gi.cprintf(ent, PRINT_HIGH, "No-one to talk to.\n");
|
|
}
|
|
}
|
|
else if (Q_stricmp (cmd, "key3") == 0) // AGGRESSIVE
|
|
{
|
|
// JOSEPH 4-FEB-99
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_NEGATIVE;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
// END JOSEPH
|
|
|
|
if ( (other->svflags & SVF_MONSTER)
|
|
&& (other->cast_info.talk)
|
|
&& (other->cast_group != ent->cast_group))
|
|
{
|
|
best = other;
|
|
}
|
|
|
|
if (best)
|
|
{
|
|
|
|
mem = level.global_cast_memory[best->character_index][ent->character_index];
|
|
|
|
if (!mem)
|
|
{
|
|
AI_RecordSighting( best, ent, VectorDistance( best->s.origin, ent->s.origin ) );
|
|
}
|
|
|
|
mem->flags |= MEMORY_ASSHOLE;
|
|
|
|
// Ridah, hack so Momo knows if we swear at him twice
|
|
if (best->name_index == NAME_MOMO)
|
|
{
|
|
if (mem->inc < 3)
|
|
{
|
|
mem->flags &= ~MEMORY_UPSET; // clear it so we charge them 30 bucks
|
|
}
|
|
|
|
// if (ent->episode_flags & EP_SKIDROW_MOMO_ASKED_MONEY)
|
|
// mem->inc++;
|
|
EP_CheckMomo (ent, mem);
|
|
|
|
}
|
|
|
|
if (best->cast_group)
|
|
{
|
|
if (ent->profanity_level == 0)
|
|
Voice_Random( ent, best, player_profanity_level1, NUM_PLAYER_PROFANITY_LEVEL1 );
|
|
else if (ent->profanity_level == 1)
|
|
Voice_Random( ent, best, player_profanity_level2, NUM_PLAYER_PROFANITY_LEVEL2 );
|
|
else
|
|
Voice_Random( ent, best, player_profanity_level3, NUM_PLAYER_PROFANITY_LEVEL3 );
|
|
|
|
if (ent->profanity_level < 3)
|
|
ent->profanity_level++;
|
|
|
|
if (ent->profanity_level == 3)
|
|
{ // spawn an entity, that will return us to normal profanity in a second
|
|
edict_t *thinkent;
|
|
|
|
thinkent = G_Spawn();
|
|
thinkent->think = P_ClearProfanity;
|
|
thinkent->nextthink = level.time + 4.0;
|
|
thinkent->owner = ent;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Voice_Random( ent, best, player_profanity_level1, NUM_PLAYER_PROFANITY_LEVEL1 );
|
|
}
|
|
|
|
// character should turn to us
|
|
best->cast_info.last_talk_turn = level.time; // so they don't look for AI characters
|
|
best->cast_info.talk_ent = ent;
|
|
|
|
AI_CheckTalk( best );
|
|
}
|
|
else
|
|
{
|
|
gi.cprintf(ent, PRINT_HIGH, "No-one to abuse.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// gi.cprintf( ent, PRINT_HIGH, "Unknown Speech command\n" );
|
|
return;
|
|
}
|
|
|
|
speechtime = level.time;
|
|
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Cmd_Order_f
|
|
|
|
1. hold = Hold Position
|
|
2. move = Move Out
|
|
3. converge = Converge on my position
|
|
===================
|
|
*/
|
|
edict_t *Order_MoveOut (edict_t *ent);
|
|
|
|
qboolean FullGang (edict_t *player)
|
|
{
|
|
edict_t *ent;
|
|
cast_memory_t *mem;
|
|
int i;
|
|
int cnt = 0;
|
|
|
|
for (i=1, ent=g_edicts+i ; i < globals.num_edicts ; i++,ent++)
|
|
{
|
|
if (ent->client)
|
|
continue;
|
|
if (!(ent->inuse))
|
|
continue;
|
|
if (ent->deadflag == DEAD_DEAD)
|
|
continue;
|
|
if (ent->cast_group != 1)
|
|
continue;
|
|
|
|
mem = level.global_cast_memory [ent->character_index][player->character_index];
|
|
|
|
if (mem && mem->flags & MEMORY_HIRED)
|
|
cnt++;
|
|
|
|
if (cnt == 2)
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void Cmd_Order_f (edict_t *ent, edict_t *other, char *cmd)
|
|
{
|
|
int flags = 0;
|
|
static float ordertime=0;
|
|
static int last_voice;
|
|
qboolean firstime = false;
|
|
|
|
if (deathmatch->value)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "No orders in deathmatch\n");
|
|
return;
|
|
}
|
|
|
|
if (Q_stricmp (cmd, "key1") == 0) // Stay Here
|
|
flags = ORDER_FOLLOWME;
|
|
else if (Q_stricmp (cmd, "key2") == 0) // Attack
|
|
flags = ORDER_MOVE;
|
|
else if (Q_stricmp (cmd, "key3") == 0) // Follow
|
|
flags = ORDER_HOLD;
|
|
|
|
ent->order = flags;
|
|
ent->order_timestamp = level.time;
|
|
|
|
// if (other->cast_info.aiflags & AI_TAKE_COVER)
|
|
// return; // can't order a hiding dude
|
|
|
|
if (ent->client)
|
|
{
|
|
cast_memory_t *cast_memory;
|
|
|
|
cast_memory = level.global_cast_memory[other->character_index][ent->character_index];
|
|
|
|
if (!EP_HiredGuys (ent, other))
|
|
{
|
|
// Ridah, 21-may-99, so they make a talking jesture if they just said something
|
|
if (other->last_talk_time == level.time)
|
|
other->cast_info.talk( other );
|
|
|
|
return;
|
|
}
|
|
|
|
if (other->gender == GENDER_MALE)
|
|
{
|
|
|
|
// RAFAEL 02-18-99
|
|
if (!(cast_memory->flags & MEMORY_HIRED)) // if the dude is not hired
|
|
{
|
|
if (flags == ORDER_MOVE) // not a valid command
|
|
return;
|
|
|
|
// if (FullGang (ent)) // if the gang is full
|
|
if (ent->client->pers.friends >= 2)
|
|
{
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 6)
|
|
Voice_Random (other, ent, &hiredguy_specific[6], 2);
|
|
|
|
other->cast_info.talk( other );
|
|
last_voice = 6;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if (!(cast_memory->flags & MEMORY_HIRE_FIRST_TIME))
|
|
{
|
|
cast_memory->flags |= MEMORY_HIRE_FIRST_TIME;
|
|
{
|
|
int rval;
|
|
rval = abs (other->currentcash);
|
|
|
|
// JOSEPH 19-FEB-99
|
|
if (flags == ORDER_FOLLOWME)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_YES;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
else if (flags == ORDER_HOLD)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_NO;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
// END JOSEPH
|
|
|
|
// gi.dprintf ("yo man I'll follow ya fer %d bucks\n", rval);
|
|
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 1)
|
|
// this line chooses the correct sound to play.. (even switches between the first and second for consecutive calls)
|
|
Voice_Specific( other, ent, hiredguy_ask, ((rval / 25) * 2) + (hiredguy_ask[((rval / 25) * 2)].last_played > hiredguy_ask[((rval / 25) * 2) + 1].last_played) );
|
|
|
|
|
|
other->cast_info.talk( other );
|
|
|
|
last_voice = 1;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
else if (!(cast_memory->flags & MEMORY_HIRE_ASK))
|
|
{
|
|
// JOSEPH 19-FEB-99
|
|
if (flags == ORDER_FOLLOWME)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_YES;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
else if (flags == ORDER_HOLD)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_NO;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
// END JOSEPH
|
|
|
|
if (ent->client->pers.currentcash >= abs (other->currentcash))
|
|
{
|
|
if (flags == ORDER_FOLLOWME)
|
|
{
|
|
cast_memory->flags |= MEMORY_HIRE_ASK;
|
|
|
|
// gi.dprintf ("so ya got the money?\n", abs (other->currentcash));
|
|
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 2)
|
|
// Voice_Specific( other, ent, hiredguy_specific, 0 + (hiredguy_specific[0].last_played > hiredguy_specific[1].last_played) );
|
|
Voice_Random (other, ent, hiredguy_specific, 2);
|
|
|
|
|
|
other->cast_info.talk( other );
|
|
last_voice = 2;
|
|
|
|
return;
|
|
}
|
|
else if (flags == ORDER_HOLD)
|
|
{
|
|
// gi.dprintf ("yo man I'll be waiting for ya\n");
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 3)
|
|
// Voice_Specific( other, ent, hiredguy_specific, 4 + (hiredguy_specific[4].last_played > hiredguy_specific[5].last_played) );
|
|
Voice_Random (other, ent, &hiredguy_specific[4], 2);
|
|
|
|
other->cast_info.talk( other );
|
|
last_voice = 3;
|
|
return;
|
|
}
|
|
else // invalid response
|
|
{
|
|
gi.dprintf( "\nInvalid response.\nkey1 = YES\nkey3 = NO\n" );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// gi.dprintf ("yo man come to me when you got %d bucks\n", abs (other->currentcash));
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 4)
|
|
Voice_Random( other, ent, &hiredguy_specific[11], 3 );
|
|
|
|
other->cast_info.talk( other );
|
|
last_voice = 4;
|
|
return;
|
|
}
|
|
}
|
|
|
|
else if (!(cast_memory->flags & MEMORY_HIRED))
|
|
{
|
|
// JOSEPH 19-FEB-99
|
|
if (flags == ORDER_HOLD)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_NO;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
else if (flags == ORDER_FOLLOWME)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_YES;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
// END JOSEPH
|
|
|
|
// JOSEPH 3-FEB-99
|
|
if (ent->client->pers.currentcash >= abs (other->currentcash))
|
|
{
|
|
if (flags == ORDER_FOLLOWME)
|
|
{ // give them the money
|
|
extern mmove_t thug_move_crch_grab;
|
|
|
|
cast_memory->flags |= MEMORY_HIRED;
|
|
ent->client->pers.currentcash -= abs (other->currentcash);
|
|
|
|
// other->currentcash = abs(other->currentcash);
|
|
other->currentcash = 0;
|
|
|
|
ent->client->pers.friends++;
|
|
|
|
if (!strcmp(other->classname, "cast_thug"))
|
|
{
|
|
other->cast_info.currentmove = &thug_move_crch_grab;
|
|
}
|
|
|
|
other->cast_info.aiflags |= AI_NOWALK_FACE;
|
|
|
|
// we just hired them, by default they should follow us
|
|
flags = ORDER_FOLLOWME;
|
|
firstime = true;
|
|
|
|
EP_HiredGuysRegisterFlags (ent, other);
|
|
}
|
|
else if (flags == ORDER_HOLD)
|
|
{
|
|
// gi.dprintf ("yo man I'll be here if you change your mind\n");
|
|
|
|
cast_memory->flags &= ~MEMORY_HIRE_ASK;
|
|
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 5)
|
|
Voice_Specific( other, ent, hiredguy_specific, 2 );
|
|
other->cast_info.talk( other );
|
|
last_voice = 5;
|
|
return;
|
|
}
|
|
}
|
|
// END JOSEPH
|
|
else
|
|
{
|
|
// gi.dprintf ("yo man come to me when you got %d bucks\n", abs (other->currentcash));
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 6)
|
|
Voice_Specific( other, ent, hiredguy_specific, 3 );
|
|
other->cast_info.talk( other );
|
|
last_voice = 6;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else // GENDER_FEMALE
|
|
{
|
|
// RAFAEL 02-18-99
|
|
if (!(cast_memory->flags & MEMORY_HIRED)) // if the dude is not hired
|
|
{
|
|
if (flags == ORDER_MOVE) // not a valid command
|
|
return;
|
|
|
|
// if (FullGang (ent)) // if the gang is full
|
|
if (ent->client->pers.friends >= 2)
|
|
{
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 6)
|
|
Voice_Random (other, ent, &hiredgal_specific[6], 2);
|
|
|
|
other->cast_info.talk( other );
|
|
last_voice = 6;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if (!(cast_memory->flags & MEMORY_HIRE_FIRST_TIME))
|
|
{
|
|
cast_memory->flags |= MEMORY_HIRE_FIRST_TIME;
|
|
{
|
|
int rval;
|
|
rval = abs (other->currentcash);
|
|
|
|
// JOSEPH 19-FEB-99
|
|
if (flags == ORDER_FOLLOWME)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_YES;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
else if (flags == ORDER_HOLD)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_NO;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
// END JOSEPH
|
|
|
|
// gi.dprintf ("yo man I'll follow ya fer %d bucks\n", rval);
|
|
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 1)
|
|
// this line chooses the correct sound to play.. (even switches between the first and second for consecutive calls)
|
|
Voice_Specific( other, ent, hiredgal_ask, ((rval / 25) * 2) + (hiredgal_ask[((rval / 25) * 2)].last_played > hiredgal_ask[((rval / 25) * 2) + 1].last_played) );
|
|
|
|
|
|
other->cast_info.talk( other );
|
|
|
|
last_voice = 1;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
else if (!(cast_memory->flags & MEMORY_HIRE_ASK))
|
|
{
|
|
// JOSEPH 19-FEB-99
|
|
if (flags == ORDER_FOLLOWME)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_YES;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
else if (flags == ORDER_HOLD)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_NO;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
// END JOSEPH
|
|
|
|
if (ent->client->pers.currentcash >= abs (other->currentcash))
|
|
{
|
|
if (flags == ORDER_FOLLOWME)
|
|
{
|
|
cast_memory->flags |= MEMORY_HIRE_ASK;
|
|
|
|
// gi.dprintf ("so ya got the money?\n", abs (other->currentcash));
|
|
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 2)
|
|
// Voice_Specific( other, ent, hiredguy_specific, 0 + (hiredguy_specific[0].last_played > hiredguy_specific[1].last_played) );
|
|
Voice_Random (other, ent, hiredgal_specific, 2);
|
|
|
|
|
|
other->cast_info.talk( other );
|
|
last_voice = 2;
|
|
|
|
return;
|
|
}
|
|
else if (flags == ORDER_HOLD)
|
|
{
|
|
// gi.dprintf ("yo man I'll be waiting for ya\n");
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 3)
|
|
// Voice_Specific( other, ent, hiredguy_specific, 4 + (hiredguy_specific[4].last_played > hiredguy_specific[5].last_played) );
|
|
Voice_Random (other, ent, &hiredgal_specific[4], 2);
|
|
|
|
other->cast_info.talk( other );
|
|
last_voice = 3;
|
|
return;
|
|
}
|
|
else // invalid response
|
|
{
|
|
gi.dprintf( "\nInvalid response.\nkey1 = YES\nkey3 = NO\n" );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// gi.dprintf ("yo man come to me when you got %d bucks\n", abs (other->currentcash));
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 4)
|
|
Voice_Specific( other, ent, hiredgal_specific, 3 );
|
|
|
|
other->cast_info.talk( other );
|
|
last_voice = 4;
|
|
return;
|
|
}
|
|
}
|
|
|
|
else if (!(cast_memory->flags & MEMORY_HIRED))
|
|
{
|
|
// JOSEPH 19-FEB-99
|
|
if (flags == ORDER_HOLD)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_NO;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
else if (flags == ORDER_FOLLOWME)
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_YES;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
// END JOSEPH
|
|
|
|
// JOSEPH 3-FEB-99
|
|
if (ent->client->pers.currentcash >= abs (other->currentcash))
|
|
{
|
|
if (flags == ORDER_FOLLOWME)
|
|
{ // give them the money
|
|
extern mmove_t thug_move_crch_grab;
|
|
|
|
cast_memory->flags |= MEMORY_HIRED;
|
|
ent->client->pers.currentcash -= abs (other->currentcash);
|
|
|
|
// other->currentcash = abs(other->currentcash);
|
|
other->currentcash = 0;
|
|
|
|
ent->client->pers.friends++;
|
|
|
|
/*
|
|
if (!strcmp(other->classname, "cast_thug"))
|
|
{
|
|
other->cast_info.currentmove = &thug_move_crch_grab;
|
|
}
|
|
*/
|
|
|
|
other->cast_info.aiflags |= AI_NOWALK_FACE;
|
|
|
|
// we just hired them, by default they should follow us
|
|
flags = ORDER_FOLLOWME;
|
|
firstime = true;
|
|
|
|
|
|
EP_HiredGuysRegisterFlags (ent, other);
|
|
}
|
|
else if (flags == ORDER_HOLD)
|
|
{
|
|
// gi.dprintf ("yo man I'll be here if you change your mind\n");
|
|
|
|
cast_memory->flags &= ~MEMORY_HIRE_ASK;
|
|
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 5)
|
|
Voice_Specific( other, ent, hiredgal_specific, 2 );
|
|
other->cast_info.talk( other );
|
|
last_voice = 5;
|
|
return;
|
|
}
|
|
}
|
|
// END JOSEPH
|
|
else
|
|
{
|
|
// gi.dprintf ("yo man come to me when you got %d bucks\n", abs (other->currentcash));
|
|
if (other->last_talk_time < (level.time - 2) || last_voice != 6)
|
|
Voice_Specific( other, ent, hiredgal_specific, 3 );
|
|
other->cast_info.talk( other );
|
|
last_voice = 6;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if in bar, don't allow killing
|
|
if (flags == ORDER_MOVE && level.bar_lvl)
|
|
{
|
|
// gi.dprintf("SOUND TODO: No killing in the bar\n");
|
|
return;
|
|
}
|
|
|
|
// this should help with the friendly guys not showing up when you change level
|
|
other->spawnflags &= ~2;
|
|
other->currentcash = 0;
|
|
other->leader = ent;
|
|
|
|
other->cast_info.aiflags &= ~(AI_MOVEOUT | AI_HOLD_POSITION);
|
|
other->cast_info.aiflags &= ~AI_NOWALK_FACE;
|
|
|
|
if (other->holdpos_ent)
|
|
{
|
|
G_FreeEdict( other->holdpos_ent );
|
|
other->holdpos_ent = NULL;
|
|
}
|
|
|
|
if (flags == ORDER_MOVE)
|
|
{
|
|
if (EP_DoKey (ent, other))
|
|
{
|
|
ent->cast_info.aiflags |= AI_DOKEY;
|
|
other->cast_info.aiflags |= AI_DOKEY;
|
|
}
|
|
else
|
|
{
|
|
ent->cast_info.aiflags |= AI_MOVEOUT;
|
|
other->cast_info.aiflags |= AI_MOVEOUT;
|
|
|
|
if (ent->moveout_ent)
|
|
{ // in case it was set before, kill it
|
|
ent->moveout_ent = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ordertime > level.time) // changed levels
|
|
ordertime = 0;
|
|
|
|
switch (flags)
|
|
{
|
|
case ORDER_MOVE :
|
|
{
|
|
if (ordertime < (level.time - 0.5))
|
|
{
|
|
Voice_Random( ent, other, m_response, NUM_MOVEOUT );
|
|
}
|
|
break;
|
|
}
|
|
case ORDER_HOLD :
|
|
{
|
|
if (ordertime < (level.time - 0.5))
|
|
Voice_Random( ent, other, holdposition, NUM_HOLDPOSITION );
|
|
other->cast_info.aiflags |= AI_HOLD_POSITION;
|
|
other->cast_info.aiflags |= AI_NOWALK_FACE;
|
|
|
|
// remember this position
|
|
if (!other->holdpos_ent)
|
|
other->holdpos_ent = G_Spawn();
|
|
|
|
VectorCopy( other->s.origin, other->holdpos_ent->s.origin );
|
|
|
|
break;
|
|
}
|
|
case ORDER_FOLLOWME :
|
|
{
|
|
if (firstime)
|
|
{
|
|
if (other->gender == GENDER_FEMALE)
|
|
Voice_Random( other, ent, &hiredgal_specific[8], 3);
|
|
else
|
|
Voice_Specific( other, ent, hiredguy_specific, (rand()%3) + 8 );
|
|
// gi.dprintf ("ok I'll go with ya\n");
|
|
}
|
|
else if (ordertime < (level.time - 0.5))
|
|
Voice_Random( ent, other, followme, NUM_FOLLOWME );
|
|
|
|
if (other->cast_info.aiflags & AI_TAKE_COVER)
|
|
{
|
|
other->cast_info.aiflags &= ~(AI_TAKE_COVER|AI_TAKECOVER_IGNOREHEALTH);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// JOSEPH 19-FEB-99
|
|
if ((flags) && (!ent->client->hud_self_talk_time == (level.time + 2.0)) &&
|
|
(!((ent->client->ps.stats[STAT_HUD_SELF_TALK] == TT_YES) ||
|
|
(ent->client->ps.stats[STAT_HUD_SELF_TALK] == TT_NO))))
|
|
{
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_COMMAND;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
}
|
|
// END JOSEPH
|
|
}
|
|
|
|
if (ordertime < (level.time - 0.5))
|
|
ordertime = level.time;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Generic "3-key" system
|
|
|
|
edict_t *key_ent;
|
|
|
|
// JOSEPH 8-FEB-99
|
|
edict_t *GetKeyEnt( edict_t *ent )
|
|
{
|
|
vec3_t dir;
|
|
vec3_t start, end;
|
|
trace_t tr;
|
|
|
|
AngleVectors( ent->client->ps.viewangles, dir, NULL, NULL );
|
|
|
|
VectorCopy( ent->s.origin, start );
|
|
start[2] += ent->viewheight;
|
|
|
|
if (deathmatch->value)
|
|
VectorMA( start, 4000, dir, end );
|
|
else
|
|
VectorMA( start, 384, dir, end );
|
|
|
|
tr = gi.trace( start, NULL, NULL, end, ent, CONTENTS_MONSTER );
|
|
|
|
if ((tr.fraction < 1) && ((deathmatch->value && tr.ent->client) || (tr.ent->svflags & SVF_MONSTER)) && (tr.ent->name_index == NAME_MOMO))
|
|
{
|
|
return tr.ent;
|
|
}
|
|
|
|
tr = gi.trace( start, NULL, NULL, end, ent, MASK_SHOT );
|
|
|
|
if ((tr.fraction < 1) && ((deathmatch->value && tr.ent->client) || (tr.ent->svflags & SVF_MONSTER)))
|
|
{
|
|
return tr.ent;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
// END JOSEPH
|
|
|
|
void Cmd_Key_f (edict_t *ent)
|
|
{
|
|
char *cmd;
|
|
|
|
|
|
if (level.speaktime > level.time)
|
|
return;
|
|
|
|
cmd = gi.argv (0);
|
|
|
|
if (key_ent = GetKeyEnt( ent ))
|
|
{
|
|
void Cmd_Wave_f (edict_t *ent, edict_t *other);
|
|
cast_memory_t *mem;
|
|
|
|
if (deathmatch->value)
|
|
{
|
|
Cmd_Wave_f( ent, key_ent );
|
|
return;
|
|
}
|
|
|
|
// JOSEPH 18-FEB-99
|
|
ent->client->ps.stats[STAT_HUD_SELF_TALK] = TT_COMMAND;
|
|
ent->client->hud_self_talk_time = level.time + 2.0;
|
|
// END JOSEPH
|
|
|
|
mem = level.global_cast_memory[key_ent->character_index][ent->character_index];
|
|
|
|
if (!mem)
|
|
return;
|
|
|
|
if (mem->memory_type == MEMORY_TYPE_FRIEND)
|
|
{ // issuing an order
|
|
|
|
Cmd_Order_f( ent, key_ent, cmd );
|
|
|
|
if (key_ent->targetname)
|
|
key_ent->targetname = 0;
|
|
if (key_ent->spawnflags & 2)
|
|
key_ent->spawnflags &=~ 2;
|
|
|
|
}
|
|
else if (mem->response) // we're responding to a question
|
|
{
|
|
response_t resp;
|
|
|
|
if (Q_stricmp (cmd, "key1") == 0)
|
|
resp = resp_yes;
|
|
else if (Q_stricmp (cmd, "key3") == 0)
|
|
resp = resp_no;
|
|
|
|
mem->response( ent, key_ent, resp );
|
|
|
|
}
|
|
else // normal discussion
|
|
{
|
|
|
|
Cmd_Speech_f ( ent, key_ent, cmd );
|
|
|
|
}
|
|
|
|
}
|
|
else // noone to talk to, so make it an order in case anyone's listening
|
|
{
|
|
int flags;
|
|
|
|
if (Q_stricmp (cmd, "key1") == 0) // Stay Here
|
|
flags = ORDER_FOLLOWME;
|
|
else if (Q_stricmp (cmd, "key2") == 0) // Attack
|
|
flags = ORDER_MOVE;
|
|
else if (Q_stricmp (cmd, "key3") == 0) // Follow
|
|
flags = ORDER_HOLD;
|
|
|
|
|
|
ent->order = flags;
|
|
ent->order_timestamp = level.time;
|
|
}
|
|
|
|
|
|
level.speaktime = level.time + 1.0;
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
// Ridah, Chasecam
|
|
void Cmd_ToggleCam_f ( edict_t *ent )
|
|
{
|
|
if (ent->flags & FL_CHASECAM)
|
|
{
|
|
ent->flags -= FL_CHASECAM;
|
|
}
|
|
else
|
|
{
|
|
ent->flags += FL_CHASECAM;
|
|
|
|
gi.centerprintf( ent, "Chasecam is incomplete, and therefore\nunsupported at this stage\n" );
|
|
}
|
|
}
|
|
// done.
|
|
|
|
// JOSEPH 13-APR-99
|
|
void Cmd_SetProps_f (int status)
|
|
{
|
|
edict_t *e;
|
|
int i;
|
|
|
|
for (i=1, e=g_edicts+i ; i < globals.num_edicts ; i++,e++)
|
|
{
|
|
if ((e->svflags & SVF_PROP) && (e->option))
|
|
{
|
|
if (status)
|
|
{
|
|
e->svflags |= SVF_NOCLIENT;
|
|
e->solid = SOLID_NOT;
|
|
}
|
|
else
|
|
{
|
|
e->svflags &= ~SVF_NOCLIENT;
|
|
e->solid = e->savesolid;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// END JOSEPH
|
|
|
|
// JOSEPH 23-MAR-99
|
|
void Cmd_FryAll_f (edict_t *ent)
|
|
{
|
|
edict_t *e = NULL;
|
|
|
|
if (deathmatch->value)
|
|
return;
|
|
|
|
while (e = findradius(e, ent->s.origin, 512))
|
|
{
|
|
if (e->svflags & SVF_MONSTER)
|
|
{
|
|
e->onfiretime = 100;
|
|
e->onfireent = e;
|
|
|
|
if (e->gender == GENDER_FEMALE)
|
|
{
|
|
Voice_Random (e, e, &female_specific[6], 2);
|
|
}
|
|
else if (e->gender == GENDER_MALE)
|
|
{
|
|
Voice_Random (e, e, &male_specific[10], 2);
|
|
}
|
|
|
|
e->pain_debounce_time = level.time + 5;
|
|
|
|
if (e->cast_info.catch_fire)
|
|
{
|
|
e->cast_info.catch_fire(e, e);
|
|
}
|
|
|
|
e->s.renderfx2 &= ~RF2_DIR_LIGHTS;
|
|
}
|
|
}
|
|
}
|
|
// END JOSEPH
|
|
|
|
// ==============================================================================
|
|
// Quake2 code follows:
|
|
|
|
char *ClientTeam (edict_t *ent)
|
|
{
|
|
char *p;
|
|
static char value[512];
|
|
|
|
value[0] = 0;
|
|
|
|
if (!ent->client)
|
|
return value;
|
|
|
|
strcpy(value, Info_ValueForKey (ent->client->pers.userinfo, "skin"));
|
|
p = strchr(value, '/');
|
|
if (!p)
|
|
return value;
|
|
|
|
if ((int)(dmflags->value) & DF_MODELTEAMS)
|
|
{
|
|
// Ridah, disabled this, teams are determined by model and skin (since that's the only way to make sure they appear the same
|
|
// *p = 0;
|
|
return value;
|
|
}
|
|
|
|
// if ((int)(dmflags->value) & DF_SKINTEAMS)
|
|
return ++p;
|
|
}
|
|
|
|
qboolean OnSameTeam (edict_t *ent1, edict_t *ent2)
|
|
{
|
|
char ent1Team [512];
|
|
char ent2Team [512];
|
|
|
|
if (teamplay->value)
|
|
{
|
|
if (ent1 && ent2 && ent1->client && ent2->client && ent1->client->pers.team && (ent1->client->pers.team == ent2->client->pers.team))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
if (!((int)(dmflags->value) & (DF_MODELTEAMS /*| DF_SKINTEAMS*/)))
|
|
return false;
|
|
|
|
strcpy (ent1Team, ClientTeam (ent1));
|
|
strcpy (ent2Team, ClientTeam (ent2));
|
|
|
|
if (strcmp(ent1Team, ent2Team) == 0)
|
|
return true;
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
void SelectNextItem (edict_t *ent, int itflags)
|
|
{
|
|
gclient_t *cl;
|
|
// int i, index;
|
|
// gitem_t *it;
|
|
|
|
cl = ent->client;
|
|
|
|
if (cl->chase_target)
|
|
{
|
|
ChaseNext(ent);
|
|
return;
|
|
}
|
|
/*
|
|
// scan for the next valid one
|
|
for (i=1 ; i<=MAX_ITEMS ; i++)
|
|
{
|
|
index = (cl->pers.selected_item + i)%MAX_ITEMS;
|
|
if (!cl->pers.inventory[index])
|
|
continue;
|
|
it = &itemlist[index];
|
|
if (!it->use)
|
|
continue;
|
|
if (!(it->flags & itflags))
|
|
continue;
|
|
|
|
cl->pers.selected_item = index;
|
|
return;
|
|
}
|
|
|
|
cl->pers.selected_item = -1;
|
|
*/
|
|
}
|
|
|
|
void SelectPrevItem (edict_t *ent, int itflags)
|
|
{
|
|
gclient_t *cl;
|
|
// int i, index;
|
|
// gitem_t *it;
|
|
|
|
cl = ent->client;
|
|
|
|
if (cl->chase_target)
|
|
{
|
|
ChasePrev(ent);
|
|
return;
|
|
}
|
|
/*
|
|
// scan for the next valid one
|
|
for (i=1 ; i<=MAX_ITEMS ; i++)
|
|
{
|
|
index = (cl->pers.selected_item + MAX_ITEMS - i)%MAX_ITEMS;
|
|
if (!cl->pers.inventory[index])
|
|
continue;
|
|
it = &itemlist[index];
|
|
if (!it->use)
|
|
continue;
|
|
if (!(it->flags & itflags))
|
|
continue;
|
|
|
|
cl->pers.selected_item = index;
|
|
return;
|
|
}
|
|
|
|
cl->pers.selected_item = -1;
|
|
*/
|
|
}
|
|
|
|
void ValidateSelectedItem (edict_t *ent)
|
|
{
|
|
gclient_t *cl;
|
|
|
|
cl = ent->client;
|
|
|
|
if (cl->pers.inventory[cl->pers.selected_item])
|
|
return; // valid
|
|
|
|
SelectNextItem (ent, -1);
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Cmd_Give_f
|
|
|
|
Give items to a client
|
|
==================
|
|
*/
|
|
void Cmd_Give_f (edict_t *ent)
|
|
{
|
|
char *name;
|
|
gitem_t *it;
|
|
int index;
|
|
int i;
|
|
qboolean give_all;
|
|
edict_t *it_ent;
|
|
|
|
if (!developer->value)
|
|
return;
|
|
|
|
if (deathmatch->value && !sv_cheats->value)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
|
|
return;
|
|
}
|
|
|
|
name = gi.args();
|
|
|
|
if (Q_stricmp(name, "all") == 0)
|
|
give_all = true;
|
|
else
|
|
give_all = false;
|
|
|
|
// JOSEPH 15-FEB-99
|
|
if (Q_stricmp(gi.argv(1), "cash") == 0)
|
|
{
|
|
if (gi.argc() == 3)
|
|
ent->client->pers.currentcash += atoi(gi.argv(2));
|
|
else
|
|
ent->client->pers.currentcash += 100;
|
|
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/pickups/cash.wav"), 1, ATTN_NORM, 0);
|
|
|
|
if (!give_all)
|
|
return;
|
|
}
|
|
// END JOSEPH
|
|
|
|
if (give_all || Q_stricmp(gi.argv(1), "health") == 0)
|
|
{
|
|
if (gi.argc() == 3)
|
|
ent->health = atoi(gi.argv(2));
|
|
else
|
|
ent->health = ent->max_health;
|
|
if (!give_all)
|
|
return;
|
|
}
|
|
|
|
if (give_all || Q_stricmp (gi.argv(1), "mods") == 0)
|
|
{
|
|
ent->client->pers.pistol_mods |= WEAPON_MOD_ROF;
|
|
|
|
ent->client->pers.pistol_mods |= WEAPON_MOD_RELOAD;
|
|
|
|
ent->client->pers.pistol_mods |= WEAPON_MOD_DAMAGE;
|
|
|
|
ent->client->pers.pistol_mods |= WEAPON_MOD_COOLING_JACKET;
|
|
|
|
ent->client->pers.hmg_shots = 30;
|
|
|
|
if (!give_all)
|
|
return;
|
|
}
|
|
|
|
if (give_all || Q_stricmp(name, "weapons") == 0)
|
|
{
|
|
for (i=0 ; i<game.num_items ; i++)
|
|
{
|
|
it = itemlist + i;
|
|
if (!it->pickup)
|
|
continue;
|
|
if (!(it->flags & IT_WEAPON))
|
|
continue;
|
|
|
|
// ent->client->pers.inventory[i] += 1;
|
|
ent->client->pers.inventory[i] = 1;
|
|
if (it->flags & IT_SILENCER)
|
|
{
|
|
ent->client->pers.silencer_shots = 20;
|
|
}
|
|
}
|
|
if (!give_all)
|
|
return;
|
|
}
|
|
|
|
if (give_all || Q_stricmp(name, "ammo") == 0)
|
|
{
|
|
for (i=0 ; i<game.num_items ; i++)
|
|
{
|
|
it = itemlist + i;
|
|
if (!it->pickup)
|
|
continue;
|
|
if (!(it->flags & IT_AMMO))
|
|
continue;
|
|
if (it->flags & IT_NOCHEATS)
|
|
continue;
|
|
Add_Ammo (ent, it, 1000);
|
|
}
|
|
if (!give_all)
|
|
return;
|
|
}
|
|
|
|
// JOSEPH 30-APR-99
|
|
if (Q_stricmp(name, "armor") == 0)
|
|
{
|
|
gitem_t *it;
|
|
|
|
it = FindItem("Jacket Armor Heavy");
|
|
ent->client->pers.inventory[ITEM_INDEX(it)] = 100;
|
|
|
|
it = FindItem("Legs Armor Heavy");
|
|
ent->client->pers.inventory[ITEM_INDEX(it)] = 100;
|
|
|
|
it = FindItem("Helmet Armor Heavy");
|
|
ent->client->pers.inventory[ITEM_INDEX(it)] = 100;
|
|
|
|
return;
|
|
}
|
|
|
|
/*if (give_all || Q_stricmp(name, "Power Shield") == 0)
|
|
{
|
|
it = FindItem("Power Shield");
|
|
it_ent = G_Spawn();
|
|
it_ent->classname = it->classname;
|
|
SpawnItem (it_ent, it);
|
|
Touch_Item (it_ent, ent, NULL, NULL);
|
|
if (it_ent->inuse)
|
|
G_FreeEdict(it_ent);
|
|
|
|
if (!give_all)
|
|
return;
|
|
}*/
|
|
// END JOSEPH
|
|
|
|
if (give_all)
|
|
{
|
|
for (i=0 ; i<game.num_items ; i++)
|
|
{
|
|
it = itemlist + i;
|
|
if (!it->pickup)
|
|
continue;
|
|
if (it->flags & (IT_ARMOR|IT_WEAPON|IT_AMMO))
|
|
continue;
|
|
if (it->flags & IT_NOCHEATS)
|
|
continue;
|
|
ent->client->pers.inventory[i] = 1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
it = FindItem (name);
|
|
if (!it)
|
|
{
|
|
name = gi.argv(1);
|
|
it = FindItem (name);
|
|
if (!it)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "not a valid item\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!it->pickup)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "non-pickup item\n");
|
|
return;
|
|
}
|
|
|
|
index = ITEM_INDEX(it);
|
|
|
|
if (it->flags & IT_AMMO)
|
|
{
|
|
if (gi.argc() == 3)
|
|
ent->client->pers.inventory[index] = atoi(gi.argv(2));
|
|
else
|
|
ent->client->pers.inventory[index] += it->quantity;
|
|
}
|
|
else
|
|
{
|
|
it_ent = G_Spawn();
|
|
it_ent->classname = it->classname;
|
|
SpawnItem (it_ent, it);
|
|
Touch_Item (it_ent, ent, NULL, NULL);
|
|
if (it->flags & IT_SILENCER)
|
|
ent->client->pers.silencer_shots = 20;
|
|
if (it_ent->inuse)
|
|
G_FreeEdict(it_ent);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
Cmd_God_f
|
|
|
|
Sets client to godmode
|
|
|
|
argv(0) god
|
|
==================
|
|
*/
|
|
void Cmd_God_f (edict_t *ent)
|
|
{
|
|
char *msg;
|
|
|
|
if (!developer->value)
|
|
return;
|
|
|
|
if (deathmatch->value && !sv_cheats->value)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
|
|
return;
|
|
}
|
|
|
|
ent->flags ^= FL_GODMODE;
|
|
if (!(ent->flags & FL_GODMODE) )
|
|
msg = "Immortal OFF\n";
|
|
else
|
|
msg = "Immortal ON\n";
|
|
|
|
gi.cprintf (ent, PRINT_HIGH, msg);
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
Cmd_Notarget_f
|
|
|
|
Sets client to notarget
|
|
|
|
argv(0) notarget
|
|
==================
|
|
*/
|
|
void Cmd_Notarget_f (edict_t *ent)
|
|
{
|
|
char *msg;
|
|
|
|
if (!developer->value)
|
|
return;
|
|
|
|
if (deathmatch->value && !sv_cheats->value)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
|
|
return;
|
|
}
|
|
|
|
ent->flags ^= FL_NOTARGET;
|
|
if (!(ent->flags & FL_NOTARGET) )
|
|
msg = "notarget OFF\n";
|
|
else
|
|
msg = "notarget ON\n";
|
|
|
|
gi.cprintf (ent, PRINT_HIGH, msg);
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
Cmd_Noclip_f
|
|
|
|
argv(0) noclip
|
|
==================
|
|
*/
|
|
void Cmd_Noclip_f (edict_t *ent)
|
|
{
|
|
char *msg;
|
|
|
|
if (!developer->value)
|
|
return;
|
|
|
|
if (deathmatch->value && !sv_cheats->value)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
|
|
return;
|
|
}
|
|
|
|
if (ent->movetype == MOVETYPE_NOCLIP)
|
|
{
|
|
ent->movetype = MOVETYPE_WALK;
|
|
msg = "noclip OFF\n";
|
|
}
|
|
else
|
|
{
|
|
ent->movetype = MOVETYPE_NOCLIP;
|
|
msg = "noclip ON\n";
|
|
}
|
|
|
|
gi.cprintf (ent, PRINT_HIGH, msg);
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
Cmd_Use_f
|
|
|
|
Use an inventory item
|
|
==================
|
|
*/
|
|
void Cmd_Use_f (edict_t *ent)
|
|
{
|
|
int index;
|
|
gitem_t *it;
|
|
char *s;
|
|
|
|
s = gi.args();
|
|
|
|
// Teamplay
|
|
if (teamplay->value && !ent->client->pers.team)
|
|
{
|
|
if (s)
|
|
{
|
|
if (!strcmp(s, "pipe"))
|
|
{ // Kings
|
|
Cmd_Join_f( ent, team_names[1] );
|
|
}
|
|
else if (!strcmp(s, "pistol"))
|
|
{ // Pins
|
|
Cmd_Join_f( ent, team_names[2] );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
it = FindItem (s);
|
|
if (!it)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "not a valid item: %s\n", s);
|
|
return;
|
|
}
|
|
if (!it->use)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
|
|
return;
|
|
}
|
|
|
|
index = ITEM_INDEX(it);
|
|
if (!ent->client->pers.inventory[index])
|
|
{
|
|
|
|
if (strcmp (it->pickup_name, "Pistol") == 0)
|
|
{
|
|
gi.dprintf ("silencer_shots: %d\n", ent->client->pers.silencer_shots);
|
|
if (!ent->client->pers.silencer_shots)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
|
|
return;
|
|
}
|
|
it = FindItem ("SPistol");
|
|
index = ITEM_INDEX (it);
|
|
if (!ent->client->pers.inventory[index])
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ent->client->pers.holsteredweapon)
|
|
{
|
|
if (level.bar_lvl)
|
|
return;
|
|
|
|
if (ent->client->pers.holsteredweapon == it)
|
|
{
|
|
ent->client->newweapon = ent->client->pers.holsteredweapon;
|
|
ChangeWeapon (ent);
|
|
ent->client->pers.holsteredweapon = 0;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
ent->client->pers.weapon = ent->client->pers.holsteredweapon;
|
|
ent->client->pers.holsteredweapon = NULL;
|
|
}
|
|
}
|
|
|
|
it->use (ent, it);
|
|
|
|
if (!ent->client->pers.holsteredweapon && !ent->client->pers.weapon && ent->client->newweapon)
|
|
{
|
|
ChangeWeapon (ent);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
Cmd_Drop_f
|
|
|
|
Drop an inventory item
|
|
==================
|
|
*/
|
|
void Cmd_Drop_f (edict_t *ent)
|
|
{
|
|
int index;
|
|
gitem_t *it;
|
|
char *s;
|
|
|
|
s = gi.args();
|
|
it = FindItem (s);
|
|
if (!it)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "not a valid item: %s\n", s);
|
|
return;
|
|
}
|
|
if (!it->drop)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
|
|
return;
|
|
}
|
|
|
|
index = ITEM_INDEX(it);
|
|
if (!ent->client->pers.inventory[index])
|
|
{
|
|
if (strcmp (it->pickup_name, "Pistol") == 0)
|
|
{
|
|
gi.dprintf ("silencer_shots: %d\n", ent->client->pers.silencer_shots);
|
|
|
|
if (!ent->client->pers.silencer_shots)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
|
|
return;
|
|
}
|
|
|
|
it = FindItem ("SPistol");
|
|
index = ITEM_INDEX (it);
|
|
if (!ent->client->pers.inventory[index])
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
|
|
return;
|
|
}
|
|
}
|
|
|
|
it->drop (ent, it);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
Cmd_Inven_f
|
|
=================
|
|
*/
|
|
void Cmd_Inven_f (edict_t *ent)
|
|
{
|
|
int i;
|
|
gclient_t *cl;
|
|
|
|
cl = ent->client;
|
|
|
|
cl->showscores = false;
|
|
cl->showhelp = false;
|
|
|
|
if (cl->showinventory)
|
|
{
|
|
cl->showinventory = false;
|
|
return;
|
|
}
|
|
|
|
cl->showinventory = true;
|
|
|
|
gi.WriteByte (svc_inventory);
|
|
for (i=0 ; i<MAX_ITEMS ; i++)
|
|
{
|
|
gi.WriteShort (cl->pers.inventory[i]);
|
|
}
|
|
gi.unicast (ent, true);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Cmd_InvUse_f
|
|
=================
|
|
*/
|
|
void Cmd_InvUse_f (edict_t *ent)
|
|
{
|
|
gitem_t *it;
|
|
|
|
ValidateSelectedItem (ent);
|
|
|
|
if (ent->client->pers.selected_item == -1)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "No item to use.\n");
|
|
return;
|
|
}
|
|
|
|
it = &itemlist[ent->client->pers.selected_item];
|
|
if (!it->use)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
|
|
return;
|
|
}
|
|
it->use (ent, it);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Cmd_WeapPrev_f
|
|
=================
|
|
*/
|
|
void Cmd_WeapPrev_f (edict_t *ent)
|
|
{
|
|
gclient_t *cl;
|
|
int i, index;
|
|
gitem_t *it;
|
|
int selected_weapon;
|
|
|
|
cl = ent->client;
|
|
|
|
// JOSEPH 10-FEB-99
|
|
if (cl->pers.holsteredweapon)
|
|
{
|
|
if (level.bar_lvl)
|
|
return;
|
|
|
|
cl->newweapon = cl->pers.holsteredweapon;
|
|
ChangeWeapon (ent);
|
|
cl->pers.holsteredweapon = 0;
|
|
return;
|
|
}
|
|
// END JOSEPH
|
|
|
|
if (!cl->pers.weapon)
|
|
return;
|
|
|
|
// Ridah, if already changing weapons, start from the next weapon, for faster cycling
|
|
if (ent->client->weaponstate == WEAPON_DROPPING)
|
|
selected_weapon = ITEM_INDEX(cl->newweapon);
|
|
else
|
|
selected_weapon = ITEM_INDEX(cl->pers.weapon);
|
|
|
|
// scan for the next valid one
|
|
for (i=1 ; i<=MAX_ITEMS ; i++)
|
|
{
|
|
index = (selected_weapon + i)%MAX_ITEMS;
|
|
if (!cl->pers.inventory[index])
|
|
continue;
|
|
it = &itemlist[index];
|
|
if (!it->use)
|
|
continue;
|
|
if (! (it->flags & IT_WEAPON) )
|
|
continue;
|
|
if (selected_weapon == ITEM_INDEX(it) && cl->newweapon)
|
|
{
|
|
// Ridah, show the current weapon on the hud, for easy scrolling
|
|
if (deathmatch->value && !strstr(cl->newweapon->icon, "pipe"))
|
|
{
|
|
it = cl->newweapon;
|
|
ent->client->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(it->icon);
|
|
ent->client->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS+ITEM_INDEX(it);
|
|
ent->client->pickup_msg_time = level.time + 5.5;
|
|
}
|
|
|
|
return; // successful
|
|
}
|
|
else
|
|
{
|
|
it->use (ent, it);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define DREWACTIVATEDISTANCE 96
|
|
|
|
// JOSEPH 11-MAY-99
|
|
qboolean infront_angle_activate (vec3_t selfang, vec3_t selforg, vec3_t otherorg)
|
|
{
|
|
vec3_t vec;
|
|
float dot;
|
|
vec3_t forward;
|
|
|
|
AngleVectors (selfang, forward, NULL, NULL);
|
|
VectorSubtract (otherorg, selforg, vec);
|
|
VectorNormalize (vec);
|
|
dot = DotProduct (vec, forward);
|
|
|
|
if (dot > 0.95)
|
|
return true;
|
|
return false;
|
|
}
|
|
// END JOSEPH
|
|
|
|
// JOSEPH 21-SEP-98
|
|
void Cmd_Activate_f (edict_t *ent)
|
|
{
|
|
edict_t *trav, *best;
|
|
float best_dist=9999, this_dist;
|
|
|
|
if (ent->movetype == MOVETYPE_NOCLIP)
|
|
{
|
|
if (maxclients->value > 1)
|
|
{
|
|
if (!ent->client->chase_target)
|
|
ChaseNext(ent);
|
|
else // disable it
|
|
{
|
|
ent->client->chase_target = NULL;
|
|
ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// if we are ducking
|
|
if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
|
|
{
|
|
// find the near enemy
|
|
trav = best = NULL;
|
|
// JOSEPH 13-MAY-99
|
|
while (trav = findradius( trav, ent->s.origin, 80 ))
|
|
// END JOSEPH
|
|
{
|
|
// JOSEPH 14-MAY-99
|
|
if (!(trav->svflags & SVF_MONSTER))
|
|
continue;
|
|
// END JOSEPH
|
|
// JOSEPH 6-JAN-99
|
|
if (trav == ent)
|
|
continue;
|
|
// END JOSEPH
|
|
//if (!infront(ent, trav))
|
|
// continue;
|
|
//if (!visible(ent, trav))
|
|
// continue;
|
|
if (((this_dist = VectorDistance(ent->s.origin, trav->s.origin)) > best_dist) && (this_dist > 32))
|
|
continue;
|
|
|
|
best = trav;
|
|
best_dist = this_dist;
|
|
}
|
|
|
|
// if the enemy has cash - then take it
|
|
// Joseph 14-MAY-99
|
|
if ((best) && (best->currentcash > 0) && best->health <= 0)
|
|
// END JOSEPH
|
|
{
|
|
int index;
|
|
gitem_t *item;
|
|
|
|
ent->client->pers.currentcash += best->currentcash;
|
|
//gi.cprintf (ent, PRINT_HIGH, "%i dollars found\n", best->currentcash);
|
|
ent->client->ps.stats[STAT_CASH_PICKUP] = best->currentcash;
|
|
best->currentcash = 0;
|
|
// flash the screen green
|
|
ent->client->bonus_alpha = 0.25;
|
|
ent->client->bonus_alpha_color = 2;
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/pickups/cash.wav"), 1, ATTN_NORM, 0);
|
|
|
|
item = FindItem ("Cash");
|
|
index = ITEM_INDEX (item);
|
|
// show icon and name on status bar
|
|
ent->client->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(item->icon);
|
|
ent->client->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS+index;
|
|
ent->client->pickup_msg_time = level.time + 5.5;
|
|
}
|
|
}
|
|
|
|
// JOSEPH 1-OCT-98
|
|
// Work in progress
|
|
/*{
|
|
edict_t *trav, *best;
|
|
float best_dist=9999, this_dist;
|
|
|
|
// find the nearest pull-enabled object
|
|
trav = best = NULL;
|
|
while (trav = findradius( trav, ent->s.origin, 128 ))
|
|
{
|
|
if (!trav->pullable)
|
|
continue;
|
|
//if (!infront(ent, trav))
|
|
// continue;
|
|
//if (!visible(ent, trav))
|
|
// continue;
|
|
if (((this_dist = VectorDistance(ent->s.origin, trav->s.origin)) > best_dist) && (this_dist > 64))
|
|
continue;
|
|
|
|
best = trav;
|
|
best_dist = this_dist;
|
|
}
|
|
|
|
// If we find something to drag
|
|
if (best)
|
|
{
|
|
vec3_t up, forward;
|
|
|
|
AngleVectors(ent->s.angles, forward, NULL, up);
|
|
//VectorScale (forward, 50, best->velocity);
|
|
VectorMA (best->velocity, 400, up, best->velocity);
|
|
best->movetype = MOVETYPE_TOSS;
|
|
best->groundentity = NULL;
|
|
}
|
|
}*/
|
|
// END JOSEPH
|
|
|
|
// JOSEPH 11-MAY-99
|
|
// find a usable brush entity and tag it as such
|
|
{
|
|
edict_t *target, *toptarget;
|
|
vec3_t dest;
|
|
trace_t trace, tr;
|
|
vec3_t dir, neworigin, endorg;
|
|
float topdistance;
|
|
int directtarget;
|
|
|
|
target = NULL;
|
|
toptarget = NULL;
|
|
topdistance = 10000;
|
|
directtarget = 0;
|
|
|
|
while (((target = findradius(target, ent->s.origin, DREWACTIVATEDISTANCE * (1 + (deathmatch->value != 0)))) || toptarget) && !directtarget)
|
|
{
|
|
if (!target)
|
|
goto startyourtriggers;
|
|
if (!(target->activate_flags & ACTIVATE_GENERAL))
|
|
continue;
|
|
if (target->targetname && target->key != -1)
|
|
continue;
|
|
|
|
VectorCopy(ent->s.origin, neworigin);
|
|
neworigin[2] += ent->viewheight;
|
|
|
|
AngleVectors( ent->client->ps.viewangles, dir, NULL, NULL );
|
|
VectorMA (neworigin, DREWACTIVATEDISTANCE * (1 + (deathmatch->value != 0)), dir, dest);
|
|
|
|
trace = gi.trace (neworigin, vec3_origin, vec3_origin, dest, ent, MASK_SOLID);
|
|
|
|
// JOSEPH 19-MAY-99
|
|
if (trace.ent && trace.ent->classname && (!strcmp(trace.ent->classname, "func_lift")))
|
|
{
|
|
edict_t *targetL;
|
|
|
|
targetL = NULL;
|
|
|
|
while (((targetL = findradius(targetL, trace.endpos, 16))))
|
|
{
|
|
if (!(targetL->activate_flags & ACTIVATE_GENERAL))
|
|
continue;
|
|
if (targetL->targetname && targetL->key != -1)
|
|
continue;
|
|
if (targetL->classname && (!strcmp(targetL->classname, "func_button")))
|
|
{
|
|
toptarget = targetL;
|
|
goto startyourtriggers;
|
|
}
|
|
}
|
|
}
|
|
// END JOSEPH
|
|
|
|
// JOSEPH 14-MAY-99
|
|
if (trace.ent == target)
|
|
{
|
|
directtarget = 1;
|
|
|
|
if ((strcmp (target->classname, "func_door") == 0) ||
|
|
(strcmp (target->classname, "func_door_rotating") == 0))
|
|
{
|
|
if ((target->team) && (target->teammaster))
|
|
{
|
|
toptarget = target->teammaster;
|
|
goto startyourtriggers;
|
|
}
|
|
}
|
|
|
|
toptarget = target;
|
|
goto startyourtriggers;
|
|
}
|
|
// END JOSEPH
|
|
|
|
VectorAdd (target->absmin, target->absmax, endorg);
|
|
VectorScale (endorg, 0.5, endorg);
|
|
|
|
if (!(infront_angle_activate(ent->client->v_angle, neworigin, endorg)))
|
|
continue;
|
|
|
|
if (VectorDistance(trace.endpos, dest ) > topdistance)
|
|
continue;
|
|
|
|
tr = gi.trace(neworigin, NULL, NULL, endorg, ent, MASK_SOLID);
|
|
|
|
// Ridah, added this since it's frustrating hitting the switches in deathmatch
|
|
if (!deathmatch->value || (!Q_stricmp(target->classname, "func_button") && !Q_stricmp(target->target, "safe2")))
|
|
if (tr.ent != target)
|
|
continue;
|
|
|
|
topdistance = VectorDistance(trace.endpos, dest);
|
|
toptarget = target;
|
|
continue;
|
|
|
|
startyourtriggers:
|
|
|
|
target = toptarget;
|
|
toptarget = NULL;
|
|
|
|
// END JOSEPH
|
|
|
|
/*{
|
|
edict_t *target;
|
|
vec3_t dest, src;
|
|
trace_t trace;
|
|
vec3_t dir;
|
|
|
|
|
|
target = NULL;
|
|
|
|
while (target = findradius ( target, ent->s.origin, DREWACTIVATEDISTANCE))
|
|
{
|
|
if (!(target->activate_flags & ACTIVATE_GENERAL))
|
|
continue;
|
|
if (target->targetname && target->key != -1)
|
|
continue;
|
|
|
|
if (strcmp (target->classname, "func_door") == 0)
|
|
{
|
|
AngleVectors( ent->client->ps.viewangles, dir, NULL, NULL );
|
|
VectorMA (ent->s.origin, DREWACTIVATEDISTANCE, dir, dest);
|
|
}
|
|
else if (strcmp (target->classname, "misc_cut_scene") == 0)
|
|
{
|
|
AngleVectors( ent->client->ps.viewangles, dir, NULL, NULL );
|
|
VectorMA (ent->s.origin, DREWACTIVATEDISTANCE, dir, dest);
|
|
}
|
|
else
|
|
{
|
|
VectorAdd (target->absmin, target->absmax, dest);
|
|
VectorScale (dest, 0.5, dest);
|
|
}
|
|
|
|
|
|
// Ridah, fix close to buttons not working
|
|
VectorCopy( ent->s.origin, src );
|
|
if ( (dest[2] > (ent->s.origin[2] + ent->mins[2]))
|
|
&& (dest[2] < (ent->s.origin[2] + ent->maxs[2])))
|
|
{
|
|
src[2] = dest[2];
|
|
}
|
|
|
|
trace = gi.trace (ent->s.origin, vec3_origin, vec3_origin, dest, ent, MASK_SOLID);
|
|
|
|
// Rafael
|
|
if (trace.ent != target)
|
|
{
|
|
// Ridah, fix close to buttons not working
|
|
if (VectorDistance( trace.endpos, dest ) > 32)
|
|
continue;
|
|
}*/
|
|
|
|
// JOSEPH 12-MAR-99-B
|
|
// If it must be trigger unlocked
|
|
if (target->key < 0)
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
// END JOSEPH
|
|
|
|
// JOSEPH 19-MAR-99-B
|
|
// Kingpin keys must be placed here to open doors
|
|
if (target->key > 0)
|
|
{
|
|
switch(target->key)
|
|
{
|
|
case 1:
|
|
{
|
|
if (!ent->client->pers.inventory[ITEM_INDEX(FindItem("StoreRoomKey"))])
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
if (!ent->client->pers.inventory[ITEM_INDEX(FindItem("Electrical_Room"))])
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
{
|
|
if (!ent->client->pers.inventory[ITEM_INDEX(FindItem("Chem_Plant_Key"))])
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
{
|
|
if (!ent->client->pers.inventory[ITEM_INDEX(FindItem("Bridge_Key"))])
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
{
|
|
if (!ent->client->pers.inventory[ITEM_INDEX(FindItem("Shipyard_Key"))])
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
{
|
|
if (!ent->client->pers.inventory[ITEM_INDEX(FindItem("Warehouse_Key"))])
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 7:
|
|
{
|
|
if (!ent->client->pers.inventory[ITEM_INDEX(FindItem("Shop_Key"))])
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
{
|
|
if (!ent->client->pers.inventory[ITEM_INDEX(FindItem("Ticket"))])
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
else
|
|
ent->client->pers.inventory[ITEM_INDEX(FindItem("Ticket"))] = 0;
|
|
}
|
|
break;
|
|
|
|
case 9:
|
|
{
|
|
if (!ent->client->pers.inventory[ITEM_INDEX(FindItem("Office_Key"))])
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 10:
|
|
{
|
|
if (!ent->client->pers.inventory[ITEM_INDEX(FindItem("key10"))])
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 11:
|
|
{
|
|
if (!(EP_UnlockDoorFlag (ent)))
|
|
{
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex("world/doors/dr_locked.wav"), 1, ATTN_NORM, 0);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ridah, once unlocked, stay unlocked
|
|
target->key = 0;
|
|
}
|
|
// END JOSEPH
|
|
|
|
// we have a valid one so lets flag it
|
|
target->activate_flags |= ACTIVATE_AND_OPEN;
|
|
break;
|
|
}
|
|
|
|
if (target)
|
|
if (target->activate_flags & ACTIVATE_AND_OPEN)
|
|
if (target->use)
|
|
{
|
|
// gi.dprintf( "%s, %s\n", target->classname, target->target );
|
|
target->use (target, ent, ent);
|
|
}
|
|
}
|
|
|
|
// Ridah, moveout command
|
|
if ((ent->cast_info.aiflags & AI_DOKEY || ent->cast_info.aiflags & AI_MOVEOUT) && ent->client->pers.friends > 0)
|
|
{
|
|
vec3_t start, end, dir;
|
|
trace_t tr;
|
|
|
|
AngleVectors( ent->client->ps.viewangles, dir, NULL, NULL );
|
|
|
|
VectorCopy( ent->s.origin, start );
|
|
start[2] += ent->viewheight;
|
|
|
|
VectorMA( start, 2048, dir, end );
|
|
|
|
tr = gi.trace( start, NULL, NULL, end, ent, MASK_SHOT );
|
|
|
|
if ( (tr.fraction < 1)
|
|
&& (tr.ent->svflags & SVF_MONSTER)
|
|
&& (tr.ent->health > 0)
|
|
&& (tr.ent->cast_group != ent->cast_group))
|
|
{
|
|
int i;
|
|
|
|
ent->moveout_ent = tr.ent;
|
|
|
|
// look for a friend to say this to
|
|
for (i=0; i<level.num_characters; i++)
|
|
{
|
|
if (!level.characters[i])
|
|
continue;
|
|
if (level.characters[i]->health <= 0)
|
|
continue;
|
|
if (level.characters[i]->leader != ent)
|
|
continue;
|
|
|
|
if (!(level.characters[i]->cast_info.aiflags & AI_MOVEOUT))
|
|
continue;
|
|
|
|
Voice_Random( ent, level.characters[i], hiredguy_combat_moveout, NUM_HIREDGUY_COMBAT_MOVEOUT );
|
|
break;
|
|
}
|
|
}
|
|
|
|
else if (ent->cast_info.aiflags & AI_DOKEY)
|
|
{
|
|
EP_Check_DoKey (ent, tr.ent);
|
|
// gi.dprintf ("gave a go do key order\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
// END JOSEPH
|
|
|
|
// RAFAEL 01-11-99
|
|
void Cmd_Reload_f (edict_t *ent)
|
|
{
|
|
gclient_t *cl;
|
|
|
|
cl = ent->client;
|
|
|
|
if (!cl->pers.weapon)
|
|
return;
|
|
|
|
// Ridah, fixes Tommygun reloading twice, if hit "reload" as it starts to auto-reload when out of ammo
|
|
if (ent->client->weaponstate == WEAPON_RELOADING)
|
|
return;
|
|
|
|
if (ent->client->weaponstate != WEAPON_READY)
|
|
return;
|
|
|
|
ent->client->reload_weapon = true;
|
|
}
|
|
// END 01-11-99
|
|
|
|
|
|
// JOSEPH 6-FEB-99
|
|
void Cmd_Holster_f (edict_t *ent)
|
|
{
|
|
gclient_t *cl;
|
|
|
|
if (deathmatch->value)
|
|
return;
|
|
|
|
if (level.bar_lvl)
|
|
{
|
|
gi.dprintf ("no weapons on this level\n");
|
|
return;
|
|
}
|
|
|
|
cl = ent->client;
|
|
|
|
if (!cl->pers.holsteredweapon)
|
|
{
|
|
if (!cl->pers.weapon)
|
|
return;
|
|
|
|
cl->pers.holsteredweapon = cl->pers.weapon;
|
|
cl->newweapon = NULL;
|
|
cl->weaponstate = WEAPON_DROPPING;
|
|
|
|
if (ent->s.renderfx2 & RF2_FLAMETHROWER)
|
|
ent->s.renderfx2 &= ~RF2_FLAMETHROWER;
|
|
}
|
|
else
|
|
{
|
|
if (cl->ps.gunindex != 0)
|
|
return;
|
|
|
|
cl->newweapon = cl->pers.holsteredweapon;
|
|
ChangeWeapon (ent);
|
|
cl->pers.holsteredweapon = 0;
|
|
}
|
|
}
|
|
|
|
void Cmd_HolsterBar_f (edict_t *ent)
|
|
{
|
|
gclient_t *cl;
|
|
|
|
cl = ent->client;
|
|
|
|
if (deathmatch->value)
|
|
return;
|
|
|
|
if (level.bar_lvl)
|
|
{
|
|
if (!cl->pers.holsteredweapon)
|
|
{
|
|
if (!cl->pers.weapon)
|
|
return;
|
|
|
|
cl->pers.holsteredweapon = cl->pers.weapon;
|
|
//cl->newweapon = NULL;
|
|
//cl->weaponstate = WEAPON_DROPPING;
|
|
cl->ps.gunindex = 0;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
if (cl->ps.gunindex != 0)
|
|
return;
|
|
|
|
cl->newweapon = cl->pers.holsteredweapon;
|
|
ChangeWeapon (ent);
|
|
cl->pers.holsteredweapon = 0;
|
|
}
|
|
|
|
|
|
}
|
|
// END JOSEPH
|
|
|
|
// JOSEPH 29-DEC-98
|
|
void Cmd_Hud_f (edict_t *ent)
|
|
{
|
|
gi.WriteByte (svc_hud);
|
|
gi.unicast (ent, true);
|
|
}
|
|
// END JOSEPH
|
|
|
|
void Cmd_Flashlight_f (edict_t *ent)
|
|
{
|
|
if (!ent->client->flashlight && ent->client->pers.inventory[ITEM_INDEX(FindItem("Flashlight"))])
|
|
ent->client->flashlight = true;
|
|
else
|
|
ent->client->flashlight = false;
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
Cmd_WeapNext_f
|
|
=================
|
|
*/
|
|
void Cmd_WeapNext_f (edict_t *ent)
|
|
{
|
|
gclient_t *cl;
|
|
int i, index;
|
|
gitem_t *it;
|
|
int selected_weapon;
|
|
|
|
cl = ent->client;
|
|
|
|
// JOSEPH 10-FEB-99
|
|
if (cl->pers.holsteredweapon)
|
|
{
|
|
if (level.bar_lvl)
|
|
return;
|
|
|
|
cl->newweapon = cl->pers.holsteredweapon;
|
|
ChangeWeapon (ent);
|
|
cl->pers.holsteredweapon = 0;
|
|
return;
|
|
}
|
|
// END JOSEPH
|
|
|
|
if (!cl->pers.weapon)
|
|
return;
|
|
|
|
// Ridah, if already changing weapons, start from the next weapon, for faster cycling
|
|
if (ent->client->weaponstate == WEAPON_DROPPING)
|
|
{
|
|
selected_weapon = ITEM_INDEX(cl->newweapon);
|
|
}
|
|
else
|
|
{
|
|
selected_weapon = ITEM_INDEX(cl->pers.weapon);
|
|
}
|
|
|
|
// scan for the next valid one
|
|
for (i=1 ; i<=MAX_ITEMS ; i++)
|
|
{
|
|
index = (selected_weapon + MAX_ITEMS - i)%MAX_ITEMS;
|
|
|
|
if (!cl->pers.inventory[index])
|
|
continue;
|
|
it = &itemlist[index];
|
|
if (!it->use)
|
|
continue;
|
|
if (! (it->flags & IT_WEAPON) )
|
|
continue;
|
|
if (selected_weapon == ITEM_INDEX(it) && cl->newweapon)
|
|
{
|
|
// Ridah, show the current weapon on the hud, for easy scrolling
|
|
if (deathmatch->value && !strstr(cl->newweapon->icon, "pipe"))
|
|
{
|
|
it = cl->newweapon;
|
|
ent->client->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(it->icon);
|
|
ent->client->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS+ITEM_INDEX(it);
|
|
ent->client->pickup_msg_time = level.time + 5.5;
|
|
}
|
|
|
|
return; // successful
|
|
}
|
|
else
|
|
{
|
|
it->use (ent, it);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Cmd_WeapLast_f
|
|
=================
|
|
*/
|
|
void Cmd_WeapLast_f (edict_t *ent)
|
|
{
|
|
gclient_t *cl;
|
|
int index;
|
|
gitem_t *it;
|
|
|
|
cl = ent->client;
|
|
|
|
if (!cl->pers.weapon || !cl->pers.lastweapon)
|
|
return;
|
|
|
|
index = ITEM_INDEX(cl->pers.lastweapon);
|
|
if (!cl->pers.inventory[index])
|
|
return;
|
|
it = &itemlist[index];
|
|
if (!it->use)
|
|
return;
|
|
if (! (it->flags & IT_WEAPON) )
|
|
return;
|
|
it->use (ent, it);
|
|
|
|
// Ridah, show the current weapon on the hud, for easy scrolling
|
|
if (deathmatch && !strstr(it->icon, "pipe"))
|
|
{
|
|
ent->client->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(it->icon);
|
|
ent->client->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS+ITEM_INDEX(it);
|
|
ent->client->pickup_msg_time = level.time + 5.5;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Cmd_InvDrop_f
|
|
=================
|
|
*/
|
|
void Cmd_InvDrop_f (edict_t *ent)
|
|
{
|
|
gitem_t *it;
|
|
int index;
|
|
char *s;
|
|
|
|
s = gi.args();
|
|
|
|
ValidateSelectedItem (ent);
|
|
|
|
if (ent->client->pers.selected_item == -1)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "No item to drop.\n");
|
|
return;
|
|
}
|
|
|
|
it = &itemlist[ent->client->pers.selected_item];
|
|
if (!it->drop)
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
|
|
return;
|
|
}
|
|
|
|
index = ITEM_INDEX(it);
|
|
if (!ent->client->pers.inventory[index])
|
|
{
|
|
gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
|
|
return;
|
|
}
|
|
|
|
it->drop (ent, it);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Cmd_Kill_f
|
|
=================
|
|
*/
|
|
void Cmd_Kill_f (edict_t *ent)
|
|
{
|
|
// don't let spectators kill themselves
|
|
if (ent->solid == SOLID_NOT)
|
|
return;
|
|
|
|
if((level.time - ent->client->respawn_time) < 5)
|
|
return;
|
|
ent->flags &= ~FL_GODMODE;
|
|
ent->health = 0;
|
|
meansOfDeath = MOD_SUICIDE;
|
|
player_die (ent, ent, ent, 1, vec3_origin, 0, 0);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Cmd_PutAway_f
|
|
=================
|
|
*/
|
|
void Cmd_PutAway_f (edict_t *ent)
|
|
{
|
|
ent->client->showscores = false;
|
|
ent->client->showhelp = false;
|
|
ent->client->showinventory = false;
|
|
}
|
|
|
|
int PlayerSort (void const *a, void const *b)
|
|
{
|
|
int anum, bnum;
|
|
|
|
anum = *(int *)a;
|
|
bnum = *(int *)b;
|
|
|
|
anum = game.clients[anum].ps.stats[STAT_FRAGS];
|
|
bnum = game.clients[bnum].ps.stats[STAT_FRAGS];
|
|
|
|
if (anum < bnum)
|
|
return -1;
|
|
if (anum > bnum)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Cmd_Players_f
|
|
=================
|
|
*/
|
|
void Cmd_Players_f (edict_t *ent)
|
|
{
|
|
int i;
|
|
int count;
|
|
char small[64];
|
|
char large[1280];
|
|
int index[256];
|
|
|
|
count = 0;
|
|
for (i = 0 ; i < maxclients->value ; i++)
|
|
if (game.clients[i].pers.connected)
|
|
{
|
|
index[count] = i;
|
|
count++;
|
|
}
|
|
|
|
// sort by frags
|
|
// Ridah, disabled, so we can use this to list players we might want to "vote ban"
|
|
// qsort (index, count, sizeof(index[0]), PlayerSort);
|
|
|
|
// print information
|
|
large[0] = 0;
|
|
|
|
for (i = 0 ; i < count ; i++)
|
|
{
|
|
Com_sprintf (small, sizeof(small), "%3i - %s (%i frags)\n",
|
|
index[i] + 1,
|
|
game.clients[index[i]].pers.netname,
|
|
game.clients[index[i]].ps.stats[STAT_FRAGS] );
|
|
if (strlen (small) + strlen(large) > sizeof(large) - 100 )
|
|
{ // can't print all of them in one packet
|
|
strcat (large, "...\n");
|
|
break;
|
|
}
|
|
strcat (large, small);
|
|
}
|
|
|
|
gi.cprintf (ent, PRINT_HIGH, "%s\n%i players\n", large, count);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
Cmd_Wave_f
|
|
=================
|
|
*/
|
|
void Cmd_Wave_f (edict_t *ent, edict_t *other)
|
|
{
|
|
char *cmd;
|
|
int rnd;
|
|
|
|
cmd = gi.argv(0);
|
|
|
|
if (!other->client)
|
|
return;
|
|
|
|
if (!ent->solid)
|
|
return;
|
|
|
|
// can't wave when ducked
|
|
if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
|
|
return;
|
|
|
|
if (ent->client->last_wave > (level.time - 2) && (ent->client->last_wave <= level.time))
|
|
return;
|
|
|
|
ent->client->last_wave = level.time;
|
|
|
|
// say something
|
|
{
|
|
|
|
if (!teamplay->value || (ent->client->pers.team != other->client->pers.team))
|
|
{
|
|
if (strstr(cmd, "key1"))
|
|
{
|
|
if (ent->gender == GENDER_MALE)
|
|
Voice_Random(ent, other, player_profanity_level2, NUM_PLAYER_PROFANITY_LEVEL2);
|
|
else if (ent->gender == GENDER_FEMALE)
|
|
Voice_Random(ent, other, f_profanity_level2, F_NUM_PROFANITY_LEVEL2);
|
|
}
|
|
else // profanity 3
|
|
{
|
|
if (ent->gender == GENDER_MALE)
|
|
Voice_Random(ent, other, player_profanity_level3, NUM_PLAYER_PROFANITY_LEVEL3);
|
|
else if (ent->gender == GENDER_FEMALE)
|
|
Voice_Random(ent, other, f_profanity_level3, F_NUM_PROFANITY_LEVEL3);
|
|
}
|
|
}
|
|
else // stay here/moving out
|
|
{
|
|
if (strstr(cmd, "key3"))
|
|
{ // hold
|
|
if (ent->gender == GENDER_MALE)
|
|
Voice_Random(ent, other, holdposition, NUM_HOLDPOSITION);
|
|
else if (ent->gender == GENDER_FEMALE)
|
|
// Voice_Random(ent, other, f_holdposition, F_NUM_HOLDPOSITION);
|
|
Voice_Random(ent, other, rc_f_profanity_level1, 5);
|
|
}
|
|
else if (strstr(cmd, "key2")) // lets go
|
|
{
|
|
if (ent->gender == GENDER_MALE)
|
|
Voice_Random(ent, other, followme, NUM_FOLLOWME);
|
|
else if (ent->gender == GENDER_FEMALE)
|
|
// Voice_Random(ent, other, f_followme, F_NUM_FOLLOWME);
|
|
Voice_Random(ent, other, rc_lola, 7);
|
|
}
|
|
else // converse
|
|
{
|
|
if (ent->gender == GENDER_MALE)
|
|
{
|
|
if (other->gender == GENDER_FEMALE)
|
|
Voice_Random(ent, other, f_neutral_talk_player, F_NUM_NEUTRAL_TALK_PLAYER);
|
|
else
|
|
Voice_Random(ent, other, neutral_talk_player, NUM_NEUTRAL_TALK_PLAYER);
|
|
}
|
|
else if (ent->gender == GENDER_FEMALE)
|
|
{
|
|
Voice_Random(ent, other, f_neutral_talk, F_NUM_NEUTRAL_TALK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ent->client->anim_priority > ANIM_WAVE)
|
|
return;
|
|
|
|
ent->client->anim_priority = ANIM_WAVE;
|
|
|
|
rnd = rand() % 3;
|
|
|
|
switch (rnd)
|
|
{
|
|
case 0:
|
|
// gi.cprintf (ent, PRINT_HIGH, "flipoff\n");
|
|
ent->s.frame = FRAME_tg_bird_01-1;
|
|
ent->client->anim_end = FRAME_tg_bird_10;
|
|
break;
|
|
case 1:
|
|
// gi.cprintf (ent, PRINT_HIGH, "salute\n");
|
|
ent->s.frame = FRAME_tg_crch_grab_01-1;
|
|
ent->client->anim_end = FRAME_tg_crch_grab_16;
|
|
break;
|
|
case 2:
|
|
// gi.cprintf (ent, PRINT_HIGH, "taunt\n");
|
|
ent->s.frame = FRAME_tg_chin_flip_01-1;
|
|
ent->client->anim_end = FRAME_tg_chin_flip_15;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Cmd_Say_f
|
|
==================
|
|
*/
|
|
void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0)
|
|
{
|
|
int i, j;
|
|
edict_t *other;
|
|
char *p;
|
|
char text[2048];
|
|
gclient_t *cl;
|
|
char *ip;
|
|
|
|
if (gi.argc () < 2 && !arg0)
|
|
return;
|
|
|
|
// don't let us talk if we were just kicked
|
|
ip = Info_ValueForKey( ent->client->pers.userinfo, "ip" );
|
|
if (ip && ip[0])
|
|
{
|
|
if (!strcmp(ip, last_kick_ip))
|
|
{
|
|
gi.cprintf( ent, PRINT_HIGH, "You cannot talk.\n" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!teamplay->value && !((int)(dmflags->value) & (DF_MODELTEAMS /*| DF_SKINTEAMS*/)))
|
|
team = false;
|
|
|
|
if (team)
|
|
Com_sprintf (text, sizeof(text), ":(%s): ", ent->client->pers.netname);
|
|
else
|
|
Com_sprintf (text, sizeof(text), ":%s: ", ent->client->pers.netname);
|
|
|
|
if (arg0)
|
|
{
|
|
strcat (text, gi.argv(0));
|
|
strcat (text, " ");
|
|
strcat (text, gi.args());
|
|
}
|
|
else
|
|
{
|
|
p = gi.args();
|
|
|
|
if (*p == '"')
|
|
{
|
|
p++;
|
|
p[strlen(p)-1] = 0;
|
|
}
|
|
strcat(text, p);
|
|
}
|
|
|
|
// don't let text be too long for malicious reasons
|
|
if (strlen(text) > 150)
|
|
text[150] = 0;
|
|
|
|
strcat(text, "\n");
|
|
|
|
if (flood_msgs->value) {
|
|
cl = ent->client;
|
|
|
|
if (level.time < cl->flood_locktill) {
|
|
gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n",
|
|
(int)(cl->flood_locktill - level.time));
|
|
return;
|
|
}
|
|
i = cl->flood_whenhead - flood_msgs->value + 1;
|
|
if (i < 0)
|
|
i = (sizeof(cl->flood_when)/sizeof(cl->flood_when[0])) + i;
|
|
if (cl->flood_when[i] &&
|
|
level.time - cl->flood_when[i] < flood_persecond->value) {
|
|
cl->flood_locktill = level.time + flood_waitdelay->value;
|
|
gi.cprintf(ent, PRINT_CHAT, "Flood protection: You can't talk for %d seconds.\n",
|
|
(int)flood_waitdelay->value);
|
|
return;
|
|
}
|
|
|
|
// if they repeat themselves really quickly, bitch-slap time
|
|
if (cl->flood_when[cl->flood_whenhead] && (cl->flood_when[cl->flood_whenhead] > level.time - 1) &&
|
|
!strcmp( ent->client->flood_lastmsg, text ))
|
|
{
|
|
cl->flood_locktill = level.time + flood_waitdelay->value;
|
|
gi.cprintf(ent, PRINT_CHAT, "Flood protection: You can't talk for %d seconds.\n",
|
|
(int)flood_waitdelay->value);
|
|
return;
|
|
}
|
|
|
|
cl->flood_whenhead = (cl->flood_whenhead + 1) %
|
|
(sizeof(cl->flood_when)/sizeof(cl->flood_when[0]));
|
|
cl->flood_when[cl->flood_whenhead] = level.time;
|
|
}
|
|
|
|
strcpy( ent->client->flood_lastmsg, text );
|
|
|
|
if (dedicated->value)
|
|
gi.cprintf(NULL, PRINT_CHAT, "%s", text);
|
|
|
|
for (j = 1; j <= game.maxclients; j++)
|
|
{
|
|
other = &g_edicts[j];
|
|
if (!(other->inuse))
|
|
continue;
|
|
if (!(other->client))
|
|
continue;
|
|
if (team)
|
|
{
|
|
if (!OnSameTeam(ent, other))
|
|
continue;
|
|
if ((ent->client->pers.team == 0) != (other->client->pers.team == 0))
|
|
continue;
|
|
}
|
|
gi.cprintf(other, PRINT_CHAT, "%s", text);
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
ClientCommand
|
|
=================
|
|
*/
|
|
void ClientCommand (edict_t *ent)
|
|
{
|
|
char *cmd;
|
|
|
|
if (!ent->client)
|
|
return; // not fully in game yet
|
|
|
|
if (!ent->inuse)
|
|
return;
|
|
|
|
cmd = gi.argv(0);
|
|
|
|
if (Q_stricmp (cmd, "players") == 0)
|
|
{
|
|
Cmd_Players_f (ent);
|
|
return;
|
|
}
|
|
if (Q_stricmp (cmd, "say") == 0)
|
|
{
|
|
Cmd_Say_f (ent, false, false);
|
|
return;
|
|
}
|
|
if (Q_stricmp (cmd, "say_team") == 0)
|
|
{
|
|
Cmd_Say_f (ent, true, false);
|
|
return;
|
|
}
|
|
if (Q_stricmp (cmd, "score") == 0)
|
|
{
|
|
Cmd_Score_f (ent);
|
|
return;
|
|
}
|
|
|
|
if (Q_stricmp (cmd, "help") == 0)
|
|
{
|
|
Cmd_Help_f (ent, 0);
|
|
return;
|
|
}
|
|
else if (Q_stricmp (cmd, "invnext") == 0)
|
|
{
|
|
if (!ent->client->chase_target)
|
|
Cmd_Help_f (ent, 1);
|
|
else
|
|
SelectNextItem (ent, -1);
|
|
|
|
return;
|
|
}
|
|
else if (Q_stricmp (cmd, "invprev") == 0)
|
|
{
|
|
if (!ent->client->chase_target)
|
|
Cmd_Help_f (ent, -1);
|
|
else
|
|
SelectPrevItem (ent, -1);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
if (level.intermissiontime)
|
|
return;
|
|
|
|
// RAFAEL
|
|
if (level.cut_scene_time)
|
|
return;
|
|
|
|
else if (level.pawn_time)
|
|
{
|
|
|
|
if (Q_stricmp (cmd, "invuse") == 0)
|
|
PawnBuy (ent);
|
|
|
|
else if (Q_stricmp (cmd, "leftarrow") == 0)
|
|
PawnLeft (ent);
|
|
else if (Q_stricmp (cmd, "rightarrow") == 0)
|
|
PawnRight (ent);
|
|
// JOSEPH 6-FEB-99
|
|
else if (Q_stricmp (cmd, "uparrow") == 0)
|
|
PawnPrev (ent);
|
|
else if (Q_stricmp (cmd, "downarrow") == 0)
|
|
PawnNext (ent);
|
|
// END JOSEPH
|
|
else if (Q_stricmp (cmd, "key1") == 0)
|
|
PawnAgree (ent);
|
|
else if (Q_stricmp (cmd, "key3") == 0)
|
|
PawnDisagree (ent);
|
|
|
|
else if (Q_stricmp (cmd, "inven") == 0)
|
|
Cmd_Inven_f (ent);
|
|
// not sure if we are going to have a sell key
|
|
// else if (Q_stricmp (cmd, "invnextw") == 0)
|
|
// PawnSell (ent);
|
|
return;
|
|
}
|
|
|
|
// JOSEPH 6-FEB-99
|
|
if (Q_stricmp (cmd, "leftarrow") == 0)
|
|
;
|
|
else if (Q_stricmp (cmd, "rightarrow") == 0)
|
|
;
|
|
else if (Q_stricmp (cmd, "uparrow") == 0)
|
|
;
|
|
else if (Q_stricmp (cmd, "downarrow") == 0)
|
|
;
|
|
else if (Q_stricmp (cmd, "use") == 0)
|
|
Cmd_Use_f (ent);
|
|
// END JOSEPH
|
|
else if (Q_stricmp (cmd, "drop") == 0)
|
|
Cmd_Drop_f (ent);
|
|
else if (Q_stricmp (cmd, "give") == 0)
|
|
Cmd_Give_f (ent);
|
|
else if (Q_stricmp (cmd, "immortal") == 0)
|
|
Cmd_God_f (ent);
|
|
else if (Q_stricmp (cmd, "notarget") == 0)
|
|
Cmd_Notarget_f (ent);
|
|
else if (Q_stricmp (cmd, "noclip") == 0)
|
|
Cmd_Noclip_f (ent);
|
|
else if (Q_stricmp (cmd, "inven") == 0)
|
|
Cmd_Inven_f (ent);
|
|
|
|
else if (Q_stricmp (cmd, "invnextw") == 0)
|
|
SelectNextItem (ent, IT_WEAPON);
|
|
else if (Q_stricmp (cmd, "invprevw") == 0)
|
|
SelectPrevItem (ent, IT_WEAPON);
|
|
else if (Q_stricmp (cmd, "invnextp") == 0)
|
|
SelectNextItem (ent, IT_POWERUP);
|
|
else if (Q_stricmp (cmd, "invprevp") == 0)
|
|
SelectPrevItem (ent, IT_POWERUP);
|
|
else if (Q_stricmp (cmd, "invuse") == 0)
|
|
Cmd_InvUse_f (ent);
|
|
else if (Q_stricmp (cmd, "invdrop") == 0)
|
|
Cmd_InvDrop_f (ent);
|
|
else if (Q_stricmp (cmd, "weapprev") == 0)
|
|
Cmd_WeapPrev_f (ent);
|
|
else if (Q_stricmp (cmd, "weapnext") == 0)
|
|
Cmd_WeapNext_f (ent);
|
|
// JOSEPH 29-DEC-98
|
|
else if (Q_stricmp (cmd, "+activate") == 0)
|
|
Cmd_Activate_f (ent);
|
|
else if (Q_stricmp (cmd, "holster") == 0)
|
|
Cmd_Holster_f (ent);
|
|
else if (Q_stricmp (cmd, "hud") == 0)
|
|
Cmd_Hud_f (ent);
|
|
// END JOSEPH
|
|
|
|
// RAFAEL
|
|
else if (Q_stricmp (cmd, "flashlight") == 0)
|
|
Cmd_Flashlight_f (ent);
|
|
// RAFAEL 01-11-99
|
|
else if (Q_stricmp (cmd, "reload") == 0)
|
|
Cmd_Reload_f (ent);
|
|
// END 01-11-99
|
|
else if (Q_stricmp (cmd, "weaplast") == 0)
|
|
Cmd_WeapLast_f (ent);
|
|
else if (Q_stricmp (cmd, "kill") == 0)
|
|
Cmd_Kill_f (ent);
|
|
else if (Q_stricmp (cmd, "putaway") == 0)
|
|
Cmd_PutAway_f (ent);
|
|
// else if (Q_stricmp (cmd, "wave") == 0)
|
|
// Cmd_Wave_f (ent);
|
|
// BEGIN: Xatrix/Ridah/Navigator/23-mar-1998
|
|
else if (Q_stricmp (cmd, "nav_debug_dest") == 0)
|
|
Cmd_NavDebugDest_f (ent);
|
|
else if (Q_stricmp (cmd, "nav_debug_showpath") == 0)
|
|
Cmd_NavDebugShowPath_f (ent);
|
|
else if (Q_stricmp (cmd, "nav_showpath") == 0)
|
|
Cmd_NavDebugShowPath_f (ent);
|
|
else if (Q_stricmp (cmd, "nav_save") == 0)
|
|
NAV_WriteActiveNodes ( ent->active_node_data, level.mapname );
|
|
else if (Q_stricmp (cmd, "nav_clear") == 0)
|
|
Cmd_NavClear_f ( ent );
|
|
else if (Q_stricmp (cmd, "nav_rebuild") == 0)
|
|
NAV_RebuildRoutes( level.node_data );
|
|
// END: Xatrix/Ridah/Navigator/23-mar-1998
|
|
|
|
else if (Q_stricmp (cmd, "spawn") == 0)
|
|
Cmd_Spawn_f (ent);
|
|
|
|
// Ridah, new 3 key command system
|
|
else if (strstr (cmd, "key") == cmd)
|
|
Cmd_Key_f (ent);
|
|
|
|
// Ridah, Chasecam
|
|
else if (Q_stricmp (cmd, "togglecam") == 0)
|
|
Cmd_ToggleCam_f (ent);
|
|
|
|
// Ridah, Lightpaint
|
|
else if (Q_stricmp (cmd, "burn_save") == 0)
|
|
Cmd_BurnSave_f (ent);
|
|
|
|
// Ridah, Vehicles
|
|
else if (Q_stricmp (cmd, "gear_up") == 0)
|
|
Cmd_GearUp_f (ent);
|
|
else if (Q_stricmp (cmd, "gear_down") == 0)
|
|
Cmd_GearDown_f (ent);
|
|
|
|
// else if (Q_stricmp (cmd, "gettexture") == 0)
|
|
// Cmd_GetTexture_f (ent);
|
|
|
|
// JOSEPH 23-MAR-99
|
|
else if (Q_stricmp (cmd, "hideprops") == 0)
|
|
Cmd_SetProps_f (0);
|
|
else if (Q_stricmp (cmd, "showprops") == 0)
|
|
Cmd_SetProps_f (1);
|
|
else if (Q_stricmp (cmd, "extracrispy") == 0)
|
|
Cmd_FryAll_f (ent);
|
|
// END JOSEPH
|
|
|
|
// else if (Q_stricmp (cmd, "gibtest") == 0)
|
|
// Cmd_GibTest_f (ent);
|
|
|
|
// Teamplay commands
|
|
else if ((Q_stricmp (cmd, "join") == 0) || (Q_stricmp (cmd, "team") == 0))
|
|
Cmd_Join_f (ent, gi.argv (1));
|
|
else if ((Q_stricmp (cmd, "spec") == 0) || (Q_stricmp (cmd, "spectator") == 0))
|
|
Cmd_Spec_f (ent);
|
|
|
|
// voting system
|
|
else if (Q_stricmp (cmd, "vote") == 0)
|
|
Cmd_Vote_f (ent);
|
|
else if ((Q_stricmp (cmd, "yes") == 0) || (Q_stricmp (cmd, "no") == 0))
|
|
Cmd_Response_f (ent);
|
|
|
|
#if 0 // turn this off once we have the tables (not used by actual game code)
|
|
// Ridah, new anorm calculations
|
|
else if (Q_stricmp (cmd, "calc_anorms") == 0)
|
|
Cmd_Anorms_f ();
|
|
else if (Q_stricmp (cmd, "calc_adots") == 0)
|
|
Cmd_Adots_f ();
|
|
// done.
|
|
#endif
|
|
|
|
else // anything that doesn't match a command will be a chat
|
|
Cmd_Say_f (ent, false, true);
|
|
|
|
}
|