forked from vera/halflife-thewastes-sdk
729 lines
18 KiB
C++
729 lines
18 KiB
C++
/***
|
|
*
|
|
* Copyright (c) 1999, Valve LLC. All rights reserved.
|
|
*
|
|
* This product contains software technology licensed from Id
|
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* Use, distribution, and modification of this source code and/or resulting
|
|
* object code is restricted to non-commercial enhancements to products from
|
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
|
* without written permission from Valve LLC.
|
|
*
|
|
****/
|
|
// Robin, 4-22-98: Moved set_suicide_frame() here from player.cpp to allow us to
|
|
// have one without a hardcoded player.mdl in tf_client.cpp
|
|
|
|
/*
|
|
|
|
===== client.cpp ========================================================
|
|
|
|
client/server game specific stuff
|
|
|
|
*/
|
|
|
|
#include "extdll.h"
|
|
#include "util.h"
|
|
#include "cbase.h"
|
|
#include "saverestore.h"
|
|
#include "player.h"
|
|
#include "spectator.h"
|
|
#include "client.h"
|
|
#include "soundent.h"
|
|
#include "gamerules.h"
|
|
|
|
extern DLL_GLOBAL ULONG g_ulModelIndexPlayer;
|
|
extern DLL_GLOBAL BOOL g_fGameOver;
|
|
extern DLL_GLOBAL int g_iSkillLevel;
|
|
extern DLL_GLOBAL ULONG g_ulFrameCount;
|
|
|
|
extern void CopyToBodyQue(entvars_t* pev);
|
|
extern int giPrecacheGrunt;
|
|
extern int gmsgSayText;
|
|
|
|
|
|
/*
|
|
* used by kill command and disconnect command
|
|
* ROBIN: Moved here from player.cpp, to allow multiple player models
|
|
*/
|
|
void set_suicide_frame(entvars_t* pev)
|
|
{
|
|
if (!FStrEq(STRING(pev->model), "models/player.mdl"))
|
|
return; // allready gibbed
|
|
|
|
// pev->frame = $deatha11;
|
|
pev->solid = SOLID_NOT;
|
|
pev->movetype = MOVETYPE_TOSS;
|
|
pev->deadflag = DEAD_DEAD;
|
|
pev->nextthink = -1;
|
|
}
|
|
|
|
|
|
/*
|
|
===========
|
|
ClientConnect
|
|
|
|
called when a player connects to a server
|
|
============
|
|
*/
|
|
BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] )
|
|
{
|
|
return g_pGameRules->ClientConnected( pEntity, pszName, pszAddress, szRejectReason );
|
|
|
|
// a client connecting during an intermission can cause problems
|
|
// if (intermission_running)
|
|
// ExitIntermission ();
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
===========
|
|
ClientDisconnect
|
|
|
|
called when a player disconnects from a server
|
|
|
|
GLOBALS ASSUMED SET: g_fGameOver
|
|
============
|
|
*/
|
|
void ClientDisconnect( edict_t *pEntity )
|
|
{
|
|
if (g_fGameOver)
|
|
return;
|
|
|
|
char text[256];
|
|
sprintf( text, "- %s has left the game\n", STRING(pEntity->v.netname) );
|
|
MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL );
|
|
WRITE_BYTE( ENTINDEX(pEntity) );
|
|
WRITE_STRING( text );
|
|
MESSAGE_END();
|
|
|
|
CSound *pSound;
|
|
pSound = CSoundEnt::SoundPointerForIndex( CSoundEnt::ClientSoundIndex( pEntity ) );
|
|
{
|
|
// since this client isn't around to think anymore, reset their sound.
|
|
if ( pSound )
|
|
{
|
|
pSound->Reset();
|
|
}
|
|
}
|
|
|
|
// since the edict doesn't get deleted, fix it so it doesn't interfere.
|
|
pEntity->v.takedamage = DAMAGE_NO;// don't attract autoaim
|
|
pEntity->v.solid = SOLID_NOT;// nonsolid
|
|
UTIL_SetOrigin ( &pEntity->v, pEntity->v.origin );
|
|
|
|
g_pGameRules->ClientDisconnected( pEntity );
|
|
}
|
|
|
|
|
|
// called by ClientKill and DeadThink
|
|
void respawn(entvars_t* pev, BOOL fCopyCorpse)
|
|
{
|
|
if (gpGlobals->coop || gpGlobals->deathmatch)
|
|
{
|
|
if ( fCopyCorpse )
|
|
{
|
|
// make a copy of the dead body for appearances sake
|
|
CopyToBodyQue(pev);
|
|
}
|
|
|
|
// respawn player
|
|
GetClassPtr( (CBasePlayer *)pev)->Spawn( );
|
|
}
|
|
else
|
|
{ // restart the entire server
|
|
SERVER_COMMAND("reload\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
ClientKill
|
|
|
|
Player entered the suicide command
|
|
|
|
GLOBALS ASSUMED SET: g_ulModelIndexPlayer
|
|
============
|
|
*/
|
|
void ClientKill( edict_t *pEntity )
|
|
{
|
|
entvars_t *pev = &pEntity->v;
|
|
|
|
CBasePlayer *pl = (CBasePlayer*) CBasePlayer::Instance( pev );
|
|
|
|
if ( pl->m_fNextSuicideTime > gpGlobals->time )
|
|
return; // prevent suiciding too ofter
|
|
|
|
pl->m_fNextSuicideTime = gpGlobals->time + 1; // don't let them suicide for 5 seconds after suiciding
|
|
|
|
// have the player kill themself
|
|
pev->health = 0;
|
|
pl->Killed( pev, GIB_NEVER );
|
|
|
|
// pev->modelindex = g_ulModelIndexPlayer;
|
|
// pev->frags -= 2; // extra penalty
|
|
// respawn( pev );
|
|
}
|
|
|
|
/*
|
|
===========
|
|
ClientPutInServer
|
|
|
|
called each time a player is spawned
|
|
============
|
|
*/
|
|
void ClientPutInServer( edict_t *pEntity )
|
|
{
|
|
CBasePlayer *pPlayer;
|
|
|
|
entvars_t *pev = &pEntity->v;
|
|
|
|
pPlayer = GetClassPtr((CBasePlayer *)pev);
|
|
pPlayer->SetCustomDecalFrames(-1); // Assume none;
|
|
|
|
// Allocate a CBasePlayer for pev, and call spawn
|
|
pPlayer->Spawn() ;
|
|
}
|
|
|
|
//// HOST_SAY
|
|
// String comes in as
|
|
// say blah blah blah
|
|
// or as
|
|
// blah blah blah
|
|
//
|
|
void Host_Say( edict_t *pEntity, int teamonly )
|
|
{
|
|
CBasePlayer *client;
|
|
int j;
|
|
char *p;
|
|
char text[128];
|
|
char szTemp[256];
|
|
const char *cpSay = "say";
|
|
const char *cpSayTeam = "say_team";
|
|
const char *pcmd = CMD_ARGV(0);
|
|
|
|
// We can get a raw string now, without the "say " prepended
|
|
if ( CMD_ARGC() == 0 )
|
|
return;
|
|
|
|
if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) )
|
|
{
|
|
if ( CMD_ARGC() >= 2 )
|
|
{
|
|
p = (char *)CMD_ARGS();
|
|
}
|
|
else
|
|
{
|
|
// say with a blank message, nothing to do
|
|
return;
|
|
}
|
|
}
|
|
else // Raw text, need to prepend argv[0]
|
|
{
|
|
if ( CMD_ARGC() >= 2 )
|
|
{
|
|
sprintf( szTemp, "%s %s", ( char * )pcmd, (char *)CMD_ARGS() );
|
|
}
|
|
else
|
|
{
|
|
// Just a one word command, use the first word...sigh
|
|
sprintf( szTemp, "%s", ( char * )pcmd );
|
|
}
|
|
p = szTemp;
|
|
}
|
|
|
|
// remove quotes if present
|
|
if (*p == '"')
|
|
{
|
|
p++;
|
|
p[strlen(p)-1] = 0;
|
|
}
|
|
|
|
// make sure the text has content
|
|
for ( char *pc = p; pc != NULL && *pc != 0; pc++ )
|
|
{
|
|
if ( isprint( *pc ) && !isspace( *pc ) )
|
|
{
|
|
pc = NULL; // we've found an alphanumeric character, so text is valid
|
|
break;
|
|
}
|
|
}
|
|
if ( pc != NULL )
|
|
return; // no character found, so say nothing
|
|
|
|
// turn on color set 2 (color on, no sound)
|
|
if ( teamonly )
|
|
sprintf( text, "%c(TEAM) %s: ", 2, STRING( pEntity->v.netname ) );
|
|
else
|
|
sprintf( text, "%c%s: ", 2, STRING( pEntity->v.netname ) );
|
|
|
|
j = sizeof(text) - 2 - strlen(text); // -2 for /n and null terminator
|
|
if ( (int)strlen(p) > j )
|
|
p[j] = 0;
|
|
|
|
strcat( text, p );
|
|
strcat( text, "\n" );
|
|
|
|
// loop through all players
|
|
// Start with the first player.
|
|
// This may return the world in single player if the client types something between levels or during spawn
|
|
// so check it, or it will infinite loop
|
|
|
|
client = NULL;
|
|
while ( ((client = (CBasePlayer*)UTIL_FindEntityByClassname( client, "player" )) != NULL) && (!FNullEnt(client->edict())) )
|
|
{
|
|
if ( !client->pev )
|
|
continue;
|
|
|
|
if ( client->edict() == pEntity )
|
|
continue;
|
|
|
|
if ( !(client->IsNetClient()) ) // Not a client ? (should never be true)
|
|
continue;
|
|
|
|
if ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE )
|
|
continue;
|
|
|
|
MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, client->pev );
|
|
WRITE_BYTE( ENTINDEX(client->edict()) );
|
|
WRITE_STRING( text );
|
|
MESSAGE_END();
|
|
|
|
}
|
|
|
|
// print to the sending client
|
|
MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, &pEntity->v );
|
|
WRITE_BYTE( ENTINDEX(pEntity) );
|
|
WRITE_STRING( text );
|
|
MESSAGE_END();
|
|
|
|
// echo to server console
|
|
g_engfuncs.pfnServerPrint( text );
|
|
}
|
|
|
|
|
|
/*
|
|
===========
|
|
ClientCommand
|
|
called each time a player uses a "cmd" command
|
|
============
|
|
*/
|
|
extern float g_flWeaponCheat;
|
|
|
|
// Use CMD_ARGV, CMD_ARGV, and CMD_ARGC to get pointers the character string command.
|
|
void ClientCommand( edict_t *pEntity )
|
|
{
|
|
const char *pcmd = CMD_ARGV(0);
|
|
const char *pstr;
|
|
|
|
// Is the client spawned yet?
|
|
if ( !pEntity->pvPrivateData )
|
|
return;
|
|
|
|
entvars_t *pev = &pEntity->v;
|
|
|
|
if ( FStrEq(pcmd, "say" ) )
|
|
{
|
|
Host_Say( pEntity, 0 );
|
|
}
|
|
else if ( FStrEq(pcmd, "say_team" ) )
|
|
{
|
|
Host_Say( pEntity, 1 );
|
|
}
|
|
else if ( FStrEq(pcmd, "give" ) )
|
|
{
|
|
if ( g_flWeaponCheat != 0.0)
|
|
{
|
|
int iszItem = ALLOC_STRING( CMD_ARGV(1) ); // Make a copy of the classname
|
|
GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) );
|
|
}
|
|
}
|
|
|
|
else if ( FStrEq(pcmd, "drop" ) )
|
|
{
|
|
// player is dropping an item.
|
|
GetClassPtr((CBasePlayer *)pev)->DropPlayerItem((char *)CMD_ARGV(1));
|
|
}
|
|
else if ( FStrEq(pcmd, "fov" ) )
|
|
{
|
|
if ( g_flWeaponCheat && CMD_ARGC() > 1)
|
|
{
|
|
GetClassPtr((CBasePlayer *)pev)->m_iFOV = atoi( CMD_ARGV(1) );
|
|
}
|
|
else
|
|
{
|
|
CLIENT_PRINTF( pEntity, print_console, UTIL_VarArgs( "\"fov\" is \"%d\"\n", (int)GetClassPtr((CBasePlayer *)pev)->m_iFOV ) );
|
|
}
|
|
}
|
|
else if ( FStrEq(pcmd, "use" ) )
|
|
{
|
|
GetClassPtr((CBasePlayer *)pev)->SelectItem((char *)CMD_ARGV(1));
|
|
}
|
|
else if (((pstr = strstr(pcmd, "weapon_")) != NULL) && (pstr == pcmd))
|
|
{
|
|
GetClassPtr((CBasePlayer *)pev)->SelectItem(pcmd);
|
|
}
|
|
else if (FStrEq(pcmd, "lastinv" ))
|
|
{
|
|
GetClassPtr((CBasePlayer *)pev)->SelectLastItem();
|
|
}
|
|
else if ( g_pGameRules->ClientCommand( GetClassPtr((CBasePlayer *)pev), pcmd ) )
|
|
{
|
|
// MenuSelect returns true only if the command is properly handled, so don't print a warning
|
|
}
|
|
else
|
|
{
|
|
// tell the user they entered an unknown command
|
|
ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Unknown command: %s\n", pcmd ) );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
ClientUserInfoChanged
|
|
|
|
called after the player changes
|
|
userinfo - gives dll a chance to modify it before
|
|
it gets sent into the rest of the engine.
|
|
========================
|
|
*/
|
|
void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer )
|
|
{
|
|
// Is the client spawned yet?
|
|
if ( !pEntity->pvPrivateData )
|
|
return;
|
|
|
|
// msg everyone if someone changes their name, and it isn't the first time (changing no name to current name)
|
|
if ( pEntity->v.netname && STRING(pEntity->v.netname)[0] != 0 && !FStrEq( STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" )) )
|
|
{
|
|
char text[256];
|
|
sprintf( text, "* %s changed name to %s\n", STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) );
|
|
MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL );
|
|
WRITE_BYTE( ENTINDEX(pEntity) );
|
|
WRITE_STRING( text );
|
|
MESSAGE_END();
|
|
|
|
UTIL_LogPrintf( "\"%s<%i>\" changed name to \"%s<%i>\"\n", STRING( pEntity->v.netname ), GETPLAYERUSERID( pEntity ), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ), GETPLAYERUSERID( pEntity ) );
|
|
}
|
|
|
|
g_pGameRules->ClientUserInfoChanged( GetClassPtr((CBasePlayer *)&pEntity->v), infobuffer );
|
|
}
|
|
|
|
|
|
void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
|
|
{
|
|
int i;
|
|
CBaseEntity *pClass;
|
|
|
|
// Clients have not been initialized yet
|
|
for ( i = 0; i < edictCount; i++ )
|
|
{
|
|
if ( pEdictList[i].free )
|
|
continue;
|
|
|
|
// Clients aren't necessarily initialized until ClientPutInServer()
|
|
if ( i < clientMax || !pEdictList[i].pvPrivateData )
|
|
continue;
|
|
|
|
pClass = CBaseEntity::Instance( &pEdictList[i] );
|
|
// Activate this entity if it's got a class & isn't dormant
|
|
if ( pClass && !(pClass->pev->flags & FL_DORMANT) )
|
|
{
|
|
pClass->Activate();
|
|
}
|
|
else
|
|
{
|
|
ALERT( at_console, "Can't instance %s\n", STRING(pEdictList[i].v.classname) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
PlayerPreThink
|
|
|
|
Called every frame before physics are run
|
|
================
|
|
*/
|
|
void PlayerPreThink( edict_t *pEntity )
|
|
{
|
|
entvars_t *pev = &pEntity->v;
|
|
CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity);
|
|
|
|
if (pPlayer)
|
|
pPlayer->PreThink( );
|
|
}
|
|
|
|
/*
|
|
================
|
|
PlayerPostThink
|
|
|
|
Called every frame after physics are run
|
|
================
|
|
*/
|
|
void PlayerPostThink( edict_t *pEntity )
|
|
{
|
|
entvars_t *pev = &pEntity->v;
|
|
CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity);
|
|
|
|
if (pPlayer)
|
|
pPlayer->PostThink( );
|
|
}
|
|
|
|
|
|
|
|
void ParmsNewLevel( void )
|
|
{
|
|
}
|
|
|
|
|
|
void ParmsChangeLevel( void )
|
|
{
|
|
// retrieve the pointer to the save data
|
|
SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData;
|
|
|
|
if ( pSaveData )
|
|
pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS );
|
|
}
|
|
|
|
|
|
//
|
|
// GLOBALS ASSUMED SET: g_ulFrameCount
|
|
//
|
|
void StartFrame( void )
|
|
{
|
|
if ( g_pGameRules )
|
|
g_pGameRules->Think();
|
|
|
|
if ( g_fGameOver )
|
|
return;
|
|
|
|
gpGlobals->teamplay = CVAR_GET_FLOAT("teamplay");
|
|
g_iSkillLevel = CVAR_GET_FLOAT("skill");
|
|
g_ulFrameCount++;
|
|
}
|
|
|
|
|
|
void ClientPrecache( void )
|
|
{
|
|
// setup precaches always needed
|
|
PRECACHE_SOUND("player/sprayer.wav"); // spray paint sound for PreAlpha
|
|
|
|
// PRECACHE_SOUND("player/pl_jumpland2.wav"); // UNDONE: play 2x step sound
|
|
|
|
PRECACHE_SOUND("player/pl_fallpain2.wav");
|
|
PRECACHE_SOUND("player/pl_fallpain3.wav");
|
|
|
|
PRECACHE_SOUND("player/pl_step1.wav"); // walk on concrete
|
|
PRECACHE_SOUND("player/pl_step2.wav");
|
|
PRECACHE_SOUND("player/pl_step3.wav");
|
|
PRECACHE_SOUND("player/pl_step4.wav");
|
|
|
|
PRECACHE_SOUND("common/npc_step1.wav"); // NPC walk on concrete
|
|
PRECACHE_SOUND("common/npc_step2.wav");
|
|
PRECACHE_SOUND("common/npc_step3.wav");
|
|
PRECACHE_SOUND("common/npc_step4.wav");
|
|
|
|
PRECACHE_SOUND("player/pl_metal1.wav"); // walk on metal
|
|
PRECACHE_SOUND("player/pl_metal2.wav");
|
|
PRECACHE_SOUND("player/pl_metal3.wav");
|
|
PRECACHE_SOUND("player/pl_metal4.wav");
|
|
|
|
PRECACHE_SOUND("player/pl_dirt1.wav"); // walk on dirt
|
|
PRECACHE_SOUND("player/pl_dirt2.wav");
|
|
PRECACHE_SOUND("player/pl_dirt3.wav");
|
|
PRECACHE_SOUND("player/pl_dirt4.wav");
|
|
|
|
PRECACHE_SOUND("player/pl_duct1.wav"); // walk in duct
|
|
PRECACHE_SOUND("player/pl_duct2.wav");
|
|
PRECACHE_SOUND("player/pl_duct3.wav");
|
|
PRECACHE_SOUND("player/pl_duct4.wav");
|
|
|
|
PRECACHE_SOUND("player/pl_grate1.wav"); // walk on grate
|
|
PRECACHE_SOUND("player/pl_grate2.wav");
|
|
PRECACHE_SOUND("player/pl_grate3.wav");
|
|
PRECACHE_SOUND("player/pl_grate4.wav");
|
|
|
|
PRECACHE_SOUND("player/pl_slosh1.wav"); // walk in shallow water
|
|
PRECACHE_SOUND("player/pl_slosh2.wav");
|
|
PRECACHE_SOUND("player/pl_slosh3.wav");
|
|
PRECACHE_SOUND("player/pl_slosh4.wav");
|
|
|
|
PRECACHE_SOUND("player/pl_tile1.wav"); // walk on tile
|
|
PRECACHE_SOUND("player/pl_tile2.wav");
|
|
PRECACHE_SOUND("player/pl_tile3.wav");
|
|
PRECACHE_SOUND("player/pl_tile4.wav");
|
|
PRECACHE_SOUND("player/pl_tile5.wav");
|
|
|
|
PRECACHE_SOUND("player/pl_swim1.wav"); // breathe bubbles
|
|
PRECACHE_SOUND("player/pl_swim2.wav");
|
|
PRECACHE_SOUND("player/pl_swim3.wav");
|
|
PRECACHE_SOUND("player/pl_swim4.wav");
|
|
|
|
PRECACHE_SOUND("player/pl_ladder1.wav"); // climb ladder rung
|
|
PRECACHE_SOUND("player/pl_ladder2.wav");
|
|
PRECACHE_SOUND("player/pl_ladder3.wav");
|
|
PRECACHE_SOUND("player/pl_ladder4.wav");
|
|
|
|
PRECACHE_SOUND("player/pl_wade1.wav"); // wade in water
|
|
PRECACHE_SOUND("player/pl_wade2.wav");
|
|
PRECACHE_SOUND("player/pl_wade3.wav");
|
|
PRECACHE_SOUND("player/pl_wade4.wav");
|
|
|
|
PRECACHE_SOUND("debris/wood1.wav"); // hit wood texture
|
|
PRECACHE_SOUND("debris/wood2.wav");
|
|
PRECACHE_SOUND("debris/wood3.wav");
|
|
|
|
PRECACHE_SOUND("plats/train_use1.wav"); // use a train
|
|
|
|
PRECACHE_SOUND("buttons/spark5.wav"); // hit computer texture
|
|
PRECACHE_SOUND("buttons/spark6.wav");
|
|
PRECACHE_SOUND("debris/glass1.wav");
|
|
PRECACHE_SOUND("debris/glass2.wav");
|
|
PRECACHE_SOUND("debris/glass3.wav");
|
|
|
|
PRECACHE_SOUND( SOUND_FLASHLIGHT_ON );
|
|
PRECACHE_SOUND( SOUND_FLASHLIGHT_OFF );
|
|
|
|
// player gib sounds
|
|
PRECACHE_SOUND("common/bodysplat.wav");
|
|
|
|
// player pain sounds
|
|
PRECACHE_SOUND("player/pl_pain2.wav");
|
|
PRECACHE_SOUND("player/pl_pain4.wav");
|
|
PRECACHE_SOUND("player/pl_pain5.wav");
|
|
PRECACHE_SOUND("player/pl_pain6.wav");
|
|
PRECACHE_SOUND("player/pl_pain7.wav");
|
|
|
|
PRECACHE_MODEL("models/player.mdl");
|
|
|
|
// hud sounds
|
|
|
|
PRECACHE_SOUND("common/wpn_hudoff.wav");
|
|
PRECACHE_SOUND("common/wpn_hudon.wav");
|
|
PRECACHE_SOUND("common/wpn_moveselect.wav");
|
|
PRECACHE_SOUND("common/wpn_select.wav");
|
|
PRECACHE_SOUND("common/wpn_denyselect.wav");
|
|
|
|
|
|
// geiger sounds
|
|
|
|
PRECACHE_SOUND("player/geiger6.wav");
|
|
PRECACHE_SOUND("player/geiger5.wav");
|
|
PRECACHE_SOUND("player/geiger4.wav");
|
|
PRECACHE_SOUND("player/geiger3.wav");
|
|
PRECACHE_SOUND("player/geiger2.wav");
|
|
PRECACHE_SOUND("player/geiger1.wav");
|
|
|
|
if (giPrecacheGrunt)
|
|
UTIL_PrecacheOther("monster_human_grunt");
|
|
}
|
|
|
|
/*
|
|
===============
|
|
const char *GetGameDescription()
|
|
|
|
Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2
|
|
===============
|
|
*/
|
|
const char *GetGameDescription()
|
|
{
|
|
if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized
|
|
return g_pGameRules->GetGameDescription();
|
|
else
|
|
return "Half-Life";
|
|
}
|
|
|
|
/*
|
|
================
|
|
PlayerCustomization
|
|
|
|
A new player customization has been registered on the server
|
|
UNDONE: This only sets the # of frames of the spray can logo
|
|
animation right now.
|
|
================
|
|
*/
|
|
void PlayerCustomization( edict_t *pEntity, customization_t *pCust )
|
|
{
|
|
entvars_t *pev = &pEntity->v;
|
|
CBasePlayer *pPlayer = (CBasePlayer *)GET_PRIVATE(pEntity);
|
|
|
|
if (!pPlayer)
|
|
{
|
|
ALERT(at_console, "PlayerCustomization: Couldn't get player!\n");
|
|
return;
|
|
}
|
|
|
|
if (!pCust)
|
|
{
|
|
ALERT(at_console, "PlayerCustomization: NULL customization!\n");
|
|
return;
|
|
}
|
|
|
|
switch (pCust->resource.type)
|
|
{
|
|
case t_decal:
|
|
pPlayer->SetCustomDecalFrames(pCust->nUserData2); // Second int is max # of frames.
|
|
break;
|
|
case t_sound:
|
|
case t_skin:
|
|
case t_model:
|
|
// Ignore for now.
|
|
break;
|
|
default:
|
|
ALERT(at_console, "PlayerCustomization: Unknown customization type!\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
SpectatorConnect
|
|
|
|
A spectator has joined the game
|
|
================
|
|
*/
|
|
void SpectatorConnect( edict_t *pEntity )
|
|
{
|
|
entvars_t *pev = &pEntity->v;
|
|
CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity);
|
|
|
|
if (pPlayer)
|
|
pPlayer->SpectatorConnect( );
|
|
}
|
|
|
|
/*
|
|
================
|
|
SpectatorConnect
|
|
|
|
A spectator has left the game
|
|
================
|
|
*/
|
|
void SpectatorDisconnect( edict_t *pEntity )
|
|
{
|
|
entvars_t *pev = &pEntity->v;
|
|
CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity);
|
|
|
|
if (pPlayer)
|
|
pPlayer->SpectatorDisconnect( );
|
|
}
|
|
|
|
/*
|
|
================
|
|
SpectatorConnect
|
|
|
|
A spectator has sent a usercmd
|
|
================
|
|
*/
|
|
void SpectatorThink( edict_t *pEntity )
|
|
{
|
|
entvars_t *pev = &pEntity->v;
|
|
CBaseSpectator *pPlayer = (CBaseSpectator *)GET_PRIVATE(pEntity);
|
|
|
|
if (pPlayer)
|
|
pPlayer->SpectatorThink( );
|
|
}
|