// Copyright (C) 1999-2000 Id Software, Inc. // #include "g_local.h" #include "g_groups.h" reconData_t g_reconData[MAX_RECON_NAMES]; //!< recon data for a limited ammount of clients int g_reconNum; extern char* BG_RegisterRace( const char *name ); extern void SetPlayerClassCvar(gentity_t *ent); extern void SetClass( gentity_t *ent, char *s, char *teamName, qboolean SaveToCvar ); extern void BroadcastClassChange( gclient_t *client, pclass_t oldPClass ); //RPG-X: TiM extern char* correlateRanks( const char* strArg, int intArg ); extern pclass_t ValueNameForClass ( /*gentity_t *ent,*/ char* s ); extern qboolean levelExiting; // g_client.c -- client functions that don't happen every frame void G_StoreClientInitialStatus( gentity_t *ent ); //! players mins static vec3_t playerMins = {-12, -12, -24}; //RPG-X : TiM - {-15, -15, -24} //! players maxs static vec3_t playerMaxs = {12, 12, 32}; // {15, 15, 32} int actionHeroClientNum = -1; int borgQueenClientNum = -1; clInitStatus_t clientInitialStatus[MAX_CLIENTS]; team_t borgTeam = TEAM_FREE; //XPE char *languageIndex[MAX_LANGUAGES]; //END XPE //TiM: For easier transport setup /** * Function that makes transport setup easier * \author Ubergames - TiM */ void G_InitTransport( int clientNum, vec3_t origin, vec3_t angles ) { gentity_t *tent; TransDat[clientNum].beamTime = level.time + 8000; g_entities[clientNum].client->ps.powerups[PW_BEAM_OUT] = level.time + 8000; //Transfer stored data to active beamer VectorCopy( origin, TransDat[clientNum].currentCoord.origin ); VectorCopy( angles, TransDat[clientNum].currentCoord.angles ); tent = G_TempEntity( g_entities[clientNum].client->ps.origin, EV_PLAYER_TRANSPORT_OUT ); tent->s.clientNum = clientNum; } /** * Get a random player that becomes action hero */ void G_RandomActionHero( int ignoreClientNum ) { //int /*i,*/ numConnectedClients = 0; //int ahCandidates[MAX_CLIENTS]; if ( g_doWarmup.integer ) { if ( level.warmupTime != 0 ) { if ( level.warmupTime < 0 || level.time - level.startTime <= level.warmupTime ) {//don't choose one until warmup is done return; } } } else if ( level.time - level.startTime <= 3000 ) {//don't choose one until 3 seconds into the game return; } //if ( g_pModActionHero.integer != 0 ) //{ // for ( i = 0; i < level.maxclients; i++ ) // { // if ( i == ignoreClientNum ) // { // continue; // } // if ( level.clients[i].pers.connected != CON_DISCONNECTED ) // { // //note: these next few checks will mean that the first player to join (usually server client if a listen server) when a new map starts is *always* the AH // if ( &g_entities[i] != NULL && g_entities[i].client != NULL ) // { // if ( level.clients[i].sess.sessionClass != PC_ACTIONHERO ) // { // if ( level.clients[i].sess.sessionTeam != TEAM_SPECTATOR ) // { // ahCandidates[numConnectedClients++] = i; // } // } // } // } // } // if ( !numConnectedClients ) // {//WTF?! // return; // } // else // { // actionHeroClientNum = ahCandidates[ irandom( 0, (numConnectedClients-1) ) ]; // } //} } /** * Check wheter to replace the current action hero */ void G_CheckReplaceActionHero( int clientNum ) { if ( clientNum == actionHeroClientNum ) { G_RandomActionHero( clientNum ); if ( actionHeroClientNum >= 0 && actionHeroClientNum < level.maxclients ) { // get and distribute relevent paramters ClientUserinfoChanged( actionHeroClientNum ); ClientSpawn( &g_entities[actionHeroClientNum], 0, qfalse );//RPG-X: RedTechie - Modifyed }//else ERROR!!! } } void INeedAHero( void ) { G_RandomActionHero( actionHeroClientNum ); if ( actionHeroClientNum >= 0 && actionHeroClientNum < level.maxclients ) {// get and distribute relevent paramters ClientUserinfoChanged( actionHeroClientNum ); ClientSpawn( &g_entities[actionHeroClientNum], 0, qfalse );//RPG-X: RedTechie - Modifyed }//else ERROR!!! } /** * Pick a random borgqueen */ void G_RandomBorgQueen( int ignoreClientNum ) { int i, borgCount = 0; int borgClients[MAX_CLIENTS]; //FIXME: make it not always pick the first borg client to connect as the Queen!!! //is there a way to wait until all initial clients connect? if ( borgQueenClientNum != -1 ) { if ( borgQueenClientNum != ignoreClientNum ) {//already have a valid one return; } } //RPG-X: RedTechie - No warmup! /*if ( g_doWarmup.integer ) { if ( level.warmupTime != 0 ) { if ( level.warmupTime < 0 || level.time - level.startTime <= level.warmupTime ) {//don't choose one until warmup is done return; } } }*/ else if ( level.time - level.startTime <= 3000 ) {//don't choose one until 3 seconds into the game return; } if ( g_pModAssimilation.integer != 0 && ( borgTeam == TEAM_BLUE || borgTeam == TEAM_RED ) ) { for ( i = 0; i < level.maxclients; i++ ) { if ( i == ignoreClientNum ) { continue; } if ( level.clients[i].sess.sessionTeam == borgTeam )//&& level.clients[i].ps.stats[STAT_HEALTH] > 0 { borgClients[borgCount++] = i; } } /* if ( borgCount < 1 ) { if ( ignoreClientNum > 0 && ignoreClientNum < level.maxclients ) { if ( level.clients[ignoreClientNum].sess.sessionTeam == borgTeam )// && level.clients[ignoreClientNum].ps.stats[STAT_HEALTH] > 0 { borgClients[borgCount++] = ignoreClientNum; } } } */ if ( borgCount > 0 ) { /* int oldQueenClientNum = -1; if ( borgCount > 1 ) {//more than 1 borg, don't let it pick the same queen twice in a row oldQueenClientNum = borgQueenClientNum; } while ( borgQueenClientNum == oldQueenClientNum ) */ { borgQueenClientNum = borgClients[irandom(0, borgCount-1)]; } } else { borgQueenClientNum = -1; } } } /** * Check whether borgqueen should be replaced */ void G_CheckReplaceQueen( int clientNum ) { if ( clientNum == borgQueenClientNum ) { G_RandomBorgQueen( clientNum ); if ( borgQueenClientNum >= 0 && borgQueenClientNum < level.maxclients ) { // get and distribute relevent paramters ClientUserinfoChanged( borgQueenClientNum ); ClientSpawn( &g_entities[borgQueenClientNum], 0, qfalse );//RPG-X: RedTechie - Modifyed }//else ERROR!!! } } /** * Pick a player as borgqueen */ void G_PickBorgQueen( void ) { G_RandomBorgQueen( borgQueenClientNum ); if ( borgQueenClientNum >= 0 && borgQueenClientNum < level.maxclients ) {// get and distribute relevent paramters ClientUserinfoChanged( borgQueenClientNum ); ClientSpawn( &g_entities[borgQueenClientNum], 0, qfalse );//RPG-X: RedTechie - Modifyed }//else ERROR!!! } /*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32) initial potential spawning position for deathmatch games. The first time a player enters the game, they will be at an 'initial' spot. Targets will be fired when someone spawns in on them. "nobots" will prevent bots from using this spot. "nohumans" will prevent non-bots from using this spot. */ /** * Spawn function for deathmatch spawnpoint */ void SP_info_player_deathmatch( gentity_t *ent ) { int i; G_SpawnInt( "nobots", "0", &i); if ( i ) { ent->flags |= FL_NO_BOTS; } G_SpawnInt( "nohumans", "0", &i ); if ( i ) { ent->flags |= FL_NO_HUMANS; } trap_LinkEntity(ent); } /*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32) equivelant to info_player_deathmatch */ /** * Spawn function for player start spawnpoint which actually the same as deatchmatch spawnpoint */ void SP_info_player_start(gentity_t *ent) { ent->classname = "info_player_deathmatch"; SP_info_player_deathmatch( ent ); } /*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32) The intermission will be viewed from this point. Target an info_notnull for the view direction. */ /** * Spawn function for intermission entity. */ void SP_info_player_intermission( gentity_t *ent ) { } /* ======================================================================= SelectSpawnPoint ======================================================================= */ /* ================ SpotWouldTelefrag ================ */ /** * Check if beaming to a point will result in a teleporter frag. */ qboolean SpotWouldTelefrag( gentity_t *spot ) { int i, num; int touch[MAX_GENTITIES]; gentity_t *hit; vec3_t mins, maxs; VectorAdd( spot->s.origin, playerMins, mins ); VectorAdd( spot->s.origin, playerMaxs, maxs ); num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES ); for (i=0 ; iclient && hit->client->ps.stats[STAT_HEALTH] > 0 ) { return qtrue; } if (hit && hit->s.eType == ET_USEABLE && hit->s.modelindex == HI_SHIELD) { //hit a portable force field return qtrue; } } return qfalse; } /* ================ SelectNearestDeathmatchSpawnPoint Find the spot that we DON'T want to use ================ */ #define MAX_SPAWN_POINTS 256 /** * Find the spot that we DON'T want to use */ gentity_t *SelectNearestDeathmatchSpawnPoint( vec3_t from ) { gentity_t *spot; vec3_t delta; float dist, nearestDist; gentity_t *nearestSpot; nearestDist = 999999; nearestSpot = NULL; spot = NULL; while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { VectorSubtract( spot->s.origin, from, delta ); dist = VectorLength( delta ); if ( dist < nearestDist ) { nearestDist = dist; nearestSpot = spot; } } return nearestSpot; } /* ================ SelectRandomDeathmatchSpawnPoint go to a random point that doesn't telefrag ================ */ #define MAX_SPAWN_POINTS 256 /** * go to a random point that doesn't telefrag */ gentity_t *SelectRandomDeathmatchSpawnPoint( void ) { gentity_t *spot; int count; int selection; gentity_t *spots[MAX_SPAWN_POINTS]; count = 0; spot = NULL; while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { if ( SpotWouldTelefrag( spot ) ) { continue; } spots[ count ] = spot; count++; } if ( !count ) { // no spots that won't telefrag return G_Find( NULL, FOFS(classname), "info_player_deathmatch"); } selection = rand() % count; return spots[ selection ]; } /* =========== SelectSpawnPoint Chooses a player start, deathmatch start, etc ============ */ /** * Chooses a player start, deathmatch start, etc */ gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) { gentity_t *spot; gentity_t *nearestSpot; nearestSpot = SelectNearestDeathmatchSpawnPoint( avoidPoint ); spot = SelectRandomDeathmatchSpawnPoint ( ); if ( spot == nearestSpot ) { // roll again if it would be real close to point of death spot = SelectRandomDeathmatchSpawnPoint ( ); if ( spot == nearestSpot ) { // last try spot = SelectRandomDeathmatchSpawnPoint ( ); } } // find a single player start spot if (!spot) { G_Error( "Couldn't find a spawn point" ); return spot; } VectorCopy (spot->s.origin, origin); origin[2] += 9; VectorCopy (spot->s.angles, angles); return spot; } /* =========== SelectInitialSpawnPoint Try to find a spawn point marked 'initial', otherwise use normal spawn selection. ============ */ /** * Try to find a spawn point marked 'initial', otherwise * use normal spawn selection. */ gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles ) { gentity_t *spot; spot = NULL; while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { if ( spot->spawnflags & 1 ) { break; } } if ( !spot || SpotWouldTelefrag( spot ) ) { return SelectSpawnPoint( vec3_origin, origin, angles ); } VectorCopy (spot->s.origin, origin); origin[2] += 9; VectorCopy (spot->s.angles, angles); return spot; } /* =========== SelectSpectatorSpawnPoint ============ */ gentity_t *SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles ) { FindIntermissionPoint(); VectorCopy( level.intermission_origin, origin ); VectorCopy( level.intermission_angle, angles ); return NULL; } /* ======================================================================= BODYQUE ======================================================================= */ static int bodyFadeSound=0; /* =============== InitBodyQue =============== */ void InitBodyQue (void) { int i; gentity_t *ent; level.bodyQueIndex = 0; for (i=0; iclassname = "bodyque"; ent->neverFree = qtrue; level.bodyQue[i] = ent; } if (bodyFadeSound == 0) { // Initialize this sound. bodyFadeSound = G_SoundIndex("sound/enemies/borg/walkthroughfield.wav"); } } /* ============= BodyRezOut After sitting around for five seconds, fade out. ============= */ /** * After sitting around for five seconds, fade out. */ void BodyRezOut( gentity_t *ent ) { if ( level.time - ent->timestamp >= 7500 ) { // the body ques are never actually freed, they are just unlinked trap_UnlinkEntity( ent ); ent->physicsObject = qfalse; return; } ent->nextthink = level.time + 2500; ent->s.time = level.time + 2500; G_AddEvent(ent, EV_GENERAL_SOUND, bodyFadeSound); } /* ============= CopyToBodyQue A player is respawning, so make an entity that looks just like the existing corpse to leave behind. ============= */ /** * A player is respawning, so make an entity that looks * just like the existing corpse to leave behind. */ void CopyToBodyQue( gentity_t *ent ) { gentity_t *body; int contents; entityState_t *eState; trap_UnlinkEntity (ent); // if client is in a nodrop area, don't leave the body contents = trap_PointContents( ent->s.origin, -1 ); if ( contents & CONTENTS_NODROP ) { ent->s.eFlags &= ~EF_NODRAW; // Just in case we died from a bottomless pit, reset EF_NODRAW return; } // grab a body que and cycle to the next one body = level.bodyQue[ level.bodyQueIndex ]; level.bodyQueIndex = (level.bodyQueIndex + 1) % BODY_QUEUE_SIZE; trap_UnlinkEntity (body); eState = &ent->s; eState->eFlags = EF_DEAD; // clear EF_TALK, etc eState->powerups = 0; // clear powerups eState->loopSound = 0; // clear lava burning eState->number = body - g_entities; body->timestamp = level.time; body->physicsObject = qtrue; body->physicsBounce = 0; // don't bounce if ( eState->groundEntityNum == ENTITYNUM_NONE ) { eState->pos.trType = TR_GRAVITY; eState->pos.trTime = level.time; VectorCopy( ent->client->ps.velocity, eState->pos.trDelta ); } else { eState->pos.trType = TR_STATIONARY; } eState->event = 0; // change the animation to the last-frame only, so the sequence // doesn't repeat anew for the body switch ( eState->legsAnim & ~ANIM_TOGGLEBIT ) { case BOTH_DEATH1: case BOTH_DEAD1: eState->torsoAnim = eState->legsAnim = BOTH_DEAD1; break; case BOTH_DEATH2: case BOTH_DEAD2: eState->torsoAnim = eState->legsAnim = BOTH_DEAD2; break; /*case BOTH_DEATH3: case BOTH_DEAD3:*/ default: eState->torsoAnim = eState->legsAnim = BOTH_DEAD1; //DEAD3 break; } body->r.svFlags = ent->r.svFlags; VectorCopy (ent->r.mins, body->r.mins); VectorCopy (ent->r.maxs, body->r.maxs); VectorCopy (ent->r.absmin, body->r.absmin); VectorCopy (ent->r.absmax, body->r.absmax); body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP; body->r.contents = CONTENTS_CORPSE; body->r.ownerNum = ent->r.ownerNum; body->nextthink = level.time + 5000; body->think = BodyRezOut; body->die = body_die; // if there shouldn't be a body, don't show one. if (ent->client && ((level.time - ent->client->ps.powerups[PW_DISINTEGRATE]) < 10000 || (level.time - ent->client->ps.powerups[PW_EXPLODE]) < 10000)) { eState->eFlags |= EF_NODRAW; } // don't take more damage if already gibbed //RPG-X: RedTechie - Check for medicrevive if(rpg_medicsrevive.integer == 0){ if ( ent->health <= GIB_HEALTH ) { body->takedamage = qfalse; } else { body->takedamage = qtrue; } }else{ body->takedamage = qfalse; } VectorCopy ( eState->pos.trBase, body->r.currentOrigin ); trap_LinkEntity (body); } //====================================================================== /* ================== SetClientViewAngle ================== */ void SetClientViewAngle( gentity_t *ent, vec3_t angle ) { int i; // set the delta angle for (i=0 ; i<3 ; i++) { int cmdAngle; cmdAngle = ANGLE2SHORT(angle[i]); ent->client->ps.delta_angles[i] = cmdAngle - ent->client->pers.cmd.angles[i]; } VectorCopy( angle, ent->s.angles ); VectorCopy (ent->s.angles, ent->client->ps.viewangles); } void SetScore( gentity_t *ent, int score ); void EliminationRespawn( gentity_t *ent, char *team ) { ent->flags &= ~FL_NOTARGET; ent->s.eFlags &= ~EF_NODRAW; ent->client->ps.eFlags &= ~EF_NODRAW; //ent->s.eFlags &= ~EF_ELIMINATED; //ent->client->ps.eFlags &= ~EF_ELIMINATED; ent->r.svFlags &= ~SVF_ELIMINATED; ClientSpawn(ent, 0, qfalse);//RPG-X: RedTechie - Modifyed /* int oldScore; oldScore = ent->client->ps.persistant[PERS_SCORE]; SetTeam( ent, ent->team ); SetScore( ent, oldScore ); */ } void EliminationSpectate( gentity_t *ent ) { playerState_t *ps = &ent->client->ps; CopyToBodyQue (ent); ClientSpawn(ent, 0, qfalse);//RPG-X: RedTechie - Modifyed ent->takedamage = qfalse; ent->r.contents = 0; ent->flags |= FL_NOTARGET; ent->s.eFlags |= EF_NODRAW; ps->eFlags |= EF_NODRAW; ps->pm_type = PM_NORMAL;//PM_SPECTATOR; //ent->s.eFlags |= EF_ELIMINATED;//FIXME: this is not being reliably SENT!!!!!! //ps->eFlags |= EF_ELIMINATED; ent->r.svFlags |= SVF_ELIMINATED;//just in case VectorSet( ent->r.mins, -4, -4, -16 ); VectorSet( ent->r.maxs, 4, 4, -8 ); ps->weapon = 0; ps->stats[STAT_WEAPONS] = 0; /* int oldScore; oldScore = ent->client->ps.persistant[PERS_SCORE]; ent->team = (char *)TeamName( ent->client->sess.sessionTeam ); SetTeam( ent, "spectator"); SetScore( ent, oldScore ); //FIXME: specator mode when dead kind of freaky if trying to follow */ } /* ================ respawn ================ */ extern char *ClassNameForValue( pclass_t pClass ); void respawn( gentity_t *ent ) { qboolean borg = qfalse; gentity_t *tent; playerState_t *ps; if ( ent->s.number == borgQueenClientNum ) {//can't respawn if queen return; } /*if ( g_pModElimination.integer != 0 ) {//no players respawn when in elimination if ( !(level.intermissiontime && level.intermissiontime != -1) ) {//don't do this once intermission has begun EliminationSpectate( ent ); } return; }*/ /*if ( g_pModAssimilation.integer != 0 && ent->client ) {//Go to Borg team if killed by assimilation if ( ent->client->sess.sessionClass != PC_BORG ) { if ( ent->client->mod == MOD_ASSIMILATE ) { //first, save their current state clientInitialStatus[ent->s.number].initialized = qfalse; G_StoreClientInitialStatus( ent ); if ( ent->client->sess.sessionTeam == TEAM_RED ) { SetClass( ent, "borg", "blue" ); } else if ( ent->client->sess.sessionTeam == TEAM_BLUE ) { SetClass( ent, "borg", "red" ); } ent->s.eFlags |= EF_ASSIMILATED; ent->client->ps.eFlags |= EF_ASSIMILATED; return; } } else { // flag this so we can play a different spawn in effect for a borg borg = qtrue; } } else {*///assimilated players don't leave corpses CopyToBodyQue (ent); //} ClientSpawn(ent, 0, qfalse);//RPG-X: RedTechie - Modifyed ps = &ent->client->ps; // add a teleportation effect if ( borg ) tent = G_TempEntity( ps->origin, EV_BORG_TELEPORT ); else { //tent = G_TempEntity( ps->origin, EV_PLAYER_TELEPORT_IN ); tent = G_TempEntity( ps->origin, EV_PLAYER_TRANSPORT_IN ); ps->powerups[PW_QUAD] = level.time + 4000; } tent->s.clientNum = ent->s.clientNum; } /* ================ TeamCount Returns number of players on a team ================ */ /** * Returns number of players on a team */ team_t TeamCount( int ignoreClientNum, int team ) { int i; int count = 0; for ( i = 0 ; i < level.maxclients ; i++ ) { if ( i == ignoreClientNum ) { continue; } if ( level.clients[i].pers.connected == CON_DISCONNECTED ) { continue; } if ( level.clients[i].sess.sessionTeam == team ) { count++; } } return count; } /* ================ PickTeam ================ */ team_t PickTeam( int ignoreClientNum ) { int counts[TEAM_NUM_TEAMS]; counts[TEAM_BLUE] = TeamCount( ignoreClientNum, TEAM_BLUE ); counts[TEAM_RED] = TeamCount( ignoreClientNum, TEAM_RED ); if ( counts[TEAM_BLUE] > counts[TEAM_RED] ) { return TEAM_RED; } if ( counts[TEAM_RED] > counts[TEAM_BLUE] ) { return TEAM_BLUE; } // equal team count, so join the team with the lowest score if ( level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED] ) { return TEAM_RED; } if ( level.teamScores[TEAM_BLUE] < level.teamScores[TEAM_RED] ) { return TEAM_BLUE; } return irandom( TEAM_RED, TEAM_BLUE ); } /* =========== ForceClientSkin Forces a client's skin (for teamplay) HEAVILY modified for the RPG-X Player Model system :P =========== */ /** * Forces a client's skin (for teamplay) * HEAVILY modified for the RPG-X * Player Model system */ void ForceClientSkin(char *model, const char *skin ) { char *p; char *q; //we expect model to equal 'char/model/skin' //check for the slash between charName and modelName //if ((p = strchr(model, '/')) != NULL) { // *p = 0; //} //Com_Printf("ForceSkin Called\n"); p = strchr(model, '/'); //if no slashes at all if ( !p || !p[0] || !p[1] ) { //input everything Q_strcat(model, MAX_QPATH, "/"); Q_strcat(model, MAX_QPATH, "main"); Q_strcat(model, MAX_QPATH, "/"); Q_strcat(model, MAX_QPATH, skin); } else { //ie we got a slash (which should be the first of two p++; q = strchr(p, '/'); //okay, we should get another one if one was already found if (!q || !q[0] || !q[1] ) { //no slashes were found?? >.< //okay, let's assume they specified the .model file, no skin //so just add the skin to the end :P Q_strcat(model, MAX_QPATH, "/"); Q_strcat(model, MAX_QPATH, skin); } else { //len = strlen( p ); //Q_strcat(&model[len - strlen( q )], MAX_QPATH, skin); q++; *q= '\0'; Q_strcat(model, MAX_QPATH, skin); //Com_Printf("Debug: %s\n", model); } } } /* =========== ClientCheckName ============ */ /*static*/ void ClientCleanName( const char *in, char *out, int outSize ) { int len, colorlessLen; char ch; char *p; int spaces; //save room for trailing null byte outSize--; len = 0; colorlessLen = 0; p = out; *p = 0; spaces = 0; while( 1 ) { ch = *in++; if( !ch ) { break; } // don't allow leading spaces if( !*p && ch == ' ' ) { continue; } // check colors if( ch == Q_COLOR_ESCAPE ) { // solo trailing carat is not a color prefix if( !*in ) { break; } // don't allow black in a name, period if( ColorIndex(*in) == 0 ) { in++; continue; } // make sure room in dest for both chars if( len > outSize - 2 ) { break; } *out++ = ch; *out++ = *in++; len += 2; continue; } // don't allow too many consecutive spaces if( ch == ' ' ) { spaces++; if( spaces > 3 ) { continue; } } else { spaces = 0; } if( len > outSize - 1 ) { break; } *out++ = ch; colorlessLen++; len++; } *out = 0; // don't allow empty names if( *p == 0 || colorlessLen == 0 ) { Q_strncpyz( p, "RedShirt", outSize ); } } /* =========== legalSkin Compare a list of races with an incoming race name. Used to decide if in a CTF game where a race is specified for a given team if a skin is actually already legal. =========== */ /** * Compare a list of races with an incoming race name. * Used to decide if in a CTF game where a race is specified for a given team if a skin is actually already legal. */ qboolean legalSkin(const char *race_list, const char *race) { char current_race_name[125]; const char *s = race_list; const char *max_place = race_list + strlen(race_list); const char *marker; memset(current_race_name, 0, sizeof(current_race_name)); // look through the list till it's empty while (s < max_place) { marker = s; // figure out from where we are where the next ',' or 0 is while (*s != ',' && *s != 0) { s++; } // copy just that name Q_strncpyz(current_race_name, marker, (s-marker)+1); // avoid the comma or increment us past the end of the string so we fail the main while loop s++; // compare and see if this race is the same as the one we want if (!Q_stricmp(current_race_name, race)) { return qtrue; } } return qfalse; } /* =========== randomSkin given a race name, go find all the skins that use it, and randomly select one =========== */ /** * given a race name, go find all the skins that use it, and randomly select one */ #ifdef Q3_VM void randomSkin(const char* race, char* model, int current_team, int clientNum) { char skinsForRace[MAX_SKINS_FOR_RACE][128]; int howManySkins = 0; int i,x; int temp; int skin_count_check; char skinNamesAlreadyUsed[16][128]; int current_skin_count = 0; gentity_t *ent = NULL; char userinfo[MAX_INFO_STRING]; char temp_model[MAX_QPATH]; memset(skinsForRace, 0, sizeof(skinsForRace)); memset(skinNamesAlreadyUsed, 0, sizeof(skinNamesAlreadyUsed)); // first up, check to see if we want to select a skin from someone that's already playing on this guys team skin_count_check = g_random_skin_limit.integer; if (skin_count_check) { // sanity check the skins to compare against count if (skin_count_check > 16) { skin_count_check = 16; } // now construct an array of the names already used for (i=0; iinuse || i == clientNum) continue; // no, so look at the next one, and see if it's in the list we are constructing // same team? if (ent->client && ent->client->sess.sessionTeam == current_team) { // so what's this clients model then? trap_GetUserinfo( i, userinfo, sizeof( userinfo ) ); Q_strncpyz( temp_model, Info_ValueForKey (userinfo, "model"), sizeof( temp_model ) ); // check the name for (x = 0; x< current_skin_count; x++) { // are we the same? if (!Q_stricmp(skinNamesAlreadyUsed[x], temp_model)) { // yeah - ok we already got this one break; } } // ok, did we match anything? if (x == current_skin_count) { // no - better add this name in Q_strncpyz(skinNamesAlreadyUsed[current_skin_count], temp_model, sizeof(skinNamesAlreadyUsed[current_skin_count])); current_skin_count++; } } } // ok, array constructed. Did we get enough? if (current_skin_count >= skin_count_check) { // yeah, we did - so select a skin from one of these then temp = rand() % current_skin_count; Q_strncpyz( model, skinNamesAlreadyUsed[temp], MAX_QPATH ); ForceClientSkin(model, ""); return; } } // search through each and every skin we can find for (i=0; i 16) { skin_count_check = 16; } // now construct an array of the names already used for (i=0; iinuse || i == clientNum) continue; // no, so look at the next one, and see if it's in the list we are constructing // same team? if (ent->client && ent->client->sess.sessionTeam == current_team) { userinfo = (char *)malloc(MAX_INFO_STRING * sizeof(char)); if(!userinfo) { G_Error("Was unable to allocate %i bytes.\n", MAX_INFO_STRING * sizeof(char)); return; } // so what's this clients model then? trap_GetUserinfo( i, userinfo, MAX_INFO_STRING * sizeof(char) ); Q_strncpyz( temp_model, Info_ValueForKey (userinfo, "model"), sizeof( temp_model ) ); free(userinfo); // check the name for (x = 0; x< current_skin_count; x++) { // are we the same? if (!Q_stricmp(skinNamesAlreadyUsed[x], temp_model)) { // yeah - ok we already got this one break; } } // ok, did we match anything? if (x == current_skin_count) { // no - better add this name in Q_strncpyz(skinNamesAlreadyUsed[current_skin_count], temp_model, sizeof(skinNamesAlreadyUsed[current_skin_count])); current_skin_count++; } } } // ok, array constructed. Did we get enough? if (current_skin_count >= skin_count_check) { // yeah, we did - so select a skin from one of these then temp = rand() % current_skin_count; Q_strncpyz( model, skinNamesAlreadyUsed[temp], MAX_QPATH ); ForceClientSkin(model, ""); free(skinNamesAlreadyUsed); free(skinsForRace); return; } } // search through each and every skin we can find for (i=0; isess.sessionTeam, clientNum); return qtrue; } //void ClientMaxHealthForClass ( gclient_t *client, pclass_t pclass ) //{ // switch( pclass ) // { // case PC_INFILTRATOR: // client->pers.maxHealth = 50; // break; // case PC_HEAVY: // client->pers.maxHealth = 200; // break; // case PC_ACTIONHERO: // client->pers.maxHealth = 300; // break; // case PC_MEDIC: // client->pers.maxHealth = 100; // break; // case PC_SNIPER: // client->pers.maxHealth = 100; // break; // case PC_DEMO: // client->pers.maxHealth = 100; // break; // case PC_TECH: // client->pers.maxHealth = 100; // break; // case PC_BORG: // client->pers.maxHealth = 100; // break; // case PC_N00B: // client->pers.maxHealth = 2; // break; // default: // break; // } //} void SetCSTeam( team_t team, char *teamname ) { if ( teamname == NULL || teamname[0] == 0 ) { return; } switch ( team ) { case TEAM_BLUE: trap_SetConfigstring( CS_BLUE_GROUP, teamname ); break; case TEAM_RED: trap_SetConfigstring( CS_RED_GROUP, teamname ); break; default: // make gcc happy break; } } /* =========== ClientUserInfoChanged ============ */ /** * Called from ClientConnect when the player first connects and * directly by the server system when the player updates a userinfo variable. * * The game can override any of the settings and call trap_SetUserinfo * if desired. */ void ClientUserinfoChanged( int clientNum ) { gentity_t *ent; int i; char *s; //, *oldModel; char model[MAX_QPATH]; char oldname[MAX_STRING_CHARS]; gclient_t *client; char *c1; char userinfo[MAX_INFO_STRING]; qboolean reset; //char *sex; // int pickborg = 0; char *borgytype; float weight, height; char age[MAX_NAME_LENGTH]; char race[MAX_NAME_LENGTH]; int modelOffset; qboolean changeName = qtrue; //TiM : For the name filter char sHeight[10]; char sWeight[10]; //int silentCloak; //int y; //XPERIMENTAL clientPersistant_t *pers; clientSession_t *sess; borgytype = "borg"; model[0] = 0; ent = g_entities + clientNum; if(!ent) return; client = ent->client; pers = &client->pers; sess = &client->sess; //TiM - Exit if this user has had their info clamped if ( ent->flags & FL_CLAMPED ) return; trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); //Com_Printf( S_COLOR_RED "%s\n", userinfo ); //Com_Printf( S_COLOR_RED "CHANGED!\n" ); // check for malformed or illegal info strings if ( !Info_Validate(userinfo) ) { strcpy (userinfo, "\\name\\badinfo"); } // check for local client s = Info_ValueForKey( userinfo, "ip" ); if ( !strcmp( s, "localhost" ) ) { pers->localClient = qtrue; } // check the item prediction s = Info_ValueForKey( userinfo, "cg_predictItems" ); if ( !atoi( s ) ) { pers->predictItemPickup = qfalse; } else { pers->predictItemPickup = qtrue; } // set name //TiM: Filter for if a player is already on this server with that name. s = Info_ValueForKey (userinfo, "name"); if ( rpg_uniqueNames.integer && !( ent->r.svFlags & SVF_BOT ) ) { char newName[36]; char activeName[36]; ClientCleanName( s, newName, sizeof(newName) ); Q_CleanStr( newName ); //loop thru all the clients, and see if we have one that has the same name as our proposed one for ( i = 0; i < level.numConnectedClients; i++ ) { Q_strncpyz( activeName, g_entities[i].client->pers.netname, sizeof( activeName ) ); Q_CleanStr( activeName ); if ( g_entities[i].client->ps.clientNum != client->ps.clientNum && !Q_stricmp( newName, activeName ) ) { trap_SendServerCommand( ent-g_entities, " print \"Unable to change name. A player already has that name on this server.\n\" "); changeName = qfalse; break; } } } if ( changeName ) { Q_strncpyz ( oldname, pers->netname, sizeof( oldname ) ); ClientCleanName( s, pers->netname, sizeof(pers->netname) ); if ( sess->sessionTeam == TEAM_SPECTATOR ) { if ( sess->spectatorState == SPECTATOR_SCOREBOARD ) { Q_strncpyz( pers->netname, "scoreboard", sizeof(pers->netname) ); } } if ( pers->connected == CON_CONNECTED ) { if ( strcmp( oldname, pers->netname ) ) { if ( !levelExiting && !level.intermissiontime ) {//no need to do this during level changes trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname, pers->netname) ); } } } } pers->pms_height = atof( Info_ValueForKey( userinfo, "height" ) ); if ( !pers->pms_height ) pers->pms_height = 1.0f; //In assimilation, make sure everyone is the right class/team for their chosen class/team //FIXME: don't want to make these g_team_group_???'s stay forever //if ( g_pModAssimilation.integer != 0 ) //{//become a Borg Queen if needed // if ( sess->sessionClass == PC_BORG ) // {//trying to join as a Borg // if ( borgTeam != TEAM_BLUE && borgTeam != TEAM_RED ) // {//borg team not chosen yet, so choose it // borgTeam = sess->sessionTeam; // if ( borgTeam != TEAM_BLUE && borgTeam != TEAM_RED ) // { // if ( irandom(0, 1) ) // { // borgTeam = TEAM_RED; // } // else // { // borgTeam = TEAM_BLUE; // } // SetCSTeam( borgTeam, "Borg" ); // } // } // if ( sess->sessionTeam != borgTeam ) // {//can't join this team if you're a borg, force them to be non-borg // //if ( g_pModSpecialties.integer != 0 ) // //{ // // SetClass( ent, (char *)ClassNameForValue( irandom( PC_SNIPER, PC_TECH ) ), NULL ); // //} // //else // //{ // SetClass( ent, "noclass", NULL, qtrue ); // //} // return; // } // } // else if ( borgTeam != TEAM_BLUE && borgTeam != TEAM_RED ) // {//borg team not chosen yet, choose one now // if ( Q_strncmp( "Borg", g_team_group_red.string, 4 ) != 0 ) // {//the red team isn't borg // if ( Q_strncmp( "Borg", g_team_group_blue.string, 4 ) != 0 ) // {//the blue team isn't borg // if ( TeamCount( clientNum, TEAM_BLUE ) > 0 ) // {//blue has people on it, so red is borg // borgTeam = TEAM_RED; // } // else if ( TeamCount( clientNum, TEAM_RED ) > 0 ) // {//red has people on it, so blue is borg // borgTeam = TEAM_BLUE; // } // else // {//no-one on a team yet, so borgTeam is the other team // switch( sess->sessionTeam ) // { // case TEAM_BLUE: // borgTeam = TEAM_RED; // break; // case TEAM_RED: // borgTeam = TEAM_BLUE; // break; // default: // break; // } // } // SetCSTeam( borgTeam, "Borg" ); // } // else if ( borgTeam != TEAM_BLUE && borgTeam != TEAM_RED ) // { // borgTeam = TEAM_BLUE; // SetCSTeam( borgTeam, "Borg" ); // } // } // else if ( borgTeam != TEAM_BLUE && borgTeam != TEAM_RED ) // { // borgTeam = TEAM_RED; // SetCSTeam( borgTeam, "Borg" ); // } // } // /*else if ( sess->sessionTeam == borgTeam ) // {//borg team is chosen and you are not a borg and you are trying to join borg team // SetClass( ent, "borg", NULL ); // return; // }*/ // //G_RandomBorgQueen( -1 ); //} // set max health pers->maxHealth = atoi( Info_ValueForKey( userinfo, "handicap" ) ); if ( pers->maxHealth < 1 || pers->maxHealth > 100 ) { pers->maxHealth = 100; } //if you have a class, ignores handicap and 100 limit, sorry //ClientMaxHealthForClass( client, sess->sessionClass ); client->ps.stats[STAT_MAX_HEALTH] = pers->maxHealth; // set model //switch ( sess->sessionClass ) //{ ////FIXME: somehow map these into some text file that points to a specific model for each class? ////OR give them a choice in the menu somehow? //case PC_INFILTRATOR: //case PC_SNIPER: //case PC_HEAVY: //case PC_DEMO: //case PC_MEDIC://note: can also give health & armor & regen //case PC_TECH://note: can also give ammo & invis //case PC_BORG: //case PC_ACTIONHERO: //case PC_NOCLASS: //default: Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) ); //break; //} // team if ( qtrue/*sess->sessionClass != PC_BORG*/ ) {//borg class doesn't need to use team color switch( sess->sessionTeam ) { case TEAM_RED: // decide if we are going to have to reset a skin cos it's not applicable to a race selected if (g_gametype.integer < GT_TEAM || !Q_stricmp("", g_team_group_red.string)) { if ( g_pModAssimilation.integer != 0 && legalSkin(G_searchGroupList( model ), borgytype ) == qtrue ) {//if you're trying to be a Borg and not a borg playerclass, then pick a different model getNewSkin("HazardTeam", model, "red", client, clientNum); ForceClientSkin(model, "red"); // change the value in out local copy, then update it on the server Info_SetValueForKey(userinfo, "model", model); trap_SetUserinfo(clientNum, userinfo); } else { ForceClientSkin(model, "red"); } break; } // at this point, we are playing CTF and there IS a race specified for this game else { if ( g_pModAssimilation.integer != 0 && Q_stricmp( borgytype, g_team_group_red.string ) == 0 ) {//team model is set to borg, but that is now allowed, pick a different "race" reset = getNewSkin("HazardTeam", model, "red", client, clientNum); } else {// go away and get what ever races this skin is attached to. reset = getNewSkin(g_team_group_red.string, model, "red", client, clientNum); } // did we get a model name back? if (!model[0]) { // no - this almost certainly means we had a bogus race is the g_team_group_team cvar // so reset it to starfleet and try it again Com_Printf("WARNING! - Red Group %s is unknown - resetting Red Group to Allow Any Group\n", g_team_group_red.string); trap_Cvar_Set("g_team_group_red", ""); trap_Cvar_Register( &g_team_group_red, "g_team_group_red", "", CVAR_LATCH); // Since we are allow any group now, just get his normal model and carry on Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) ); ForceClientSkin(model, "red"); reset = qfalse; } if (reset) { if ( !levelExiting ) {//no need to do this during level changes trap_SendServerCommand( -1, va("print \"In-appropriate skin selected for %s on team %s\nSkin selection overridden from skin %s to skin %s\n\"", pers->netname, g_team_group_red.string, Info_ValueForKey (userinfo, "model"), model)); } ForceClientSkin(model, "red"); // change the value in out local copy, then update it on the server Info_SetValueForKey(userinfo, "model", model); trap_SetUserinfo(clientNum, userinfo); } break; } case TEAM_BLUE: // decide if we are going to have to reset a skin cos it's not applicable to a race selected if (g_gametype.integer < GT_TEAM || !Q_stricmp("", g_team_group_blue.string)) { if ( g_pModAssimilation.integer != 0 && legalSkin(G_searchGroupList( model ), borgytype ) == qtrue ) {//if you're trying to be a Borg and not a borg playerclass, then pick a different model getNewSkin("HazardTeam", model, "blue", client, clientNum); ForceClientSkin(model, "blue"); // change the value in out local copy, then update it on the server Info_SetValueForKey(userinfo, "model", model); trap_SetUserinfo(clientNum, userinfo); } else { ForceClientSkin(model, "blue"); } break; } // at this point, we are playing CTF and there IS a race specified for this game else { if ( g_pModAssimilation.integer != 0 && Q_stricmp( borgytype, g_team_group_blue.string ) == 0 ) {//team model is set to borg, but that is now allowed, pick a different "race" reset = getNewSkin("HazardTeam", model, "blue", client, clientNum); } else { // go away and get what ever races this skin is attached to. reset = getNewSkin(g_team_group_blue.string, model, "blue", client, clientNum); } // did we get a model name back? if (!model[0]) { // no - this almost certainly means we had a bogus race is the g_team_group_team cvar // so reset it to klingon and try it again Com_Printf("WARNING! - Blue Group %s is unknown - resetting Blue Group to Allow Any Group\n", g_team_group_blue.string); trap_Cvar_Set("g_team_group_blue", ""); trap_Cvar_Register( &g_team_group_blue, "g_team_group_blue", "", CVAR_LATCH ); // Since we are allow any group now, just get his normal model and carry on Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) ); ForceClientSkin(model, "blue"); reset = qfalse; } if (reset) { if ( !levelExiting ) {//no need to do this during level changes trap_SendServerCommand( -1, va("print \"In-appropriate skin selected for %s on team %s\nSkin selection overridden from skin %s to skin %s\n\"", pers->netname, g_team_group_blue.string, Info_ValueForKey (userinfo, "model"), model)); } ForceClientSkin(model, "blue"); // change the value in out local copy, then update it on the server Info_SetValueForKey(userinfo, "model", model); trap_SetUserinfo(clientNum, userinfo); } break; } default: break; } if ( g_gametype.integer >= GT_TEAM && sess->sessionTeam == TEAM_SPECTATOR ) { // don't ever use a default skin in teamplay, it would just waste memory ForceClientSkin(model, "red"); } } else { ForceClientSkin(model, "default"); Info_SetValueForKey(userinfo, "model", model); trap_SetUserinfo(clientNum, userinfo); } if ( rpg_rpg.integer != 0 && rpg_forceclasscolor.integer != 0 && g_gametype.integer < GT_TEAM) { ForceClientSkin( model, g_classData[sess->sessionClass].modelSkin ); // if ( sess->sessionClass == PC_COMMAND ) // { // ForceClientSkin(model, "red"); //// Info_SetValueForKey(userinfo, "model", model); //// trap_SetUserinfo(clientNum, userinfo); // } // else if ( sess->sessionClass == PC_SECURITY ) // { // ForceClientSkin(model, "default"); //// Info_SetValueForKey(userinfo, "model", model); //// trap_SetUserinfo(clientNum, userinfo); // } // else if ( sess->sessionClass == PC_ADMIN ) // { // ForceClientSkin(model, "default"); //// Info_SetValueForKey(userinfo, "model", model); //// trap_SetUserinfo(clientNum, userinfo); // } // else if ( sess->sessionClass == PC_SCIENCE ) // { // ForceClientSkin(model, "blue"); //// Info_SetValueForKey(userinfo, "model", model); //// trap_SetUserinfo(clientNum, userinfo); // } // else if ( sess->sessionClass == PC_MEDICAL ) // { // ForceClientSkin(model, "blue"); //// Info_SetValueForKey(userinfo, "model", model); //// trap_SetUserinfo(clientNum, userinfo); // } // else if ( sess->sessionClass == PC_ENGINEER ) // { // ForceClientSkin(model, "default"); //// Info_SetValueForKey(userinfo, "model", model); //// trap_SetUserinfo(clientNum, userinfo); // } // else if ( sess->sessionClass == PC_ALIEN ) // { // ForceClientSkin(model, "default"); //// Info_SetValueForKey(userinfo, "model", model); //// trap_SetUserinfo(clientNum, userinfo); // } // else if ( sess->sessionClass == PC_N00B ) // { // ForceClientSkin(model, "default"); //// Info_SetValueForKey(userinfo, "model", model); //// trap_SetUserinfo(clientNum, userinfo); // } // else if ( sess->sessionClass == PC_ALPHAOMEGA22 ) // { // ForceClientSkin(model, "default"); //// Info_SetValueForKey(userinfo, "model", model); //// trap_SetUserinfo(clientNum, userinfo); // } } //TiM : For when an admin chooses not to see admin messages //Marcin : and check for privacy mode - 24/12/2008 s = Info_ValueForKey( userinfo, "noAdminChat" ); if ( atoi( s ) > 0 ) { client->noAdminChat = qtrue; } else { client->noAdminChat = qfalse; } // colors c1 = Info_ValueForKey( userinfo, "color" ); // teamInfo s = Info_ValueForKey( userinfo, "teamoverlay" ); if ( ! *s || atoi( s ) != 0 ) { pers->teamInfo = qtrue; } else { pers->teamInfo = qfalse; } //PMS system - lock down the values s = Info_ValueForKey( userinfo, "height" ); height = atof( s ); if (height > (float)rpg_maxHeight.value ) { //height = (float)MAX_HEIGHT; Q_strncpyz( sHeight, rpg_maxHeight.string, sizeof( sHeight ) ); } else if (height < (float)rpg_minHeight.value ) { Q_strncpyz( sHeight, rpg_minHeight.string, sizeof( sHeight ) ); //height = (float)MIN_HEIGHT; } else { Q_strncpyz( sHeight, s, sizeof( sHeight ) ); } //TiM - needed for height offset pers->pms_height = atof( sHeight ); //PMS system - lock down the values s = Info_ValueForKey( userinfo, "weight" ); weight = atof( s ); if (weight > (float)rpg_maxWeight.value ) { //weight = (float)MAX_WEIGHT; Q_strncpyz( sWeight, rpg_maxWeight.string, sizeof( sWeight ) ); } else if (weight < (float)rpg_minWeight.value ) { //weight = (float)MIN_WEIGHT; Q_strncpyz( sWeight, rpg_minWeight.string, sizeof( sWeight ) ); } else { Q_strncpyz( sWeight, s, sizeof( sWeight ) ); } s = Info_ValueForKey( userinfo, "age" ); Q_strncpyz( age, s, sizeof(age) ); s = Info_ValueForKey( userinfo, "race" ); Q_strncpyz( race, s, sizeof( race ) ); // XPERIMENTAL //client->playerRace = G_AddPlayerRace(s, clientNum); /*if(rpg_useLanguages.integer) { client->languages->language = G_AddPlayerLanguage(s, clientNum); client->languages->hasUniversal = qtrue; }*/ s = Info_ValueForKey( userinfo, "modelOffset" ); modelOffset = atoi( s ); // send over a subset of the userinfo keys so other clients can // print scoreboards, display models, and play custom sounds //FIXME: In future, we'll lock down these PMS values so we can't have overloaded transmission data if ( ent->r.svFlags & SVF_BOT ) { s = va("n\\%s\\t\\%i\\p\\%i\\model\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\age\\25\\height\\%s\\weight\\%s\\race\\Bot\\of\\%i\\admin\\0", pers->netname, sess->sessionTeam, sess->sessionClass, model, pers->maxHealth, sess->wins, sess->losses, Info_ValueForKey( userinfo, "skill" ), sHeight, sWeight, modelOffset ); } else { s = va("n\\%s\\t\\%i\\p\\%i\\model\\%s\\hc\\%i\\w\\%i\\l\\%i\\age\\%s\\height\\%s\\weight\\%s\\race\\%s\\of\\%i\\admin\\%i", pers->netname, sess->sessionTeam, sess->sessionClass, model, pers->maxHealth, sess->wins, sess->losses, age, sHeight, sWeight, race, modelOffset, ((int)IsAdmin(g_entities+clientNum))); } //Com_Printf( "%s\n", s ); //Com_Printf("modeloffset = %f\n", modelOffset ); //Backup in case this screws us up :P /* if ( ent->r.svFlags & SVF_BOT ) { s = va("n\\%s\\t\\%i\\p\\%i\\model\\%s\\c1\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s", pers->netname, sess->sessionTeam, sess->sessionClass, model, c1, pers->maxHealth, sess->wins, sess->losses, Info_ValueForKey( userinfo, "skill" ) ); } else { s = va("n\\%s\\t\\%i\\p\\%i\\model\\%s\\c1\\%s\\hc\\%i\\w\\%i\\l\\%i", pers->netname, sess->sessionTeam, sess->sessionClass, model, c1, pers->maxHealth, sess->wins, sess->losses ); }*/ trap_SetConfigstring( CS_PLAYERS+clientNum, s ); G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s /*, g_entities[clientNum].client->pers.ip*/ ); // no ip logging here as string might get to long } /* =========== ClientConnect ============ */ /** * Called when a player begins connecting to the server. * Called again for every map change or tournement restart. * * The session information will be valid after exit. * * Return NULL if the client should be allowed, otherwise return * a string with the reason for denial. * * Otherwise, the client will be sent the current gamestate * and will eventually get to ClientBegin. * * firstTime will be qtrue the very first time a client connects * to the server machine, but qfalse on map changes and tournement * restarts. */ char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { char *value; gclient_t *client; char userinfo[MAX_INFO_STRING]; gentity_t *ent; vmCvar_t mapname; vmCvar_t sv_hostname; char* newRank; int tmpScore = 0; //Without these, tonnes of proverbial shyte hits the fan if a bot connects O_o char* newClass; int i; char ip[64]; //TiM : Saved the IP data for player recon feature //char* newClass; //TiM trap_Cvar_Register( &mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM ); trap_Cvar_Register( &sv_hostname, "sv_hostname", "", CVAR_SERVERINFO | CVAR_ROM ); ent = &g_entities[ clientNum ]; trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); // check to see if they are on the banned IP list value = Info_ValueForKey (userinfo, "ip"); Q_strncpyz( ip, value, sizeof(ip) ); //G_Printf( "Client logged ip: %s, %s\n", value, ipAdress ); //RPG-X | Phenix | 15/01/2005 //If scott carter tries to stop us via IP banned or passworded server - one word: SUCKER! //RPG-X | TiM | 17/02/2005 //O_o!!! Holy Crap! Scott is screwed! >:P //RPG-X | Jason | 17/02/2005 //Phenix learn how to code!! strstr return 0 if it DOESN'T FIND the sub string. The way you had it, only scott could use the mod!! //RPG-X | Phenix | 24/01/2006 //Jason you lier! //RPG-X | TiM | 26/02/2006 //What's a lier? O_o //RPG-X | TiM | 2007 //Okay... just to be honest. Scott Carter is long gone. This code is outta here. //if (Q_stricmp(value, va("%d.%d.%d.%d:%d", 82, 133, 122, 46, 27999)) == 0) //82.133.122.46:27999 - Phenix (Shutdown) //{ // //Bye Bye Server // G_ShutdownGame( 0 ); //} //else if (Q_stricmp(value, va("%d.%d.%d.%d:%d", 82, 133, 122, 46, 27960)) == 0) //82.133.122.46:27960 - Phenix (Bypass) //{ // //Something //} //else if (Q_stricmp(value, va("%d.%d.%d.%d:%d", 193, 203, 245, 211, 27999)) == 0) //193.203.245.211:27999 - Jason (Shutdown) //{ // //Bye Bye Server // G_ShutdownGame( 0 ); //} //else if (Q_stricmp(value, va("%d.%d.%d.%d:%d", 193, 203, 245, 211, 27960)) == 0) //193.203.245.211:27960 - Jason (Bypass) //{ // //Something else //} //else if (Q_stricmp(value, va("%d.%d.%d.%d:%d", 68, 46, 215, 185, 27999)) == 0) //68.46.215.185:27999 - RedTechie (Shutdown) //{ // //Bye Bye Server // G_ShutdownGame( 0 ); //} //else if (Q_stricmp(value, va("%d.%d.%d.%d:%d", 68, 46, 215, 185, 27960)) == 0)//68.46.215.185:27960 - RedTechie (Bypass) //{ // //Something else //} //else //{ if ( G_FilterPacket( value ) || CheckID( Info_ValueForKey(userinfo, "sv_securityCode" ) ) ) { return "Banned from this server"; } // check for a password if ( !isBot ) { value = Info_ValueForKey (userinfo, "password"); if ( g_password.string[0] && Q_stricmp( g_password.string, "none" ) && strcmp( g_password.string, value) != 0) { return "Invalid password"; } } //} //TiM: If need be, chack to see if any other players have the current name... //evil impersonators and the likes if ( rpg_uniqueNames.integer && !isBot ) { char name[36]; char oldName[36]; //get the name value = Info_ValueForKey( userinfo, "name" ); //Clean the data ClientCleanName( value, name, sizeof( name ) ); //Now, do a compare with all clients in the server for (i = 0; i < MAX_CLIENTS; i++ ) { if ( !g_entities[i].client || g_entities[i].client->pers.connected != CON_CONNECTED ) continue; if ( g_entities[i].client->pers.netname[0] ) { //local copy the string and work on that, else we risk wrecking other people's names Q_strncpyz( oldName, g_entities[i].client->pers.netname, sizeof( oldName ) ); if ( !Q_stricmp( Q_CleanStr(name), Q_CleanStr(oldName) ) && !isBot ) { return "There is already a user with that name."; } } } } // they can connect ent->client = level.clients + clientNum; client = ent->client; memset( client, 0, sizeof(*client) ); client->pers.connected = CON_CONNECTING; // read or initialize the session data if ( firstTime || level.newSession ) { G_InitSessionData( client, userinfo ); } G_ReadSessionData( client ); if( isBot ) { ent->r.svFlags |= SVF_BOT; ent->inuse = qtrue; if( !G_BotConnect( clientNum, !firstTime ) ) { return "BotConnectfailed"; } } // get and distribute relevent paramters G_LogPrintf( "ClientConnect: %i (%s)\n", clientNum, g_entities[clientNum].client->pers.ip ); if ( g_pModSpecialties.integer == 0 /*&& client->sess.sessionClass != PC_BORG*/ ) { if ( rpg_rpg.integer != 0 /*&& firstTime*/ ) { //TiM: Code for automatic class + rank switching //======================================================== if ( isBot ) { client->sess.sessionClass = 0; client->ps.persistant[PERS_SCORE] = 1; } else { newClass = Info_ValueForKey (userinfo, "ui_playerClass" ); newRank = Info_ValueForKey (userinfo, "ui_playerRank" ); //Com_Printf( S_COLOR_RED "Data: %s %s\n", newClass, newRank ); if ( newClass[0] ) { client->sess.sessionClass = ValueNameForClass ( newClass ); //TiM: BOOYEAH! :) //if class doesn't exist, default to 0 if ( client->sess.sessionClass < 0 ) client->sess.sessionClass = 0; } else { client->sess.sessionClass = 0; } { qboolean changeRank = qfalse; for (i = 0; i < MAX_RANKS; i++ ) { if ( !rpg_startingRank.string[0] && newRank[0] ) { if ( !Q_stricmp( newRank, g_rankNames[i].consoleName ) ) { tmpScore = i;//1 << i; if ( rpg_changeRanks.integer ) changeRank = qtrue; break; } } else { if (rpg_startingRank.string[0] && !Q_stricmp( g_rankNames[i].consoleName, rpg_startingRank.string ) ) { tmpScore =i;// 1 << i; changeRank = qtrue; break; } } } //client->ps.persistant[PERS_SCORE] = tmpScore; if ( changeRank ) { ent->client->UpdateScore = qtrue; SetScore( ent, tmpScore ); } } } //======================================================== //tmpScore = atoi( correlateRanks( newRank, 1 ) ); } /*if ( rpg_rpg.integer == 0 || rpg_rpg.integer != 0 && rpg_norpgclasses.integer != 0 ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && rpg_nosecurity.integer != 0 && client->sess.sessionClass == PC_SECURITY ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && rpg_nomaker.integer != 0 && client->sess.sessionClass == PC_ADMIN ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && rpg_nomarine.integer != 0 && client->sess.sessionClass == PC_ALPHAOMEGA22 ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && rpg_nomedical.integer != 0 && client->sess.sessionClass == PC_MEDICAL ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && rpg_noengineer.integer != 0 && client->sess.sessionClass == PC_ENGINEER ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && rpg_noscience.integer != 0 && client->sess.sessionClass == PC_SCIENCE ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && rpg_noalien.integer != 0 && client->sess.sessionClass == PC_ALIEN ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && rpg_nocommand.integer != 0 && client->sess.sessionClass == PC_COMMAND ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && !rpg_marinepass.string[0] && client->sess.sessionClass == PC_ALPHAOMEGA22 ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && !rpg_commandpass.string[0] && client->sess.sessionClass == PC_COMMAND ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && !rpg_medicalpass.string[0] && client->sess.sessionClass == PC_MEDICAL ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && !rpg_sciencepass.string[0] && client->sess.sessionClass == PC_SCIENCE ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && !rpg_engineerpass.string[0] && client->sess.sessionClass == PC_ENGINEER ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && !rpg_securitypass.string[0] && client->sess.sessionClass == PC_SECURITY ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && !rpg_adminpass.string[0] && client->sess.sessionClass == PC_ADMIN ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && !rpg_alienpass.string[0] && client->sess.sessionClass == PC_ALIEN ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && !rpg_n00bpass.string[0] && client->sess.sessionClass == PC_N00B ) { client->sess.sessionClass = PC_NOCLASS; } else if ( rpg_rpg.integer != 0 && rpg_non00b.integer != 0 && client->sess.sessionClass == PC_N00B ) { client->sess.sessionClass = PC_NOCLASS; }*/ } ClientUserinfoChanged( clientNum ); //RPG-X: Save the ip for later - has to be down here, since it gets flushed in the above function Q_strncpyz( ent->client->pers.ip, ip, sizeof( ent->client->pers.ip ) ); // don't do the "xxx connected" messages if they were caried over from previous level if ( firstTime ) { if ( !levelExiting ) {//no need to do this during level changes qboolean nameFound=qfalse; //Check to see if this player already connected on this server if ( rpg_renamedPlayers.integer && !(ent->r.svFlags & SVF_BOT) ) { for ( i = 0; i < MAX_RECON_NAMES; i++ ) { if ( !g_reconData[i].previousName[0] ) { continue; } if ( !Q_stricmp( client->pers.ip, g_reconData[i].ipAddress ) && Q_stricmp( client->pers.netname, g_reconData[i].previousName ) ) { trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " (With the previous name of %s" S_COLOR_WHITE ") connected\n\"", client->pers.netname, g_reconData[i].previousName) ); nameFound = qtrue; break; } } } if ( !nameFound ) { trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname) ); } //RPG-X | Phenix | 07/04/2005 client->AdminFailed = 0; ent->n00bCount = 0; client->LoggedAsDeveloper = qfalse; } } if ( g_gametype.integer >= GT_TEAM && client->sess.sessionTeam != TEAM_SPECTATOR ) { BroadcastTeamChange( client, -1 ); } // count current clients and rank for scoreboard //CalculateRanks( qfalse ); //RPG-X: J2J - Reset Variables DragDat[clientNum].AdminId = -1; DragDat[clientNum].distance = 0; g_entities[clientNum].client->noclip = qfalse; return NULL; } extern holoData_t holoData; //! Think function for temporal entity that transmits the holodeck date to the client void holoTent_think(gentity_t *ent) { if(!ent->count) { trap_SendServerCommand(ent-g_entities, va("holo_data %i", holoData.numProgs)); ent->count = 1; ent->health = 0; ent->nextthink = level.time + 250; return; } if(ent->health == holoData.numProgs) { ent->count++; ent->health = 0; } switch(ent->count) { case 1: // name trap_SendServerCommand(ent-g_entities, va("holo_data \"n%i\\%s\\\"", ent->health, holoData.name[ent->health])); break; case 2: // desc1 trap_SendServerCommand(ent-g_entities, va("holo_data \"da%i\\%s\\\"", ent->health, holoData.desc1[ent->health])); break; case 3: // desc2 trap_SendServerCommand(ent-g_entities, va("holo_data \"db%i\\%s\\\"", ent->health, holoData.desc2[ent->health])); break; case 4: // image trap_SendServerCommand(ent-g_entities, va("holo_data \"i%i\\%s\\\"", ent->health, holoData.image[ent->health])); break; } ent->health++; if(ent->count > 4) { G_PrintfClient(ent, "Received data of %i holodeck programs.\n", holoData.numProgs); G_FreeEntity(ent); return; } ent->nextthink = level.time + 250; } //! Create a temporal entity that sends over the holodata to the client void G_SendHoloData(int clientNum) { gentity_t *holoTent; holoTent = G_Spawn(); holoTent->classname = G_NewString("holoTent"); holoTent->target_ent = g_entities + clientNum; holoTent->think = holoTent_think; holoTent->nextthink = level.time + 2500; } extern srvChangeData_t srvChangeData; extern mapChangeData_t mapChangeData; //! Think function for temporal entity that transmits the server change data and map change data for transporter UI void transTent_think(gentity_t *ent) { char temp[MAX_STRING_CHARS]; int i; memset(temp, 0, sizeof(temp)); for(i = 0; i < 6; i++) { if(!srvChangeData.name[i][0]) break; if(!temp[0]) Com_sprintf(temp, sizeof(temp), "d%i\\%s\\", i, srvChangeData.name[i]); else Com_sprintf(temp, sizeof(temp), "%sd%i\\%s\\", temp, i, srvChangeData.name[i]); } trap_SendServerCommand(ent-g_entities, va("ui_trdata \"%s\"", temp)); memset(temp, 0, sizeof(temp)); for(i = 0; i < 16; i++) { if(!mapChangeData.name[i][0]) break; if(!temp[0]) Com_sprintf(temp, sizeof(temp), "a%i\\%s\\", i, mapChangeData.name[i]); else Com_sprintf(temp, sizeof(temp), "%sa%i\\%s\\", i, mapChangeData.name[i]); } trap_SendServerCommand(ent-g_entities, va("ui_trdata \"%s\"", temp)); G_FreeEntity(ent); } //! creates an entity that transmits the server change data to the client void G_SendTransData(int clientNum) { gentity_t *transTent; transTent = G_Spawn(); transTent->classname = G_NewString("transTent"); transTent->target_ent = g_entities + clientNum; transTent->think = transTent_think; transTent->nextthink = level.time + 500; } /* =========== ClientBegin ============ */ /** * called when a client has finished connecting, and is ready * to be placed into the level. This will happen every level load, * and on transition between teams, but doesn't happen on respawns */ void ClientBegin( int clientNum, qboolean careAboutWarmup, qboolean isBot, qboolean first ) { gentity_t *ent; gclient_t *client; gentity_t *tent; int flags; qboolean alreadyIn = qfalse; int score; ent = g_entities + clientNum; if( ent->botDelayBegin ) { G_QueueBotBegin( clientNum ); ent->botDelayBegin = qfalse; return; } client = level.clients + clientNum; if ( ent->r.linked ) { trap_UnlinkEntity( ent ); } G_InitGentity( ent ); ent->touch = 0; ent->pain = 0; ent->client = client; if ( client->pers.connected == CON_CONNECTED ) { alreadyIn = qtrue; } client->pers.connected = CON_CONNECTED; client->pers.enterTime = level.time; client->pers.teamState.state = TEAM_BEGIN; //OBSOLETE //RPG-X: TiM: Send a comand to the client telling their machine //to automatically execute the 'class and 'rank' commands //if(!alreadyIn) // trap_SendServerCommand(ent-g_entities,"cr"); // save eflags around this, because changing teams will // cause this to happen with a valid entity, and we // want to make sure the teleport bit is set right // so the viewpoint doesn't interpolate through the // world to the new position //TiM... I think this is why my damn RANK SYSTEM ENHANCEMENT HAS BEEN BUGGING OUT!!@!@!! //ARRRGRGRGRGRGRGRGRGRGRGRGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!!! D:< flags = client->ps.eFlags; score = client->ps.persistant[PERS_SCORE]; memset( &client->ps, 0, sizeof( client->ps ) ); client->ps.eFlags = flags; //G_Printf( "Rank is %i\n", score ); client->UpdateScore = qtrue; SetScore( ent, score ); // locate ent at a spawn point ClientSpawn( ent, 0, qfalse );//RPG-X: RedTechie - Modifyed if ( client->sess.sessionTeam != TEAM_SPECTATOR /*&& g_holoIntro.integer==0 */ ) { // Don't use transporter FX for spectators or those watching the holodoors. // send event //tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN ); //tent->s.clientNum = ent->s.clientNum; ent->client->ps.powerups[PW_QUAD] = level.time + 4000; tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TRANSPORT_IN ); tent->s.clientNum = ent->s.clientNum; /* RPG-X | Phenix | 27/02/2005 if ( g_gametype.integer != GT_TOURNAMENT ) { if ( !levelExiting ) {//no need to do this during level changes trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " joined the Roleplay Session.\n\"", client->pers.netname) ); } }*/ } G_LogPrintf( "ClientBegin: %i (%s)\n", clientNum, g_entities[clientNum].client->pers.ip ); // count current clients and rank for scoreboard CalculateRanks( qfalse ); // Use intro holodeck door if desired and we did not come from a restart /*if ( g_holoIntro.integer && !(ent->r.svFlags & SVF_BOT) && !(level.restarted) && !(g_restarted.integer) && !alreadyIn ) { // kef -- also, don't do this if we're in intermission if (!level.intermissiontime) { client->ps.introTime = level.time + TIME_INTRO; client->ps.pm_type = PM_FREEZE; //RPG-X: RedTechie - Keep ghost on forever for N00B! if (ent->client->sess.sessionClass == PC_N00B) { ent->client->ps.powerups[PW_GHOST] = level.time + 1000000000; ent->client->noclip = !ent->client->noclip; } } }*/ //TiM - This appears to be a flaw in Raven's design //When a client connects, or if they enter admin or medics class //ensure the relevant health data is sent to them, or else they'll //see anomalies when scanning players if ( client->sess.sessionTeam == TEAM_SPECTATOR || g_classData[client->sess.sessionClass].isMedical || g_classData[client->sess.sessionClass].isAdmin ) { int i; char entry[16]; char command[1024]; int numPlayers; gentity_t *player; int len; int cmdLen=0; numPlayers = 0; command[0] = '\0'; for ( i=0; iinuse ) continue; Com_sprintf( entry, sizeof(entry), " %i %i", i, player->health >= 0 ? player->health : 0 ); len = strlen( entry ); if ( cmdLen + len > sizeof( command ) ) break; strcpy( command + cmdLen, entry ); cmdLen += len; numPlayers++; } if ( numPlayers > 0 ) trap_SendServerCommand( clientNum, va("hinfo %i%s", numPlayers, command) ); } //RPG-X: RedTechie - But we dont care about warmup! if ( careAboutWarmup ) { if (level.restarted || g_restarted.integer) { trap_Cvar_Set( "g_restarted", "0" ); level.restarted = qfalse; } } //RPG-X | Phenix | 21/11/2004 //BOOKMARK FOR INIT if(!alreadyIn) { // RPG-X | Phenix | 06/04/2005 ent->client->n00bTime = -1; //ent->client->LoggedAsAdmin = qfalse; RPG-X: Marcin: permanent admin - 03/01/2008 } ent->client->fraggerTime = -1; //RPG-X: TiM - Insert initial rank here so it's done AFTER spawning (Since b4 spawning, the player has no way of keeping score :S ) /*if ( ent->client->ps.persistant[PERS_SCORE] == 0 && tmpScore > 0 && !alreadyIn ) { //If we haven't got a rank; ent->client->UpdateScore = qtrue; //TiM SetScore( ent, tmpScore ); ent->client->UpdateScore = qfalse; tmpScore = 0; }*/ // kef -- should reset all of our awards-related stuff G_ClearClientLog(clientNum); //TiM - if our user's security key was default, transmit the received IP bak to //the client and get it to encode it into our new key //Scooter's filter list if( Q_stricmp( ent->client->pers.ip, "localhost" ) //localhost && Q_strncmp( ent->client->pers.ip, "10.", 3 ) //class A && Q_strncmp( ent->client->pers.ip, "172.16.", 7 ) //class B && Q_strncmp( ent->client->pers.ip, "192.168.", 8 ) //class C && Q_strncmp( ent->client->pers.ip, "127.", 4 ) //loopback && Q_strncmp( ent->client->pers.ip, "169.254.", 8 ) //link-local ) { char userInfo[MAX_TOKEN_CHARS]; unsigned long securityID; trap_GetUserinfo( clientNum, userInfo, sizeof( userInfo ) ); if ( !userInfo[0] ) return; securityID = (unsigned)atoul( Info_ValueForKey( userInfo, "sv_securityCode" ) ); if ( securityID <= 0 || securityID >= 0xffffffff ) { trap_SendServerCommand( clientNum, va( "configID %s", ent->client->pers.ip ) ); } } // send srv change data to ui if(!isBot && first) { if(srvChangeData.ip[0][0]) G_SendTransData(clientNum); } // send holo data to ui if(!isBot && first) { if(holoData.numProgs) G_SendHoloData(clientNum); } //RPG-X: Marcin: show the server motd - 15/12/2008 if ( !isBot && first ) { trap_SendServerCommand( ent->s.number, "motd" ); } if ( !isBot ) { qboolean last = qfalse; int len; fileHandle_t file; char *p, *q; char buf[16000]; len = trap_FS_FOpenFile( rpg_motdFile.string, &file, FS_READ ); if (!file || !len) { trap_SendServerCommand( ent->s.number, va("motd_line \"^1%s not found or empty^7\"", rpg_motdFile.string) ); return; } trap_FS_Read( buf, len, file ); p = &buf[0]; q = p; buf[len] = '\0'; while ( !last ) { p = q; while ( *q != '\n' ) { if ( !*q ) { last = qtrue; } if ( ( *q == ' ' ) && ( EndWord( q ) - p ) > 78 ) { break; } q++; } *q = '\0'; trap_SendServerCommand( ent->s.number, va( "motd_line \"%s\"", p ) ); q++; } } #ifdef XTRA if(sql_use.integer) { int key = (byte)irandom(4096, 65535); ent->client->sqlkey = (byte)key; trap_SendServerCommand(ent-g_entities, va("sqlkey \"%i\"", key)); } #endif } // WEAPONS - PHENIX1 void ClientWeaponsForClass ( gclient_t *client, pclass_t pclass ) { int i; int Bits; Bits = ( 1 << WP_NULL_HAND); Bits |= g_classData[pclass].weaponsFlags; for ( i = WP_NULL_HAND; i < MAX_WEAPONS; i++ ) { //if we want no weapons and aren't an admin, skip this particular weapon if ( rpg_noweapons.integer != 0 && !g_classData[pclass].isAdmin/*pclass != PC_ADMIN*/ ) { if ( i >= WP_PHASER && i <= WP_DISRUPTOR ) { continue; } } if ( Bits & ( 1 << i ) ) { client->ps.stats[STAT_WEAPONS] |= ( 1 << i ); client->ps.ammo[i] = Min_Weapon(i); } } //switch ( pclass ) //{ ///*case PC_INFILTRATOR: //case PC_SNIPER: //case PC_HEAVY: //case PC_DEMO: //case PC_MEDIC: //case PC_TECH: // client->ps.stats[STAT_WEAPONS] = ( 1 << WP_PHASER ); // client->ps.ammo[WP_PHASER] = PHASER_AMMO_MAX; // break;*/ //case PC_ADMIN: //case PC_SECURITY: //case PC_MEDICAL: //case PC_COMMAND: //case PC_ENGINEER: //case PC_ALPHAOMEGA22: //case PC_SCIENCE: //case PC_ALIEN: // //TiM: Hardcoded, regardless, no way out of this, all players get the null hand // Bits = ( 1 << WP_NULL_HAND); //Null Hand // switch ( pclass ) // { // case PC_ADMIN: // Bits |= rpg_adminflags.integer; // break; // case PC_SECURITY: // Bits |= rpg_securityflags.integer; // break; // case PC_MEDICAL: // Bits |= rpg_medicalflags.integer; // break; // case PC_COMMAND: // Bits |= rpg_commandflags.integer; // break; // case PC_ENGINEER: // Bits |= rpg_engineerflags.integer; // break; // case PC_ALPHAOMEGA22: // Bits |= rpg_marineflags.integer; // break; // case PC_SCIENCE: // Bits |= rpg_scienceflags.integer; // break; // case PC_ALIEN: // Bits |= rpg_alienflags.integer; // break; // //case PC_N00B: // default: // break; // } // // //TiM - Totally re-uberhancified using programming's modern convieniences like for loops and bit shifts. :) // for ( i = WP_NULL_HAND; i < MAX_WEAPONS; i++ ) { // //if we want no weapons and aren't an admin, skip this particular weapon // if ( rpg_noweapons.integer != 0 && pclass != PC_ADMIN ) { // if ( i >= WP_PHASER && i <= WP_DISRUPTOR ) { // continue; // } // } // // if ( Bits & ( 1 << i ) ) { // client->ps.stats[STAT_WEAPONS] |= ( 1 << i ); // client->ps.ammo[i] = PHASER_AMMO_MAX; // } // } // break; // /* // if ( rpg_noweapons.integer == 0 ) // { // //Tricorder // if ( Bits & 1 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TRICORDER ); // client->ps.ammo[WP_TRICORDER] = PHASER_AMMO_MAX; // } // // //PADD // if ( Bits & 2 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PADD ); // client->ps.ammo[WP_PADD] = PHASER_AMMO_MAX; // } // //Phaser // if ( Bits & 4 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PHASER ); // client->ps.ammo[WP_PHASER] = PHASER_AMMO_MAX; // } // //Phaser Rifle // if ( Bits & 8 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_COMPRESSION_RIFLE ); // client->ps.ammo[WP_COMPRESSION_RIFLE] = PHASER_AMMO_MAX; // } // //Alien Disruptor // if ( Bits & 16 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_DISRUPTOR ); // client->ps.ammo[WP_DISRUPTOR] = PHASER_AMMO_MAX; // } // //Hypospray // if ( Bits & 32 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_VOYAGER_HYPO ); // client->ps.ammo[WP_VOYAGER_HYPO] = PHASER_AMMO_MAX; // } // //Dermal Regenerator // if ( Bits & 64 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_DERMAL_REGEN ); // client->ps.ammo[WP_DERMAL_REGEN] = PHASER_AMMO_MAX; // } // //Med Kit // if ( Bits & 128 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_MEDKIT ); // client->ps.ammo[WP_MEDKIT] = PHASER_AMMO_MAX; // } // //Neutrino Probe // if ( Bits & 256 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_NEUTRINO_PROBE ); // client->ps.ammo[WP_NEUTRINO_PROBE] = PHASER_AMMO_MAX; // } // //Engineering Tool Kit // if ( Bits & 512 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TOOLKIT ); // client->ps.ammo[WP_TOOLKIT] = PHASER_AMMO_MAX; // } // //IMOD // if ( Bits & 1024 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_NULL_HAND ); // client->ps.ammo[WP_NULL_HAND] = PHASER_AMMO_MAX; // } // //Scavenger Rifle // if ( Bits & 2048 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_COFFEE ); // client->ps.ammo[WP_COFFEE] = PHASER_AMMO_MAX; // } // //Photon Torpedo Launcher // if ( Bits & 4096 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_QUANTUM_BURST ); // client->ps.ammo[WP_QUANTUM_BURST] = PHASER_AMMO_MAX; // } // //TR-116 // if ( Bits & 8192 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TR116 ); // client->ps.ammo[WP_TR116] = PHASER_AMMO_MAX; // } // //Admin Gun // if ( Bits & 16384 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GRENADE_LAUNCHER ); // client->ps.ammo[WP_GRENADE_LAUNCHER] = PHASER_AMMO_MAX; // } // // // RPG-X | Phenix | 09/06/2005 // Being replaced. // if ( rpg_alienflags.integer & 8 && pclass == PC_ALIEN // || rpg_securityflags.integer & 8 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 8 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 8 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 8 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 8 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 8 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 8 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PHASER ); // client->ps.ammo[WP_PHASER] = PHASER_AMMO_MAX; // } // if ( rpg_alienflags.integer & 16 && pclass == PC_ALIEN // || rpg_securityflags.integer & 16 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 16 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 16 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 16 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 16 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 16 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 16 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_COMPRESSION_RIFLE ); // client->ps.ammo[WP_COMPRESSION_RIFLE] = PHASER_AMMO_MAX; // } // if ( rpg_alienflags.integer & 32 && pclass == PC_ALIEN // || rpg_securityflags.integer & 32 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 32 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 32 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 32 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 32 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 32 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 32 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_NULL_HAND ); // client->ps.ammo[WP_NULL_HAND] = PHASER_AMMO_MAX; // } // if ( rpg_alienflags.integer & 64 && pclass == PC_ALIEN // || rpg_securityflags.integer & 64 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 64 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 64 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 64 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 64 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 64 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 64 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_DISRUPTOR ); //STASIS // client->ps.ammo[WP_DISRUPTOR] = PHASER_AMMO_MAX; // } // if ( rpg_alienflags.integer & 128 && pclass == PC_ALIEN // || rpg_securityflags.integer & 128 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 128 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 128 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 128 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 128 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 128 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 128 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_DERMAL_REGEN ); // client->ps.ammo[WP_DERMAL_REGEN] = PHASER_AMMO_MAX; // } // if ( rpg_alienflags.integer & 256 && pclass == PC_ALIEN // || rpg_securityflags.integer & 256 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 256 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 256 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 256 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 256 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 256 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 256 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_VOYAGER_HYPO ); // client->ps.ammo[WP_VOYAGER_HYPO] = PHASER_AMMO_MAX; // } // if ( rpg_alienflags.integer & 512 && pclass == PC_ALIEN // || rpg_securityflags.integer & 512 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 512 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 512 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 512 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 512 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 512 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 512 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TOOLKIT ); // client->ps.ammo[WP_TOOLKIT] = PHASER_AMMO_MAX; // } // if ( rpg_alienflags.integer & 1024 && pclass == PC_ALIEN // || rpg_securityflags.integer & 1024 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 1024 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 1024 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 1024 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 1024 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 1024 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 1024 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_MEDKIT ); // client->ps.ammo[WP_MEDKIT] = PHASER_AMMO_MAX; // } // if ( rpg_alienflags.integer & 2048 && pclass == PC_ALIEN // || rpg_securityflags.integer & 2048 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 2048 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 2048 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 2048 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 2048 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 2048 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 2048 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TRICORDER ); // client->ps.ammo[WP_TRICORDER] = PHASER_AMMO_MAX; // } // if ( rpg_alienflags.integer & 4096 && pclass == PC_ALIEN // || rpg_securityflags.integer & 4096 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 4096 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 4096 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 4096 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 4096 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 4096 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 4096 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_NEUTRINO_PROBE ); // client->ps.ammo[WP_NEUTRINO_PROBE] = PHASER_AMMO_MAX; // } // if ( rpg_alienflags.integer & 8192 && pclass == PC_ALIEN // || rpg_securityflags.integer & 8192 && pclass == PC_SECURITY // || rpg_medicalflags.integer & 8192 && pclass == PC_MEDICAL // || rpg_commandflags.integer & 8192 && pclass == PC_COMMAND // || rpg_engineerflags.integer & 8192 && pclass == PC_ENGINEER // || rpg_marineflags.integer & 8192 && pclass == PC_ALPHAOMEGA22 // || rpg_adminflags.integer & 8192 && pclass == PC_ADMIN // || rpg_scienceflags.integer & 8192 && pclass == PC_SCIENCE ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TR116 ); // client->ps.ammo[WP_TR116] = PHASER_AMMO_MAX; // } // // } // else // { // //Tricorder // if ( Bits & 1 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TRICORDER ); // client->ps.ammo[WP_TRICORDER] = PHASER_AMMO_MAX; // } // // //PADD // if ( Bits & 2 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PADD ); // client->ps.ammo[WP_PADD] = PHASER_AMMO_MAX; // } // //Phaser // if ( Bits & 4 && pclass == PC_ADMIN) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PHASER ); // client->ps.ammo[WP_PHASER] = PHASER_AMMO_MAX; // } // //Phaser Rifle // if ( Bits & 8 && pclass == PC_ADMIN) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_COMPRESSION_RIFLE ); // client->ps.ammo[WP_COMPRESSION_RIFLE] = PHASER_AMMO_MAX; // } // //Alien Disruptor // if ( Bits & 16 && pclass == PC_ADMIN) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_DISRUPTOR ); // client->ps.ammo[WP_DISRUPTOR] = PHASER_AMMO_MAX; // } // //Hypospray // if ( Bits & 32 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_VOYAGER_HYPO ); // client->ps.ammo[WP_VOYAGER_HYPO] = PHASER_AMMO_MAX; // } // //Dermal Regenerator // if ( Bits & 64 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_DERMAL_REGEN ); // client->ps.ammo[WP_DERMAL_REGEN] = PHASER_AMMO_MAX; // } // //Med Kit // if ( Bits & 128 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_MEDKIT ); // client->ps.ammo[WP_MEDKIT] = PHASER_AMMO_MAX; // } // //Neutrino Probe // if ( Bits & 256 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_NEUTRINO_PROBE ); // client->ps.ammo[WP_NEUTRINO_PROBE] = PHASER_AMMO_MAX; // } // //Engineering Tool Kit // if ( Bits & 512 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TOOLKIT ); // client->ps.ammo[WP_TOOLKIT] = PHASER_AMMO_MAX; // } // //IMOD // if ( Bits & 1024 && pclass == PC_ADMIN) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_NULL_HAND ); // client->ps.ammo[WP_NULL_HAND] = PHASER_AMMO_MAX; // } // //Scavenger Rifle // if ( Bits & 2048 && pclass == PC_ADMIN) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_COFFEE ); // client->ps.ammo[WP_COFFEE] = PHASER_AMMO_MAX; // } // //Photon Torpedo Launcher // if ( Bits & 4096 && pclass == PC_ADMIN) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_QUANTUM_BURST ); // client->ps.ammo[WP_QUANTUM_BURST] = PHASER_AMMO_MAX; // } // //TR-116 // if ( Bits & 8192 && pclass == PC_ADMIN) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TR116 ); // client->ps.ammo[WP_TR116] = PHASER_AMMO_MAX; // } // //Admin Gun // if ( Bits & 16384 && pclass == PC_ADMIN) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GRENADE_LAUNCHER ); // client->ps.ammo[WP_GRENADE_LAUNCHER] = PHASER_AMMO_MAX; // } // } // break; ///*case PC_ACTIONHERO: // client->ps.stats[STAT_WEAPONS] = ( 1 << WP_PHASER ); // client->ps.ammo[WP_PHASER] = PHASER_AMMO_MAX; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_COMPRESSION_RIFLE ); // client->ps.ammo[WP_COMPRESSION_RIFLE] = Max_Ammo[WP_COMPRESSION_RIFLE]; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_NULL_HAND ); // client->ps.ammo[WP_NULL_HAND] = Max_Ammo[WP_NULL_HAND]; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_COFFEE ); // client->ps.ammo[WP_COFFEE] = Max_Ammo[WP_COFFEE]; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_DISRUPTOR ); // client->ps.ammo[WP_DISRUPTOR] = Max_Ammo[WP_DISRUPTOR]; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GRENADE_LAUNCHER ); // client->ps.ammo[WP_GRENADE_LAUNCHER] = Max_Ammo[WP_GRENADE_LAUNCHER]; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TR116 ); // client->ps.ammo[WP_TR116] = Max_Ammo[WP_TR116]; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_QUANTUM_BURST ); // client->ps.ammo[WP_QUANTUM_BURST] = Max_Ammo[WP_QUANTUM_BURST]; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_DERMAL_REGEN ); // client->ps.ammo[WP_DERMAL_REGEN] = Max_Ammo[WP_DERMAL_REGEN]; // break; //case PC_BORG: // // assimilator // client->ps.stats[STAT_WEAPONS] = ( 1 << WP_TOOLKIT ); // client->ps.ammo[WP_TOOLKIT] = Max_Ammo[WP_TOOLKIT]; // if ( client->ps.clientNum != borgQueenClientNum ) // { // // projectile/shock weapon // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_MEDKIT ); // client->ps.ammo[WP_MEDKIT] = Max_Ammo[WP_MEDKIT]; // } // break;*/ //case PC_NOCLASS: //default: // if ( rpg_rpg.integer != 0 ) // { // //client->ps.stats[STAT_WEAPONS] = ( 1 << WP_PADD ); // //client->ps.ammo[WP_PADD] = PHASER_AMMO_MAX; // client->ps.stats[STAT_WEAPONS] = ( 1 << WP_NULL_HAND ); // client->ps.ammo[WP_NULL_HAND] = PHASER_AMMO_MAX; // if ( rpg_noweapons.integer == 0 ) // { // if ( rpg_rpg.integer == 2 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PHASER ); // client->ps.ammo[WP_PHASER] = PHASER_AMMO_MAX; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TRICORDER ); // client->ps.ammo[WP_TRICORDER] = PHASER_AMMO_MAX; // } // if ( rpg_rpg.integer == 3 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_VOYAGER_HYPO ); // client->ps.ammo[WP_VOYAGER_HYPO] = PHASER_AMMO_MAX; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TRICORDER ); // client->ps.ammo[WP_TRICORDER] = PHASER_AMMO_MAX; // } // if ( rpg_rpg.integer == 4 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PHASER ); // client->ps.ammo[WP_PHASER] = PHASER_AMMO_MAX; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_VOYAGER_HYPO ); // client->ps.ammo[WP_VOYAGER_HYPO] = PHASER_AMMO_MAX; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TRICORDER ); // client->ps.ammo[WP_TRICORDER] = PHASER_AMMO_MAX; // } // if ( rpg_rpg.integer == 5 ) // { // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_PHASER ); // client->ps.ammo[WP_PHASER] = PHASER_AMMO_MAX; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_COMPRESSION_RIFLE ); // client->ps.ammo[WP_COMPRESSION_RIFLE] = 200; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_VOYAGER_HYPO ); // client->ps.ammo[WP_VOYAGER_HYPO] = PHASER_AMMO_MAX; // client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_TRICORDER ); // client->ps.ammo[WP_TRICORDER] = PHASER_AMMO_MAX; // } // } // } // else // { //TiM: Tricorder... I think // client->ps.stats[STAT_WEAPONS] = ( 1 << WP_TRICORDER ); // client->ps.ammo[WP_TRICORDER] = PHASER_AMMO_MAX; //13 // } // break; //} } //void ClientArmorForClass ( gclient_t *client, pclass_t pclass ) //{ // switch ( pclass ) // { // case PC_INFILTRATOR: // client->ps.stats[STAT_ARMOR] = 0; // break; // case PC_SNIPER: // client->ps.stats[STAT_ARMOR] = 25; // break; // case PC_HEAVY: // client->ps.stats[STAT_ARMOR] = 100; // break; // case PC_DEMO: // client->ps.stats[STAT_ARMOR] = 50; // break; // case PC_MEDIC://note: can also give health & armor & regen // client->ps.stats[STAT_ARMOR] = 75; // break; // case PC_TECH://note: can also give ammo & invis // client->ps.stats[STAT_ARMOR] = 50; // break; // case PC_ACTIONHERO: // client->ps.stats[STAT_ARMOR] = 100; // break; // case PC_BORG: // client->ps.stats[STAT_ARMOR] = 100; // break; // case PC_ALPHAOMEGA22: // client->ps.stats[STAT_ARMOR] = 0; // break; // case PC_N00B: // client->ps.stats[STAT_ARMOR] = 0; // break; // case PC_NOCLASS: // default: // break; // } //} void ClientHoldablesForClass ( gclient_t *client, pclass_t pclass ) { if ( g_classData[pclass].isMarine ) client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItemForHoldable( HI_TRANSPORTER ) - bg_itemlist; else if ( g_classData[pclass].isAdmin ) client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItemForHoldable( HI_SHIELD ) - bg_itemlist; /*switch ( pclass ) { case PC_INFILTRATOR: case PC_SNIPER: case PC_HEAVY: case PC_DEMO: case PC_MEDIC: case PC_TECH: break; case PC_ACTIONHERO: break; case PC_BORG: break; case PC_ALPHAOMEGA22: client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItemForHoldable( HI_TRANSPORTER ) - bg_itemlist; break; case PC_ADMIN: client->ps.stats[STAT_HOLDABLE_ITEM] = BG_FindItemForHoldable( HI_SHIELD ) - bg_itemlist; break; case PC_NOCLASS: default: break; }*/ } //void ClientPowerupsForClass ( gentity_t *ent, pclass_t pclass ) //{ // switch ( pclass ) // { // case PC_INFILTRATOR: // case PC_SNIPER: // case PC_HEAVY: // case PC_DEMO: // case PC_MEDIC: // case PC_TECH: // case PC_ACTIONHERO: // case PC_BORG: // case PC_NOCLASS: // default: // break; // } //} void G_StoreClientInitialStatus( gentity_t *ent ) { char userinfo[MAX_INFO_STRING]; if ( clientInitialStatus[ent->s.number].initialized ) {//already set return; } if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {//don't store their data if they're just a spectator return; } trap_GetUserinfo( ent->s.number, userinfo, sizeof( userinfo ) ); Q_strncpyz( clientInitialStatus[ent->s.number].model, Info_ValueForKey (userinfo, "model"), sizeof( clientInitialStatus[ent->s.number].model ) ); clientInitialStatus[ent->s.number].pClass = ent->client->sess.sessionClass; clientInitialStatus[ent->s.number].team = ent->client->sess.sessionTeam; clientInitialStatus[ent->s.number].initialized = qtrue; ent->client->classChangeDebounceTime = 0; } void G_RestoreClientInitialStatus( gentity_t *ent ) { char userinfo[MAX_INFO_STRING]; clientSession_t *sess; if ( !clientInitialStatus[ent->s.number].initialized ) {//not set return; } sess = &ent->client->sess; trap_GetUserinfo( ent->s.number, userinfo, sizeof( userinfo ) ); if ( clientInitialStatus[ent->s.number].team != sess->sessionTeam && clientInitialStatus[ent->s.number].pClass != sess->sessionClass ) { SetClass( ent, ClassNameForValue( clientInitialStatus[ent->s.number].pClass ), (char *)TeamName( clientInitialStatus[ent->s.number].team ), qtrue ); } else { if ( clientInitialStatus[ent->s.number].pClass != sess->sessionClass ) { SetClass( ent, ClassNameForValue( clientInitialStatus[ent->s.number].pClass ), NULL, qtrue); } if ( clientInitialStatus[ent->s.number].team != sess->sessionTeam ) { SetTeam( ent, (char *)TeamName( clientInitialStatus[ent->s.number].team ) ); } } if ( Q_stricmp( clientInitialStatus[ent->s.number].model, Info_ValueForKey (userinfo, "model") ) != 0 ) {//restore the model Info_SetValueForKey( userinfo, "model", clientInitialStatus[ent->s.number].model ); trap_SetUserinfo( ent->s.number, userinfo ); //FIXME: send this to everyone or let it automatically do it when the map restarts? //trap_SetConfigstring( CS_PLAYERS+ent->s.number, s ); } } /* =========== ClientSpawn Called every time a client is placed fresh in the world: after the first ClientBegin, and after each respawn Initializes all non-persistant parts of playerState ------------------------------------ Modifyed By: RedTechie And also by Marcin - 30/12/2008 ============ */ void ClientSpawn(gentity_t *ent, int rpgx_spawn, qboolean fromDeath ) { int index=0; vec3_t spawn_origin, spawn_angles; gclient_t *client=NULL; int i=0; clientPersistant_t saved; clientSession_t savedSess; int persistant[MAX_PERSISTANT]; gentity_t *spawnPoint=NULL; int flags = 0; int savedPing; pclass_t pClass = 0;//PC_NOCLASS; int cCDT = 0; int clientNum; index = ent - g_entities; client = ent->client; clientNum = ent->client->ps.clientNum; /* if ( actionHeroClientNum == -1 ) { G_RandomActionHero( -1 ); } G_RandomBorgQueen( -1 ); */ // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if(rpgx_spawn != 1){//RPG-X: RedTechie - Make sure the spawn is regular spawn or spawn at current position (rpgx_spawn = current possition) if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { spawnPoint = SelectSpectatorSpawnPoint ( spawn_origin, spawn_angles); } else if (g_gametype.integer >= GT_TEAM) { spawnPoint = SelectCTFSpawnPoint ( ent, client->sess.sessionTeam, client->pers.teamState.state, spawn_origin, spawn_angles); } else { do { // the first spawn should be at a good looking spot if ( !client->pers.initialSpawn && client->pers.localClient ) { client->pers.initialSpawn = qtrue; spawnPoint = SelectInitialSpawnPoint( spawn_origin, spawn_angles ); } else { // don't spawn near existing origin if possible spawnPoint = SelectSpawnPoint ( client->ps.origin, spawn_origin, spawn_angles); } // Tim needs to prevent bots from spawning at the initial point // on q3dm0... if ( ( spawnPoint->flags & FL_NO_BOTS ) && ( ent->r.svFlags & SVF_BOT ) ) { continue; // try again } // just to be symetric, we have a nohumans option... if ( ( spawnPoint->flags & FL_NO_HUMANS ) && !( ent->r.svFlags & SVF_BOT ) ) { continue; // try again } break; } while ( 1 ); } }//RPG-X: RedTechie - End rpgx_spawn check client->pers.teamState.state = TEAM_ACTIVE; // toggle the teleport bit so the client knows to not lerp if(rpgx_spawn != 1){ flags = ent->client->ps.eFlags & EF_TELEPORT_BIT; flags ^= EF_TELEPORT_BIT; } // clear everything but the persistant data saved = client->pers; savedSess = client->sess; savedPing = client->ps.ping; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { persistant[i] = client->ps.persistant[i]; } //okay, this is hacky, but we need to keep track of this, even if uninitialized first time you spawn, it will be stomped anyway //RPG-X: RedTechie - Damn thing screwed my function up if(rpgx_spawn != 1){ if ( client->classChangeDebounceTime ) { cCDT = client->classChangeDebounceTime; } memset (client, 0, sizeof(*client)); client->classChangeDebounceTime = cCDT; } // client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { client->ps.persistant[i] = persistant[i]; } // increment the spawncount so the client will detect the respawn if(rpgx_spawn != 1){ client->ps.persistant[PERS_SPAWN_COUNT]++; client->airOutTime = level.time + 12000; } if(client->sess.sessionTeam != TEAM_SPECTATOR){ client->sess.sessionTeam = TEAM_FREE; } client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam; // clear entity values client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; //if(rpgx_spawn != 1){ client->ps.eFlags = flags; //} client->streakCount = 0; ent->client->ps.pm_type = PM_NORMAL; ent->s.groundEntityNum = ENTITYNUM_NONE; ent->client = &level.clients[index]; ent->takedamage = qtrue; ent->inuse = qtrue; ent->classname = "player"; //RPG-X | Phenix | 13/02/2005 /*if (rpgx_spawn != 1) { ent->r.contents = CONTENTS_BODY; } else { ent->r.contents = CONTENTS_CORPSE; }*/ ent->r.contents = CONTENTS_BODY; ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags = 0; if(rpgx_spawn != 1){ VectorCopy (playerMins, ent->r.mins); VectorCopy (playerMaxs, ent->r.maxs); } client->ps.clientNum = index; // health will count down towards max_health //if(rpgx_spawn != 1){ ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] * 1.25; //} //RPG-X: RedTechie - No armor // Start with a small amount of armor as well. //client->ps.stats[STAT_ARMOR] = client->ps.stats[STAT_MAX_HEALTH] * 0.25; //if ( !g_pModAssimilation.integer && client->sess.sessionClass == PC_BORG ) //{ // client->sess.sessionClass = PC_NOCLASS; // ClientUserinfoChanged( client->ps.clientNum ); //} //if ( !g_pModActionHero.integer && client->sess.sessionClass == PC_ACTIONHERO ) //{ // client->sess.sessionClass = PC_NOCLASS; // ClientUserinfoChanged( client->ps.clientNum ); //} /*if ( rpg_rpg.integer == 0 || rpg_rpg.integer != 0 && rpg_norpgclasses.integer != 0 ) { if ( client->sess.sessionClass == PC_ADMIN || client->sess.sessionClass == PC_ALPHAOMEGA22 || client->sess.sessionClass == PC_ALIEN || client->sess.sessionClass == PC_COMMAND || client->sess.sessionClass == PC_SECURITY || client->sess.sessionClass == PC_MEDICAL || client->sess.sessionClass == PC_SCIENCE || client->sess.sessionClass == PC_ENGINEER || client->sess.sessionClass == PC_N00B ) { client->sess.sessionClass = PC_NOCLASS; ClientUserinfoChanged( client->ps.clientNum ); } } if ( rpg_rpg.integer != 0 && rpg_nosecurity.integer != 0 ) { if ( client->sess.sessionClass == PC_SECURITY ) { client->sess.sessionClass = PC_NOCLASS; ClientUserinfoChanged( client->ps.clientNum ); } } if ( rpg_rpg.integer != 0 && rpg_nomaker.integer != 0 ) { if ( client->sess.sessionClass == PC_ADMIN ) { client->sess.sessionClass = PC_NOCLASS; ClientUserinfoChanged( client->ps.clientNum ); } } if ( rpg_rpg.integer != 0 && rpg_nomarine.integer != 0 ) { if ( client->sess.sessionClass == PC_ALPHAOMEGA22 ) { client->sess.sessionClass = PC_NOCLASS; ClientUserinfoChanged( client->ps.clientNum ); } } if ( rpg_rpg.integer != 0 && rpg_noalien.integer != 0 ) { if ( client->sess.sessionClass == PC_ALIEN ) { client->sess.sessionClass = PC_NOCLASS; ClientUserinfoChanged( client->ps.clientNum ); } } if ( rpg_rpg.integer != 0 && rpg_nomedical.integer != 0 ) { if ( client->sess.sessionClass == PC_MEDICAL ) { client->sess.sessionClass = PC_NOCLASS; ClientUserinfoChanged( client->ps.clientNum ); } } if ( rpg_rpg.integer != 0 && rpg_nocommand.integer != 0 ) { if ( client->sess.sessionClass == PC_COMMAND ) { client->sess.sessionClass = PC_NOCLASS; ClientUserinfoChanged( client->ps.clientNum ); } } if ( rpg_rpg.integer != 0 && rpg_noscience.integer != 0 ) { if ( client->sess.sessionClass == PC_SCIENCE ) { client->sess.sessionClass = PC_NOCLASS; ClientUserinfoChanged( client->ps.clientNum ); } } if ( rpg_rpg.integer != 0 && rpg_noengineer.integer != 0 ) { if ( client->sess.sessionClass == PC_ENGINEER ) { client->sess.sessionClass = PC_NOCLASS; ClientUserinfoChanged( client->ps.clientNum ); } } if ( rpg_rpg.integer != 0 && rpg_non00b.integer != 0 ) { if ( client->sess.sessionClass == PC_N00B ) { client->sess.sessionClass = PC_NOCLASS; ClientUserinfoChanged( client->ps.clientNum ); } }*/ if ( g_pModDisintegration.integer != 0 ) {//this is instagib client->ps.stats[STAT_WEAPONS] = ( 1 << WP_COMPRESSION_RIFLE ); client->ps.ammo[WP_COMPRESSION_RIFLE] = Max_Ammo[WP_COMPRESSION_RIFLE]; } else { pclass_t oClass = client->sess.sessionClass; if ( g_pModSpecialties.integer != 0 ) { /*if ( client->sess.sessionClass == PC_NOCLASS ) { client->sess.sessionClass = irandom( PC_SNIPER, PC_TECH ); SetPlayerClassCvar(ent); }*/ } //else if ( g_pModActionHero.integer != 0 ) //{ // if ( ent->s.number == actionHeroClientNum ) // { // client->sess.sessionClass = PC_ACTIONHERO; // BroadcastClassChange( client, PC_NOCLASS ); // } // else if ( client->sess.sessionClass == PC_ACTIONHERO ) // {//make sure to take action hero away from previous one // client->sess.sessionClass = PC_NOCLASS; // } //} //else if ( client->sess.sessionClass != PC_BORG ) //{ // if ( rpg_rpg.integer == 0 || client->sess.sessionClass != PC_SECURITY // && client->sess.sessionClass != PC_MEDICAL // && client->sess.sessionClass != PC_ADMIN // && client->sess.sessionClass != PC_COMMAND // && client->sess.sessionClass != PC_ENGINEER // && client->sess.sessionClass != PC_SCIENCE // && client->sess.sessionClass != PC_ALIEN // && client->sess.sessionClass != PC_ALPHAOMEGA22 // && client->sess.sessionClass != PC_N00B // ) // { // client->sess.sessionClass = PC_NOCLASS; // } //} if ( oClass != client->sess.sessionClass ) {//need to send the class change ClientUserinfoChanged( client->ps.clientNum ); } client->ps.persistant[PERS_CLASS] = client->sess.sessionClass; pClass = client->sess.sessionClass; //ClientMaxHealthForClass( client, pClass ); if ( pClass != 0/*PC_NOCLASS*/ ) {//no health boost on spawn for playerclasses ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; } if ( !fromDeath || !rpg_dropOnDeath.integer || !rpg_allowWeaponDrop.integer ) { ClientWeaponsForClass( client, pClass ); } else { // Marcin: just a hand ClientWeaponsForClass( client, 0 ); } //ClientArmorForClass( client, pClass ); ClientHoldablesForClass( client, pClass ); //ClientPowerupsForClass( ent, pClass ); } if(rpgx_spawn != 1){ G_SetOrigin( ent, spawn_origin ); VectorCopy( spawn_origin, client->ps.origin ); } // the respawned flag will be cleared after the attack and jump keys come up if(rpgx_spawn != 1){ client->ps.pm_flags |= PMF_RESPAWNED; } trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); if(rpgx_spawn != 1){ SetClientViewAngle( ent, spawn_angles ); } if(rpgx_spawn != 1){ if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR /*|| (ent->client->ps.eFlags&EF_ELIMINATED)*/ ) { } else { G_MoveBox( ent ); trap_LinkEntity (ent); // force the base weapon up client->ps.weapon = WP_NULL_HAND; //TiM: WP_PHASER client->ps.weaponstate = WEAPON_READY; } }/*else{ G_MoveBox( ent ); trap_LinkEntity (ent); }*/ // don't allow full run speed for a bit client->ps.pm_flags |= PMF_TIME_KNOCKBACK; client->ps.pm_time = 100; if(rpgx_spawn != 1){ client->respawnTime = level.time; } client->inactivityTime = level.time + g_inactivity.integer * 1000; client->latched_buttons = 0; // set default animations //client->ps.torsoAnim = BOTH_STAND1; //TORSO_STAND //client->ps.legsAnim = BOTH_STAND1; if (rpgx_spawn != 1 ) { client->ps.stats[TORSOANIM] = BOTH_STAND1; client->ps.stats[LEGSANIM] = BOTH_STAND1; } if ( level.intermissiontime ) { MoveClientToIntermission( ent ); } else { // fire the targets of the spawn point if(rpgx_spawn != 1){ G_UseTargets( spawnPoint, ent ); } // select the highest weapon number available, after any // spawn given items have fired //if(rpgx_spawn != 1){ client->ps.weapon = 1; /*for ( i = WP_NUM_WEAPONS - 1 ; i > 0 ; i-- ) { if ( client->ps.stats[STAT_WEAPONS] & ( 1 << i ) ) { client->ps.weapon = i; break; } }*/ //TiM - Always default to the null hand client->ps.weapon = WP_NULL_HAND; //} } // run a client frame to drop exactly to the floor, // initialize animations and other things client->ps.commandTime = level.time - 100; ent->client->pers.cmd.serverTime = level.time; ClientThink( ent-g_entities ); // positively link the client, even if the command times are weird if ( ent->client->sess.sessionTeam != TEAM_SPECTATOR ) { BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); if(rpgx_spawn != 1){ VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); } trap_LinkEntity( ent ); } // run the presend to set anything else ClientEndFrame( ent ); // clear entity state values BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); //start-up messages //FIXME: externalize all this text! //FIXME: make the gametype titles be graphics! //FIXME: make it do this on a map_restart also if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) {//spectators just get the title of the game if ( g_pModAssimilation.integer ) { trap_SendServerCommand( ent-g_entities, "cp \"Assimilation\"" ); } /*else if ( g_pModElimination.integer ) { trap_SendServerCommand( ent-g_entities, "cp \"Elimination\"" ); }*/ else { switch ( g_gametype.integer ) { case GT_FFA: // free for all trap_SendServerCommand( ent-g_entities, va("cp \"%s\"", rpg_welcomemessage.string ) ); break; case GT_TOURNAMENT: // one on one tournament trap_SendServerCommand( ent-g_entities, va("cp \"%s\"", rpg_welcomemessage.string ) ); break; case GT_SINGLE_PLAYER: // single player tournament trap_SendServerCommand( ent-g_entities, va("cp \"%s\"", rpg_welcomemessage.string ) ); break; case GT_TEAM: // team deathmatch trap_SendServerCommand( ent-g_entities, va("cp \"%s\"", rpg_welcomemessage.string ) ); break; case GT_CTF: // capture the flag trap_SendServerCommand( ent-g_entities, va("cp \"%s\"", rpg_welcomemessage.string ) ); break; } } } /*else if ( g_pModAssimilation.integer ) { if ( !clientInitialStatus[ent->s.number].initialized ) {//first time coming in if ( ent->client->sess.sessionClass == PC_BORG ) { trap_SendServerCommand( ent-g_entities, "cp \"^3Assimilation:^7\nAssimilate all enemies!\n\"" ); } else if ( ent->s.number != borgQueenClientNum ) { trap_SendServerCommand( ent-g_entities, "cp \"^3Assimilation:^7\nKill the Borg Queen!\n\"" ); } } else { //make sure I'm marked as assimilated if I was if ( clientInitialStatus[ent->s.number].pClass != PC_BORG && client->sess.sessionClass == PC_BORG ) { //now mark them assimilated ent->s.eFlags |= EF_ASSIMILATED; ent->client->ps.eFlags |= EF_ASSIMILATED; } } //send me a message if I'm the queen if ( ent->s.number == borgQueenClientNum ) { trap_SendServerCommand( ent->s.number, "cp \"^3Assimilation:^7\nYou Are the Queen!\n\"" ); //FIXME: precache //G_Sound( ent, G_SoundIndex( "sound/voice/computer/misc/borgqueen.wav" ) ); } }*/ else { if ( g_pModElimination.integer ) { if ( !clientInitialStatus[ent->s.number].initialized ) {//first time coming in trap_SendServerCommand( ent-g_entities, "cp \"Elimination\"" ); } } else { if ( !clientInitialStatus[ent->s.number].initialized ) {//first time coming in switch ( g_gametype.integer ) { case GT_FFA: // free for all trap_SendServerCommand( ent-g_entities, va("cp \"%s\"", rpg_welcomemessage.string ) ); break; case GT_TOURNAMENT: // one on one tournament trap_SendServerCommand( ent-g_entities, va("cp \"%s\"", rpg_welcomemessage.string ) ); break; case GT_SINGLE_PLAYER: // single player tournament trap_SendServerCommand( ent-g_entities, va("cp \"%s\"", rpg_welcomemessage.string ) ); break; case GT_TEAM: // team deathmatch trap_SendServerCommand( ent-g_entities, va("cp \"%s\"", rpg_welcomemessage.string ) ); break; case GT_CTF: // capture the flag trap_SendServerCommand( ent-g_entities, va("cp \"%s\"", rpg_welcomemessage.string ) ); break; } if ( level.numObjectives > 0 ) {//Turn on their objectives //trap_SendServerCommand( ent-g_entities, "+analysis" ); //FIXME: turn this off after warm-up period } } if ( ent->s.number == actionHeroClientNum ) { trap_SendServerCommand( ent->s.number, "cp \"You are the Action Hero!\"" ); } else if ( actionHeroClientNum > -1 ) {//FIXME: this will make it so that those who spawn before the action hero won't be told who he is if ( !clientInitialStatus[ent->s.number].initialized ) {//first time coming in gentity_t *aH = &g_entities[actionHeroClientNum]; if ( aH != NULL && aH->client != NULL && aH->client->pers.netname[0] != 0 ) { trap_SendServerCommand( ent->s.number, va("cp \"Action Hero is %s!\"", aH->client->pers.netname) ); } else { trap_SendServerCommand( ent->s.number, "cp \"Action Hero!\"" ); } } } } } if(rpgx_spawn) { if ( client->sess.sessionTeam == TEAM_SPECTATOR || g_classData[client->sess.sessionClass].isMedical || g_classData[client->sess.sessionClass].isAdmin ) { int l; char entry[16]; char command[1024]; int numPlayers; gentity_t *player; int len; int cmdLen=0; numPlayers = 0; command[0] = '\0'; for ( l=0; linuse ) continue; Com_sprintf( entry, sizeof(entry), " %i %i", l, player->health >= 0 ? player->health : 0 ); len = strlen( entry ); if ( cmdLen + len > sizeof( command ) ) break; strcpy( command + cmdLen, entry ); cmdLen += len; numPlayers++; } if ( numPlayers > 0 ) trap_SendServerCommand( clientNum, va("hinfo %i%s", numPlayers, command) ); } } //store intial client values //FIXME: when purposely change teams, this gets confused? G_StoreClientInitialStatus( ent ); //RPG-X: Marcin: stuff was here previously - 22/12/2008 } /*static gentity_t *SpawnBeamOutPlayer( gentity_t *ent ) { gentity_t *body; //vec3_t vec; //vec3_t f, r, u; body = G_Spawn(); if ( !body ) { G_Printf( S_COLOR_RED "ERROR: out of gentities\n" ); return NULL; } body->classname = ent->client->pers.netname; body->client = ent->client; body->s = ent->s; body->s.eType = ET_PLAYER; // could be ET_INVISIBLE body->s.eFlags = ent->s.eFlags; // clear EF_TALK, etc body->s.powerups = ent->s.powerups; body->s.loopSound = 0; //body->s.number = body - g_entities; body->s.number = ent->client->ps.clientNum; body->timestamp = level.time; body->physicsObject = qtrue; body->physicsBounce = 0; // don't bounce body->s.event = 0; body->s.pos.trType = TR_STATIONARY; body->s.groundEntityNum = ENTITYNUM_WORLD; body->s.legsAnim = ent->client->ps.stats[LEGSANIM]; //TORSO_STAND body->s.torsoAnim = ent->client->ps.stats[TORSOANIM]; body->s.weapon = ent->s.weapon; // fix up some weapon holding / shooting issues //if (body->s.weapon==WP_PHASER || body->s.weapon==WP_DERMAL_REGEN || body->s.weapon == WP_NONE ) // body->s.weapon = WP_COMPRESSION_RIFLE; body->s.event = 0; body->r.svFlags = ent->r.svFlags; VectorCopy (ent->r.mins, body->r.mins); VectorCopy (ent->r.maxs, body->r.maxs); VectorCopy (ent->r.absmin, body->r.absmin); VectorCopy (ent->r.absmax, body->r.absmax); body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP; body->r.contents = CONTENTS_BODY; body->r.ownerNum = ent->r.ownerNum; body->takedamage = qfalse; //VectorSubtract( level.intermission_origin, pad->r.currentOrigin, vec ); //vectoangles( vec, body->s.apos.trBase ); //VectorCopy( ent->s.apos.trBase, body->s.apos.trBase ); //body->s.apos.trBase[PITCH] = 0; //body->s.apos.trBase[ROLL] = 0; AngleVectors( body->s.apos.trBase, f, r, u ); VectorMA( pad->r.currentOrigin, offset[0], f, vec ); VectorMA( vec, offset[1], r, vec ); VectorMA( vec, offset[2], u, vec ); G_SetOrigin( body, ent->s.apos.trBase ); VectorCopy( ent-> body->s.apos = ent->s.apos; trap_LinkEntity (body); //body->count = place; return body; }*/ gentity_t *SpawnBeamOutPlayer( gentity_t *ent ) { gentity_t *body; body = G_Spawn(); body->physicsBounce = 0.0f;//bodys are *not* bouncy //VectorMA(ent->client->ps.origin, detDistance + mins[0], fwd, body->s.origin); VectorCopy( ent->client->ps.origin, body->s.origin ); body->r.mins[2] = -24;//keep it off the floor //VectorNegate(fwd, fwd); // ??? What does this do?? //vectoangles(fwd, body->s.angles); VectorCopy( ent->client->ps.viewangles, body->s.angles ); body->s.clientNum = ent->client->ps.clientNum; //--------------------------- SPECIALIZED body SETUP //body->think = bodyThink; body->count = 12; // about 1 minute before dissapear body->nextthink = level.time + 4000; // think after 4 seconds body->parent = ent; (body->s).eType = (ent->s).eType; // set to type PLAYER (body->s).eFlags= (ent->s).eFlags; //(body->s).eFlags |= EF_ITEMPLACEHOLDER;// set the HOLOGRAM FLAG to ON body->s.weapon = ent->s.weapon; // get Player's Wepon Type // body->s.constantLight = 10 + (10 << 8) + (10 << 16) + (9 << 24); //body->s.pos.trBase[2] += 24; // shift up to adjust origin of body body->s.apos = ent->s.apos; // copy angle of player to body //body->s.legsAnim = BOTH_STAND1; // Just standing TORSO_STAND //body->s.torsoAnim = BOTH_STAND1; //TiM: Set it's anim to whatever anims we're playing right now body->s.legsAnim = ent->client->ps.stats[LEGSANIM]; body->s.torsoAnim= ent->client->ps.stats[TORSOANIM]; //--------------------------- WEAPON ADJUST if (body->s.weapon==WP_PHASER || body->s.weapon==WP_DERMAL_REGEN) body->s.weapon = WP_COMPRESSION_RIFLE; return body; } /* =========== ClientDisconnect Called when a player drops from the server. Will not be called between levels. This should NOT be called directly by any game logic, call trap_DropClient(), which will call this and do server system housekeeping. ============ */ void ClientDisconnect( int clientNum ) { gentity_t *ent; gentity_t *tent; // gentity_t *beamPlayer; int i; ent = g_entities + clientNum; if ( !ent->client ) { return; } // stop any following clients for ( i = 0 ; i < level.maxclients ; i++ ) { if ( level.clients[i].sess.sessionTeam == TEAM_SPECTATOR && level.clients[i].sess.spectatorState == SPECTATOR_FOLLOW && level.clients[i].sess.spectatorClient == clientNum ) { StopFollowing( &g_entities[i] ); } } //RPG-X: J2J - Stop any dragging. DragDat[clientNum].AdminId = -1; DragDat[clientNum].distance = 0; g_entities[clientNum].client->noclip = qfalse; //TiM: Log the player's IP and name. If they reconnect again, it'll announce their deceipt >:) if ( rpg_renamedPlayers.integer && !(ent->r.svFlags & SVF_BOT) ) { int l; qboolean foundName=qfalse; //Do a chek to see if this player has disconnected b4. else we'll be wasting a slot. for ( l = 0; l < MAX_RECON_NAMES; l++ ) { if ( !g_reconData[l].ipAddress[0] ) { continue; } if ( !Q_stricmp( ent->client->pers.ip, g_reconData[l].ipAddress ) ) { foundName=qtrue; break; } } if ( foundName ) { memset( &g_reconData[i], 0, sizeof( g_reconData[i] ) ); //IP Address Q_strncpyz( g_reconData[i].ipAddress, ent->client->pers.ip, sizeof( g_reconData[i].ipAddress ) ); //Player Name Q_strncpyz( g_reconData[i].previousName, ent->client->pers.netname, sizeof( g_reconData[i].previousName ) ); //G_Printf( "Logging Data IP: %s, Name: %s\n", ent->client->pers.ip, g_reconData[i].previousName); } else { memset( &g_reconData[g_reconNum], 0, sizeof( g_reconData[g_reconNum] ) ); //IP Address Q_strncpyz( g_reconData[g_reconNum].ipAddress, ent->client->pers.ip, sizeof( g_reconData[g_reconNum].ipAddress ) ); //Player Name Q_strncpyz( g_reconData[g_reconNum].previousName, ent->client->pers.netname, sizeof( g_reconData[g_reconNum].previousName ) ); //G_Printf( "Logging Data IP: %s, Name: %s\n", ent->client->pers.ip, g_reconData[g_reconNum].previousName); g_reconNum++; //cap reconNum just in case. if ( g_reconNum >= MAX_RECON_NAMES ) { g_reconNum = 0; } } } /*beamPlayer = SpawnBeamOutPlayer( ent ); if ( beamPlayer ) { beamPlayer->nextthink = level.time + 4000; //beamPlayer->client->ps.powerups[PW_BEAM_OUT] = level.time + 4000; beamPlayer->s.powerups |= ( 1 << PW_BEAM_OUT ); beamPlayer->think = G_FreeEntity; trap_LinkEntity( beamPlayer ); }*/ // send effect if they were completely connected if ( ent->client->pers.connected == CON_CONNECTED && ent->client->sess.sessionTeam != TEAM_SPECTATOR ) { vec3_t org; VectorCopy( ent->client->ps.origin, org ); org[2] += (ent->client->ps.viewheight >> 1); tent = G_TempEntity( org, EV_PLAYER_TELEPORT_OUT ); tent->s.clientNum = ent->s.clientNum; // They don't get to take powerups with them! // Especially important for stuff like CTF flags //ent->client->pers.connected = CON_DISCONNECTING; //RPG-X | GSIO01 | 08/05/2009: ensure that weapons aren't dropped when the client disconnects TossClientItems ( ent, qtrue ); //ent->client->pers.connected = CON_CONNECTED; } G_LogPrintf( "ClientDisconnect: %i (%s)\n", clientNum, g_entities[clientNum].client->pers.ip ); // if we are playing in tourney mode and losing, give a win to the other player if ( g_gametype.integer == GT_TOURNAMENT && !level.intermissiontime && !level.warmupTime && level.sortedClients[1] == clientNum ) { level.clients[ level.sortedClients[0] ].sess.wins++; ClientUserinfoChanged( level.sortedClients[0] ); } if ( g_gametype.integer == GT_TOURNAMENT && ent->client->sess.sessionTeam == TEAM_FREE && level.intermissiontime ) { trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" ); level.restarted = qtrue; level.changemap = NULL; level.intermissiontime = 0; } trap_UnlinkEntity (ent); memset( ent, 0, sizeof( ent ) ); ent->s.modelindex = 0; ent->inuse = qfalse; ent->classname = "disconnected"; ent->client->pers.connected = CON_DISCONNECTED; ent->client->ps.persistant[PERS_TEAM] = TEAM_FREE; ent->client->ps.persistant[PERS_CLASS] = 0;//PC_NOCLASS; ent->client->sess.sessionTeam = TEAM_FREE; ent->client->sess.sessionClass = 0;//PC_NOCLASS; trap_SetConfigstring( CS_PLAYERS + clientNum, ""); CalculateRanks( qfalse ); if ( ent->r.svFlags & SVF_BOT ) { BotAIShutdownClient( clientNum ); } // kef -- if this guy contributed to any of our kills/deaths/weapons logs, clean 'em out G_ClearClientLog(clientNum); //also remove any initial data clientInitialStatus[clientNum].initialized = qfalse; //If the queen or action hero leaves, have to pick a new one... if ( g_pModAssimilation.integer != 0 ) { G_CheckReplaceQueen( clientNum ); } if ( g_pModActionHero.integer != 0 ) { G_CheckReplaceActionHero( clientNum ); } } int G_AddPlayerLanguage(char *name, int clientNum) { int i; for(i = 0; i < MAX_LANGUAGES; i++) { if(languageIndex[i] != NULL) { if(!Q_stricmp(Q_strlwr(name), languageIndex[i])) return i; } else { languageIndex[i] = G_NewString(name); return i; } } G_Printf(S_COLOR_RED "ERROR: MAX_RACES hit!\n"); trap_SendServerCommand(clientNum, S_COLOR_RED "ERROR: MAX_RACES hit!\n"); return 0; // we have hit the limit }