void BeginIntermission (edict_t *targ) { int i; edict_t *ent, *client; if (level.intermissiontime) return; // allready activated //ZOID if (deathmatch->value && ctf->value) CTFCalcScores(); //ZOID // game.autosaved = false; // respawn any dead clients // for (i=0 ; i<maxclients->value ; i++) // { // client = g_edicts + 1 + i; // if (!client->inuse) // continue; // if (client->health <= 0) // respawn(client); // } level.intermissiontime = level.time; level.changemap = targ->map; // if on same unit, return immediately if (!deathmatch->value && (targ->map && targ->map[0] != '*') ) { // go immediately to the next level level.exitintermission = 1; return; } level.exitintermission = 0; // find an intermission spot ent = G_Find (NULL, FOFS(classname), "info_player_intermission"); if (!ent) { // the map creator forgot to put in an intermission point... ent = G_Find (NULL, FOFS(classname), "info_player_start"); if (!ent) ent = G_Find (NULL, FOFS(classname), "info_player_deathmatch"); } else { // chose one of four spots i = rand() & 3; while (i--) { ent = G_Find (ent, FOFS(classname), "info_player_intermission"); if (!ent) // wrap around the list ent = G_Find (ent, FOFS(classname), "info_player_intermission"); } } VectorCopy (ent->s.origin, level.intermission_origin); VectorCopy (ent->s.angles, level.intermission_angle); // move all clients to the intermission point for (i=0 ; i<maxclients->value ; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; MoveClientToIntermission (client); } }
/* * called when a client has finished connecting, and is ready * to be placed into the game. This will happen every level load. */ void ClientBegin(edict_t *ent) { int i; if (!ent) { return; } ent->client = game.clients + (ent - g_edicts - 1); if (deathmatch->value) { ClientBeginDeathmatch(ent); return; } /* if there is already a body waiting for us (a loadgame), just take it, otherwise spawn one from scratch */ if (ent->inuse == true) { /* the client has cleared the client side viewangles upon connecting to the server, which is different than the state when the game is saved, so we need to compensate with deltaangles */ for (i = 0; i < 3; i++) { ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT( ent->client->ps.viewangles[i]); } } else { /* a spawn point will completely reinitialize the entity except for the persistant data that was initialized at ClientConnect() time */ G_InitEdict(ent); ent->classname = "player"; InitClientResp(ent->client); PutClientInServer(ent); } if (level.intermissiontime) { MoveClientToIntermission(ent); } else { /* send effect if in a multiplayer game */ if (game.maxclients > 1) { gi.WriteByte(svc_muzzleflash); gi.WriteShort(ent - g_edicts); gi.WriteByte(MZ_LOGIN); gi.multicast(ent->s.origin, MULTICAST_PVS); gi.bprintf(PRINT_HIGH, "%s entered the game\n", ent->client->pers.netname); } } /* make sure all view stuff is valid */ ClientEndServerFrame(ent); }
/* =========== 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 ============ */ void ClientSpawn(gentity_t *ent) { int index; vec3_t spawn_origin, spawn_angles; gclient_t *client; int i; clientPersistant_t saved; clientSession_t savedSess; int persistant[MAX_PERSISTANT]; gentity_t *spawnPoint; int flags; int savedPing; // char *savedAreaBits; int accuracy_hits, accuracy_shots; int eventSequence; char userinfo[MAX_INFO_STRING]; index = ent - g_entities; client = ent->client; // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { spawnPoint = SelectSpectatorSpawnPoint ( spawn_origin, spawn_angles); } else if (g_gametype.integer >= GT_CTF ) { // all base oriented team games use the CTF spawn points spawnPoint = SelectCTFSpawnPoint ( 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 ); } client->pers.teamState.state = TEAM_ACTIVE; // always clear the kamikaze flag ent->s.eFlags &= ~EF_KAMIKAZE; // toggle the teleport bit so the client knows to not lerp // and never clear the voted flag flags = ent->client->ps.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED); flags ^= EF_TELEPORT_BIT; // clear everything but the persistant data saved = client->pers; savedSess = client->sess; savedPing = client->ps.ping; // savedAreaBits = client->areabits; accuracy_hits = client->accuracy_hits; accuracy_shots = client->accuracy_shots; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { persistant[i] = client->ps.persistant[i]; } eventSequence = client->ps.eventSequence; memset (client, 0, sizeof(*client)); // bk FIXME: Com_Memset? client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; // client->areabits = savedAreaBits; client->accuracy_hits = accuracy_hits; client->accuracy_shots = accuracy_shots; client->lastkilled_client = -1; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { client->ps.persistant[i] = persistant[i]; } client->ps.eventSequence = eventSequence; // increment the spawncount so the client will detect the respawn client->ps.persistant[PERS_SPAWN_COUNT]++; client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam; client->airOutTime = level.time + 12000; trap_GetUserinfo( index, userinfo, sizeof(userinfo) ); // set max health client->pers.maxHealth = atoi( Info_ValueForKey( userinfo, "handicap" ) ); if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) { client->pers.maxHealth = 100; } // clear entity values client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; client->ps.eFlags = flags; ent->s.groundEntityNum = ENTITYNUM_NONE; ent->client = &level.clients[index]; ent->takedamage = qtrue; ent->inuse = qtrue; ent->classname = "player"; ent->r.contents = CONTENTS_BODY; ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags = 0; VectorCopy (playerMins, ent->r.mins); VectorCopy (playerMaxs, ent->r.maxs); client->ps.clientNum = index; client->ps.stats[STAT_WEAPONS] = ( 1 << WP_MACHINEGUN ); if ( g_gametype.integer == GT_TEAM ) { client->ps.ammo[WP_MACHINEGUN] = 50; } else { client->ps.ammo[WP_MACHINEGUN] = 100; } client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET ); client->ps.ammo[WP_GAUNTLET] = -1; client->ps.ammo[WP_GRAPPLING_HOOK] = -1; // health will count down towards max_health ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] + 25; 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 client->ps.pm_flags |= PMF_RESPAWNED; trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); SetClientViewAngle( ent, spawn_angles ); if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { } else { G_KillBox( ent ); trap_LinkEntity (ent); // force the base weapon up client->ps.weapon = WP_MACHINEGUN; client->ps.weaponstate = WEAPON_READY; } // don't allow full run speed for a bit client->ps.pm_flags |= PMF_TIME_KNOCKBACK; client->ps.pm_time = 100; client->respawnTime = level.time; client->inactivityTime = level.time + g_inactivity.integer * 1000; client->latched_buttons = 0; // set default animations client->ps.torsoAnim = TORSO_STAND; client->ps.legsAnim = LEGS_IDLE; if ( level.intermissiontime ) { MoveClientToIntermission( ent ); } else { // fire the targets of the spawn point G_UseTargets( spawnPoint, ent ); // select the highest weapon number available, after any // spawn given items have fired 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; } } } // 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 ); 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 ); }
/* =========== ClientSpawn Called every time a client is placed fresh in the world: after the first ClientBegin, and after each respawn Initializes all non-persistent parts of playerState ============ */ void ClientSpawn( gentity_t *ent, gentity_t *spawn, const vec3_t origin, const vec3_t angles ) { int index; vec3_t spawn_origin, spawn_angles; gclient_t *client; int i; clientPersistant_t saved; clientSession_t savedSess; qboolean savedNoclip, savedCliprcontents; int persistant[ MAX_PERSISTANT ]; gentity_t *spawnPoint = NULL; int flags; int savedPing; int teamLocal; int eventSequence; char userinfo[ MAX_INFO_STRING ]; vec3_t up = { 0.0f, 0.0f, 1.0f }; int maxAmmo, maxClips; weapon_t weapon; index = ent - g_entities; client = ent->client; teamLocal = client->pers.teamSelection; //if client is dead and following teammate, stop following before spawning if ( client->sess.spectatorClient != -1 ) { client->sess.spectatorClient = -1; client->sess.spectatorState = SPECTATOR_FREE; } // only start client if chosen a class and joined a team if ( client->pers.classSelection == PCL_NONE && teamLocal == TEAM_NONE ) { client->sess.spectatorState = SPECTATOR_FREE; } else if ( client->pers.classSelection == PCL_NONE ) { client->sess.spectatorState = SPECTATOR_LOCKED; } // if client is dead and following teammate, stop following before spawning if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) { G_StopFollowing( ent ); } if ( origin != NULL ) { VectorCopy( origin, spawn_origin ); } if ( angles != NULL ) { VectorCopy( angles, spawn_angles ); } // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if ( client->sess.spectatorState != SPECTATOR_NOT ) { if ( teamLocal == TEAM_NONE ) { spawnPoint = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles ); } else if ( teamLocal == TEAM_ALIENS ) { spawnPoint = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles ); } else if ( teamLocal == TEAM_HUMANS ) { spawnPoint = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles ); } } else { if ( spawn == NULL ) { G_Error( "ClientSpawn: spawn is NULL" ); } spawnPoint = spawn; if ( ent != spawn ) { //start spawn animation on spawnPoint G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue ); if ( spawnPoint->buildableTeam == TEAM_ALIENS ) { spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME; } else if ( spawnPoint->buildableTeam == TEAM_HUMANS ) { spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME; } } } // toggle the teleport bit so the client knows to not lerp flags = ( ent->client->ps.eFlags & EF_TELEPORT_BIT ) ^ EF_TELEPORT_BIT; G_UnlaggedClear( ent ); // clear everything but the persistent data saved = client->pers; savedSess = client->sess; savedPing = client->ps.ping; savedNoclip = client->noclip; savedCliprcontents = client->cliprcontents; for ( i = 0; i < MAX_PERSISTANT; i++ ) { persistant[ i ] = client->ps.persistant[ i ]; } eventSequence = client->ps.eventSequence; memset( client, 0, sizeof( *client ) ); client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; client->noclip = savedNoclip; client->cliprcontents = savedCliprcontents; for ( i = 0; i < MAX_PERSISTANT; i++ ) { client->ps.persistant[ i ] = persistant[ i ]; } client->ps.eventSequence = eventSequence; // increment the spawncount so the client will detect the respawn client->ps.persistant[ PERS_SPAWN_COUNT ]++; client->ps.persistant[ PERS_SPECSTATE ] = client->sess.spectatorState; client->airOutTime = level.time + 12000; trap_GetUserinfo( index, userinfo, sizeof( userinfo ) ); client->ps.eFlags = flags; //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection ); ent->s.groundEntityNum = ENTITYNUM_NONE; ent->client = &level.clients[ index ]; ent->takedamage = teamLocal != TEAM_NONE && client->sess.spectatorState == SPECTATOR_NOT; //qtrue; ent->classname = S_PLAYER_CLASSNAME; if ( client->noclip ) { client->cliprcontents = CONTENTS_BODY; } else { ent->r.contents = CONTENTS_BODY; } ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags &= FL_GODMODE | FL_NOTARGET; // calculate each client's acceleration ent->evaluateAcceleration = qtrue; client->ps.stats[ STAT_MISC ] = 0; client->ps.eFlags = flags; client->ps.clientNum = index; BG_ClassBoundingBox( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL ); if ( client->sess.spectatorState == SPECTATOR_NOT ) { client->ps.stats[ STAT_MAX_HEALTH ] = BG_Class( ent->client->pers.classSelection )->health; } else { client->ps.stats[ STAT_MAX_HEALTH ] = 100; } // clear entity values if ( ent->client->pers.classSelection == PCL_HUMAN ) { BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats ); weapon = client->pers.humanItemSelection; } else if ( client->sess.spectatorState == SPECTATOR_NOT ) { weapon = BG_Class( ent->client->pers.classSelection )->startWeapon; } else { weapon = WP_NONE; } maxAmmo = BG_Weapon( weapon )->maxAmmo; maxClips = BG_Weapon( weapon )->maxClips; client->ps.stats[ STAT_WEAPON ] = weapon; client->ps.ammo = maxAmmo; client->ps.clips = maxClips; // We just spawned, not changing weapons client->ps.persistant[ PERS_NEWWEAPON ] = 0; ent->client->ps.stats[ STAT_CLASS ] = ent->client->pers.classSelection; ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection; ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE; ent->client->ps.stats[ STAT_STATE ] = 0; VectorSet( ent->client->ps.grapplePoint, 0.0f, 0.0f, 1.0f ); // health will count down towards max_health ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25; //if evolving scale health if ( ent == spawn ) { ent->health *= ent->client->pers.evolveHealthFraction; client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction; } //clear the credits array for ( i = 0; i < MAX_CLIENTS; i++ ) { ent->credits[ i ] = 0; } client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX; G_SetOrigin( ent, spawn_origin ); VectorCopy( spawn_origin, client->ps.origin ); #define UP_VEL 150.0f #define F_VEL 50.0f //give aliens some spawn velocity if ( client->sess.spectatorState == SPECTATOR_NOT && client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) { if ( ent == spawn ) { //evolution particle system G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) ); } else { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); if ( spawnPoint->s.origin2[ 2 ] > 0.0f ) { vec3_t forward, dir; AngleVectors( spawn_angles, forward, NULL, NULL ); VectorScale( forward, F_VEL, forward ); VectorAdd( spawnPoint->s.origin2, forward, dir ); VectorNormalize( dir ); VectorScale( dir, UP_VEL, client->ps.velocity ); } G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 ); } } else if ( client->sess.spectatorState == SPECTATOR_NOT && client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); } // the respawned flag will be cleared after the attack and jump keys come up client->ps.pm_flags |= PMF_RESPAWNED; trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); G_SetClientViewAngle( ent, spawn_angles ); if ( client->sess.spectatorState == SPECTATOR_NOT ) { trap_LinkEntity( ent ); // force the base weapon up if ( client->pers.teamSelection == TEAM_HUMANS ) { G_ForceWeaponChange( ent, weapon ); } client->ps.weaponstate = WEAPON_READY; } // don't allow full run speed for a bit client->ps.pm_flags |= PMF_TIME_KNOCKBACK; client->ps.pm_time = 100; client->respawnTime = level.time; ent->nextRegenTime = level.time; client->inactivityTime = level.time + g_inactivity.integer * 1000; usercmdClearButtons( client->latched_buttons ); // set default animations client->ps.torsoAnim = TORSO_STAND; client->ps.legsAnim = LEGS_IDLE; if ( level.intermissiontime ) { MoveClientToIntermission( ent ); } else { // fire the targets of the spawn point if ( !spawn && spawnPoint ) { G_EventFireEntity( spawnPoint, ent, ON_SPAWN ); } // select the highest weapon number available, after any // spawn given items have fired client->ps.weapon = 1; for ( i = WP_NUM_WEAPONS - 1; i > 0; i-- ) { if ( BG_InventoryContainsWeapon( i, client->ps.stats ) ) { client->ps.weapon = i; break; } } } // 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 ( client->sess.spectatorState == SPECTATOR_NOT ) { ent->r.svFlags |= SVF_CLIENTS_IN_RANGE; ent->r.clientRadius = MAX( HELMET_RANGE, ALIENSENSE_RANGE ); BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); trap_LinkEntity( ent ); } // must do this here so the number of active clients is calculated CalculateRanks(); // run the presend to set anything else ClientEndFrame( ent ); // clear entity state values BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); client->pers.infoChangeTime = level.time; }
/* =========== 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 ============ */ void ClientSpawn(gentity_t *ent) { int index; vec3_t spawn_origin, spawn_angles; gclient_t *client; int i; clientPersistant_t saved; clientSession_t savedSess; int persistant[MAX_PERSISTANT]; gentity_t *spawnPoint; int flags; int savedPing; // char *savedAreaBits; int accuracy_hits, accuracy_shots; int eventSequence; // char userinfo[MAX_INFO_STRING]; forcedata_t savedForce; void *ghoul2save; int saveSaberNum = ENTITYNUM_NONE; int wDisable = 0; index = ent - g_entities; client = ent->client; if (client->ps.fd.forceDoInit) { //force a reread of force powers WP_InitForcePowers( ent ); client->ps.fd.forceDoInit = 0; } // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { spawnPoint = SelectSpectatorSpawnPoint ( spawn_origin, spawn_angles); } else if (g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTY) { // all base oriented team games use the CTF spawn points spawnPoint = SelectCTFSpawnPoint ( client->sess.sessionTeam, client->pers.teamState.state, spawn_origin, spawn_angles); } else if (g_gametype.integer == GT_SAGA) { spawnPoint = SelectSagaSpawnPoint ( 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 ); } client->pers.teamState.state = TEAM_ACTIVE; // toggle the teleport bit so the client knows to not lerp // and never clear the voted flag flags = ent->client->ps.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED); flags ^= EF_TELEPORT_BIT; // clear everything but the persistant data saved = client->pers; savedSess = client->sess; savedPing = client->ps.ping; // savedAreaBits = client->areabits; accuracy_hits = client->accuracy_hits; accuracy_shots = client->accuracy_shots; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { persistant[i] = client->ps.persistant[i]; } eventSequence = client->ps.eventSequence; savedForce = client->ps.fd; ghoul2save = client->ghoul2; saveSaberNum = client->ps.saberEntityNum; memset (client, 0, sizeof(*client)); // bk FIXME: Com_Memset? //rww - Don't wipe the ghoul2 instance or the animation data client->ghoul2 = ghoul2save; //or the saber ent num client->ps.saberEntityNum = saveSaberNum; client->ps.fd = savedForce; client->ps.duelIndex = ENTITYNUM_NONE; client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; // client->areabits = savedAreaBits; client->accuracy_hits = accuracy_hits; client->accuracy_shots = accuracy_shots; client->lastkilled_client = -1; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { client->ps.persistant[i] = persistant[i]; } client->ps.eventSequence = eventSequence; // increment the spawncount so the client will detect the respawn client->ps.persistant[PERS_SPAWN_COUNT]++; client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam; client->airOutTime = level.time + 12000; // trap_GetUserinfo( index, userinfo, sizeof(userinfo) ); // set max health client->pers.maxHealth = 100;//atoi( Info_ValueForKey( userinfo, "handicap" ) ); if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) { client->pers.maxHealth = 100; } // clear entity values client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; client->ps.eFlags = flags; ent->s.groundEntityNum = ENTITYNUM_NONE; ent->client = &level.clients[index]; ent->takedamage = qtrue; ent->inuse = qtrue; ent->classname = "player"; ent->r.contents = CONTENTS_BODY; ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags = 0; VectorCopy (playerMins, ent->r.mins); VectorCopy (playerMaxs, ent->r.maxs); client->ps.clientNum = index; //give default weapons client->ps.stats[STAT_WEAPONS] = ( 1 << WP_NONE ); if (g_gametype.integer == GT_HOLOCRON) { //always get free saber level 1 in holocron client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_SABER ); //these are precached in g_items, ClearRegisteredItems() } else { if (client->ps.fd.forcePowerLevel[FP_SABERATTACK]) { client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_SABER ); //these are precached in g_items, ClearRegisteredItems() } else { //if you don't have saber attack rank then you don't get a saber client->ps.stats[STAT_WEAPONS] |= (1 << WP_STUN_BATON); } } if (g_gametype.integer == GT_TOURNAMENT) { wDisable = g_duelWeaponDisable.integer; } else { wDisable = g_weaponDisable.integer; } if (!wDisable || !(wDisable & (1 << WP_BRYAR_PISTOL))) { client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL ); } else if (g_gametype.integer == GT_JEDIMASTER) { client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL ); } if (g_gametype.integer == GT_JEDIMASTER) { client->ps.stats[STAT_WEAPONS] &= ~(1 << WP_SABER); client->ps.stats[STAT_WEAPONS] |= (1 << WP_STUN_BATON); } if (client->ps.stats[STAT_WEAPONS] & (1 << WP_BRYAR_PISTOL)) { client->ps.weapon = WP_BRYAR_PISTOL; } else if (client->ps.stats[STAT_WEAPONS] & (1 << WP_SABER)) { client->ps.weapon = WP_SABER; } else { client->ps.weapon = WP_STUN_BATON; } /* client->ps.stats[STAT_HOLDABLE_ITEMS] |= ( 1 << HI_BINOCULARS ); client->ps.stats[STAT_HOLDABLE_ITEM] = BG_GetItemIndexByTag(HI_BINOCULARS, IT_HOLDABLE); */ client->ps.stats[STAT_HOLDABLE_ITEMS] = 0; client->ps.stats[STAT_HOLDABLE_ITEM] = 0; if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { client->ps.stats[STAT_WEAPONS] = 0; client->ps.stats[STAT_HOLDABLE_ITEMS] = 0; client->ps.stats[STAT_HOLDABLE_ITEM] = 0; } client->ps.ammo[AMMO_BLASTER] = 100; //ammoData[AMMO_BLASTER].max; //100 seems fair. // client->ps.ammo[AMMO_POWERCELL] = ammoData[AMMO_POWERCELL].max; // client->ps.ammo[AMMO_FORCE] = ammoData[AMMO_FORCE].max; // client->ps.ammo[AMMO_METAL_BOLTS] = ammoData[AMMO_METAL_BOLTS].max; // client->ps.ammo[AMMO_ROCKETS] = ammoData[AMMO_ROCKETS].max; /* client->ps.stats[STAT_WEAPONS] = ( 1 << WP_BRYAR_PISTOL); if ( g_gametype.integer == GT_TEAM ) { client->ps.ammo[WP_BRYAR_PISTOL] = 50; } else { client->ps.ammo[WP_BRYAR_PISTOL] = 100; } */ client->ps.rocketLockIndex = MAX_CLIENTS; client->ps.rocketLockTime = 0; //rww - Set here to initialize the circling seeker drone to off. //A quick note about this so I don't forget how it works again: //ps.genericEnemyIndex is kept in sync between the server and client. //When it gets set then an entitystate value of the same name gets //set along with an entitystate flag in the shared bg code. Which //is why a value needs to be both on the player state and entity state. //(it doesn't seem to just carry over the entitystate value automatically //because entity state value is derived from player state data or some //such) client->ps.genericEnemyIndex = -1; client->ps.isJediMaster = qfalse; client->ps.fallingToDeath = 0; //Do per-spawn force power initialization WP_SpawnInitForcePowers( ent ); // health will count down towards max_health ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH];// * 1.25; Boot - no extra 25 hp on start. // Start with a small amount of armor as well. client->ps.stats[STAT_ARMOR] = client->ps.stats[STAT_MAX_HEALTH] * 0.25; 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 client->ps.pm_flags |= PMF_RESPAWNED; trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); SetClientViewAngle( ent, spawn_angles ); if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { } else { G_KillBox( ent ); trap_LinkEntity (ent); // force the base weapon up client->ps.weapon = WP_BRYAR_PISTOL; client->ps.weaponstate = FIRST_WEAPON; } // don't allow full run speed for a bit client->ps.pm_flags |= PMF_TIME_KNOCKBACK; client->ps.pm_time = 100; client->respawnTime = level.time; client->inactivityTime = level.time + g_inactivity.integer * 1000; client->latched_buttons = 0; // set default animations client->ps.torsoAnim = WeaponReadyAnim[client->ps.weapon]; client->ps.legsAnim = WeaponReadyAnim[client->ps.weapon]; if ( level.intermissiontime ) { MoveClientToIntermission( ent ); } else { // fire the targets of the spawn point G_UseTargets( spawnPoint, ent ); // select the highest weapon number available, after any // spawn given items have fired 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; } } } // 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 ); VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); trap_LinkEntity( ent ); } if (g_spawnInvulnerability.integer) { ent->client->ps.eFlags |= EF_INVULNERABLE; ent->client->invulnerableTimer = level.time + g_spawnInvulnerability.integer; } // run the presend to set anything else ClientEndFrame( ent ); // clear entity state values BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); }
void BeginIntermission (edict_t *targ) { int i, n; edict_t *ent, *client; if (level.intermissiontime) return; // already activated //ZOID if (deathmatch->value && ctf->value) CTFCalcScores(); //ZOID game.autosaved = false; // respawn any dead clients for (i=0 ; i<maxclients->value ; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; if (client->health <= 0) respawn(client); } level.intermissiontime = level.time; level.changemap = targ->map; if (strstr(level.changemap, "*")) { if (coop->value) { for (i=0 ; i<maxclients->value ; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; // strip players of all keys between units for (n = 0; n < MAX_ITEMS; n++) { if (itemlist[n].flags & IT_KEY) client->client->pers.inventory[n] = 0; } } } } else { if (!deathmatch->value) { level.exitintermission = 1; // go immediately to the next level return; } } level.exitintermission = 0; // find an intermission spot ent = G_Find (NULL, FOFS(classname), "info_player_intermission"); if (!ent) { // the map creator forgot to put in an intermission point... ent = G_Find (NULL, FOFS(classname), "info_player_start"); if (!ent) ent = G_Find (NULL, FOFS(classname), "info_player_deathmatch"); } else { // chose one of four spots i = rand() & 3; while (i--) { ent = G_Find (ent, FOFS(classname), "info_player_intermission"); if (!ent) // wrap around the list ent = G_Find (ent, FOFS(classname), "info_player_intermission"); } } VectorCopy (ent->s.origin, level.intermission_origin); VectorCopy (ent->s.angles, level.intermission_angle); // Knightmare- letterboxing if (!strcmp(ent->classname, "info_player_intermission")) level.intermission_letterbox = (ent->spawnflags & 1); else level.intermission_letterbox = false; // move all clients to the intermission point for (i=0 ; i<maxclients->value ; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; MoveClientToIntermission (client); } }
/* =========== 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 ============ */ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles ) { int index; vec3_t spawn_origin, spawn_angles; gclient_t *client; int i; clientPersistant_t saved; clientSession_t savedSess; int persistant[ MAX_PERSISTANT ]; gentity_t *spawnPoint = NULL; int flags; int savedPing; int teamLocal; int eventSequence; char userinfo[ MAX_INFO_STRING ]; vec3_t up = { 0.0f, 0.0f, 1.0f }; int maxAmmo, maxClips; weapon_t weapon; index = ent - g_entities; client = ent->client; teamLocal = client->pers.teamSelection; //TA: only start client if chosen a class and joined a team if( client->pers.classSelection == PCL_NONE && teamLocal == PTE_NONE ) { client->sess.sessionTeam = TEAM_SPECTATOR; client->sess.spectatorState = SPECTATOR_FREE; } else if( client->pers.classSelection == PCL_NONE ) { client->sess.sessionTeam = TEAM_SPECTATOR; client->sess.spectatorState = SPECTATOR_LOCKED; } //if client is dead and following teammate, stop following before spawning if(ent->client->sess.spectatorClient!=-1) { ent->client->sess.spectatorClient = -1; ent->client->sess.spectatorState = SPECTATOR_FREE; } if( origin != NULL ) VectorCopy( origin, spawn_origin ); if( angles != NULL ) VectorCopy( angles, spawn_angles ); // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if( client->sess.sessionTeam == TEAM_SPECTATOR ) { if( teamLocal == PTE_NONE ) spawnPoint = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles ); else if( teamLocal == PTE_ALIENS ) spawnPoint = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles ); else if( teamLocal == PTE_HUMANS ) spawnPoint = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles ); } else { if( spawn == NULL ) { G_Error( "ClientSpawn: spawn is NULL\n" ); return; } spawnPoint = spawn; if( ent != spawn ) { //start spawn animation on spawnPoint G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue ); if( spawnPoint->biteam == PTE_ALIENS ) spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME; else if( spawnPoint->biteam == PTE_HUMANS ) spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME; } } client->pers.teamState.state = TEAM_ACTIVE; // toggle the teleport bit so the client knows to not lerp flags = ent->client->ps.eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED ); flags ^= EF_TELEPORT_BIT; G_UnlaggedClear( ent ); // 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 ]; eventSequence = client->ps.eventSequence; memset( client, 0, sizeof( *client ) ); client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; client->lastkilled_client = -1; for( i = 0; i < MAX_PERSISTANT; i++ ) client->ps.persistant[ i ] = persistant[ i ]; client->ps.eventSequence = eventSequence; // increment the spawncount so the client will detect the respawn client->ps.persistant[ PERS_SPAWN_COUNT ]++; client->ps.persistant[ PERS_TEAM ] = client->sess.sessionTeam; // restore really persistant things client->ps.persistant[ PERS_SCORE ] = client->pers.score; client->ps.persistant[ PERS_CREDIT ] = client->pers.credit; client->airOutTime = level.time + 12000; trap_GetUserinfo( index, userinfo, sizeof( userinfo ) ); client->ps.eFlags = flags; //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection ); ent->s.groundEntityNum = ENTITYNUM_NONE; ent->client = &level.clients[ index ]; ent->takedamage = qtrue; ent->inuse = qtrue; ent->classname = "player"; ent->r.contents = CONTENTS_BODY; ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags = 0; //TA: calculate each client's acceleration ent->evaluateAcceleration = qtrue; client->ps.stats[ STAT_WEAPONS ] = 0; client->ps.stats[ STAT_WEAPONS2 ] = 0; client->ps.stats[ STAT_SLOTS ] = 0; client->ps.eFlags = flags; client->ps.clientNum = index; BG_FindBBoxForClass( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL ); if( client->sess.sessionTeam != TEAM_SPECTATOR ) client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] = BG_FindHealthForClass( ent->client->pers.classSelection ); else client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] = 100; // clear entity values if( ent->client->pers.classSelection == PCL_HUMAN ) { BG_AddWeaponToInventory( WP_BLASTER, client->ps.stats ); BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats ); weapon = client->pers.humanItemSelection; } else if( client->sess.sessionTeam != TEAM_SPECTATOR ) weapon = BG_FindStartWeaponForClass( ent->client->pers.classSelection ); else weapon = WP_NONE; BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips ); BG_AddWeaponToInventory( weapon, client->ps.stats ); BG_PackAmmoArray( weapon, client->ps.ammo, client->ps.powerups, maxAmmo, maxClips ); ent->client->ps.stats[ STAT_PCLASS ] = ent->client->pers.classSelection; ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.teamSelection; ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE; ent->client->ps.stats[ STAT_STATE ] = 0; VectorSet( ent->client->ps.grapplePoint, 0.0f, 0.0f, 1.0f ); // health will count down towards max_health ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25; //if evolving scale health if( ent == spawn ) { ent->health *= ent->client->pers.evolveHealthFraction; client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction; } //clear the credits array for( i = 0; i < MAX_CLIENTS; i++ ) ent->credits[ i ] = 0; client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA; G_SetOrigin( ent, spawn_origin ); VectorCopy( spawn_origin, client->ps.origin ); #define UP_VEL 150.0f #define F_VEL 50.0f //give aliens some spawn velocity if( client->sess.sessionTeam != TEAM_SPECTATOR && client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) { if( ent == spawn ) { //evolution particle system G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) ); } else { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); if( spawnPoint->s.origin2[ 2 ] > 0.0f ) { vec3_t forward, dir; AngleVectors( spawn_angles, forward, NULL, NULL ); VectorScale( forward, F_VEL, forward ); VectorAdd( spawnPoint->s.origin2, forward, dir ); VectorNormalize( dir ); VectorScale( dir, UP_VEL, client->ps.velocity ); } G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 ); } } else if( client->sess.sessionTeam != TEAM_SPECTATOR && client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); } // the respawned flag will be cleared after the attack and jump keys come up client->ps.pm_flags |= PMF_RESPAWNED; trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); G_SetClientViewAngle( ent, spawn_angles ); if( !( client->sess.sessionTeam == TEAM_SPECTATOR ) ) { /*G_KillBox( ent );*/ //blame this if a newly spawned client gets stuck in another trap_LinkEntity( ent ); // force the base weapon up client->ps.weapon = WP_NONE; client->ps.weaponstate = WEAPON_READY; } // don't allow full run speed for a bit client->ps.pm_flags |= PMF_TIME_KNOCKBACK; client->ps.pm_time = 100; client->respawnTime = level.time; client->lastKillTime = level.time; client->inactivityTime = level.time + g_inactivity.integer * 1000; client->latched_buttons = 0; // set default animations client->ps.torsoAnim = TORSO_STAND; client->ps.legsAnim = LEGS_IDLE; if( level.intermissiontime ) MoveClientToIntermission( ent ); else { // fire the targets of the spawn point if( !spawn ) G_UseTargets( spawnPoint, ent ); // select the highest weapon number available, after any // spawn given items have fired client->ps.weapon = 1; for( i = WP_NUM_WEAPONS - 1; i > 0 ; i-- ) { if( BG_InventoryContainsWeapon( i, client->ps.stats ) ) { client->ps.weapon = i; break; } } } // 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( client->sess.sessionTeam != TEAM_SPECTATOR ) { BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); trap_LinkEntity( ent ); } //TA: must do this here so the number of active clients is calculated CalculateRanks( ); // run the presend to set anything else ClientEndFrame( ent ); // clear entity state values BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); }
/* =========== 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 ============ */ void ClientSpawn(gentity_t *ent) { int index; vec3_t spawn_origin, spawn_angles; gclient_t *client; int i; clientPersistant_t saved; clientSession_t savedSess; int persistant[MAX_PERSISTANT]; gentity_t *spawnPoint; int flags; int savedPing; // char *savedAreaBits; int accuracy_hits, accuracy_shots; int eventSequence; char userinfo[MAX_INFO_STRING]; index = ent - g_entities; client = ent->client; // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { spawnPoint = SelectSpectatorSpawnPoint ( 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 ); } client->pers.teamState.state = TEAM_ACTIVE; // always clear the kamikaze flag // ent->s.eFlags &= ~EF_KAMIKAZE; // toggle the teleport bit so the client knows to not lerp // and never clear the voted flag flags = ent->s.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED); flags ^= EF_TELEPORT_BIT; // clear everything but the persistant data saved = client->pers; savedSess = client->sess; savedPing = client->ps.ping; // savedAreaBits = client->areabits; accuracy_hits = client->accuracy_hits; accuracy_shots = client->accuracy_shots; Com_Memset (client, 0, sizeof(*client)); client->ps.stats[STAT_ATTACKERCLIENT] = -1; client->ps.stats[STAT_INFOCLIENT] = -1; client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; // client->areabits = savedAreaBits; client->accuracy_hits = accuracy_hits; client->accuracy_shots = accuracy_shots; client->lastkilled_client = -1; client->airOutTime = level.time + 12000; trap_GetUserinfo( index, userinfo, sizeof(userinfo) ); // set max health client->pers.maxHealth = atoi( Info_ValueForKey( userinfo, "handicap" ) ); if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) { client->pers.maxHealth = 100; } // clear entity values client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; ent->s.eFlags = flags; ent->s.groundEntityNum = ENTITYNUM_NONE; ent->client = &level.clients[index]; ent->takedamage = qtrue; ent->inuse = qtrue; ent->classname = "player"; ent->r.contents = CONTENTS_BODY; ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags = 0; VectorCopy (playerMins, ent->r.mins); VectorCopy (playerMaxs, ent->r.maxs); client->ps.clientNum = index; // health will count down towards max_health ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] + 25; 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 client->ps.pm_flags |= PMF_RESPAWNED; trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); SetClientViewAngle( ent, spawn_angles ); if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { } else { G_KillBox( 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; client->respawnTime = level.time; client->inactivityTime = level.time + g_inactivity.integer * 1000; client->latched_buttons = 0; if ( level.intermissiontime ) { MoveClientToIntermission( ent ); } else { // fire the targets of the spawn point G_UseTargets( spawnPoint, ent ); } // 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 ); 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 ); ent->s.modelindex = G_ModelIndex("models/human/coxswain.tik"); }
/** 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 */ void ClientSpawn(gentity_t *ent) { int index; vec3_t spawn_origin, spawn_angles; gclient_t *client; clientPersistant_t saved; clientSession_t savedSess; int persistant[MAX_PERSISTANT]; gentity_t *spawnPoint; gentity_t *tent; int flags; int eventSequence; char userinfo[MAX_INFO_STRING]; index = ent - g_entities; client = ent->client; // follow other players when eliminated if (!level.warmupTime && g_gametype.integer == GT_ELIMINATION && client->sess.sessionTeam != TEAM_SPECTATOR) { if (level.roundStarted) { client->sess.spectatorState = SPECTATOR_FREE; client->eliminated = qtrue; return; } else { client->sess.spectatorState = SPECTATOR_NOT; client->eliminated = qfalse; } } VectorClear(spawn_origin); // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if (client->sess.sessionTeam == TEAM_SPECTATOR) { SelectSpectatorSpawnPoint(spawn_origin, spawn_angles); } else if (g_gametype.integer == GT_DEFRAG) { spawnPoint = SelectDefragSpawnPoint(spawn_origin, spawn_angles); } else if (g_gametype.integer == GT_CTF) { spawnPoint = SelectCTFSpawnPoint(client->sess.sessionTeam, spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT)); } else if (client->pers.lastKiller) { spawnPoint = SelectSpawnPoint(client->pers.lastKiller->ps.origin, spawn_origin, spawn_angles, ent->r.svFlags & SVF_BOT); } else { spawnPoint = SelectSpawnPoint(client->ps.origin, spawn_origin, spawn_angles, ent->r.svFlags & SVF_BOT); } if (!spawnPoint) { G_Error("Cannot find a spawn point.\n"); return; } // toggle the teleport bit so the client knows to not lerp flags = ent->client->ps.eFlags & (EF_TELEPORT_BIT); flags ^= EF_TELEPORT_BIT; // unlagged - backward reconciliation #3 // we don't want players being backward-reconciled to the place they died G_ResetHistory( ent ); // and this is as good a time as any to clear the saved state ent->client->saved.leveltime = 0; // clear everything but the persistant data saved = client->pers; savedSess = client->sess; eventSequence = client->ps.eventSequence; Com_Memcpy(persistant, client->ps.persistant, sizeof persistant); Com_Memset(client, 0, sizeof(*client)); client->pers = saved; client->sess = savedSess; client->ps.eventSequence = eventSequence; Com_Memcpy(client->ps.persistant, persistant, sizeof client->ps.persistant); // increment the spawncount so the client will detect the respawn client->ps.persistant[PERS_SPAWN_COUNT]++; client->ps.persistant[PERS_TEAM] = client->sess.sessionTeam; client->airOutTime = level.time + 12000; trap_GetUserinfo(index, userinfo, sizeof(userinfo)); // set max health client->pers.maxHealth = atoi(Info_ValueForKey(userinfo, "handicap")); if (client->pers.maxHealth < 1 || client->pers.maxHealth > 100) { client->pers.maxHealth = 100; } // clear entity values client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; client->ps.eFlags = flags; ent->s.groundEntityNum = ENTITYNUM_NONE; ent->client = &level.clients[index]; ent->takedamage = qtrue; ent->inuse = qtrue; ent->classname = "player"; ent->r.contents = CONTENTS_BODY; ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags &= ~FL_NO_KNOCKBACK; ent->flags &= ~FL_FORCE_GESTURE; VectorCopy(playerMins, ent->r.mins); VectorCopy(playerMaxs, ent->r.maxs); client->ps.clientNum = index; ClientGiveWeapons(client); if (g_gametype.integer == GT_ELIMINATION) { client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] * 2; client->ps.stats[STAT_ARMOR] = client->ps.stats[STAT_MAX_HEALTH] * 1.5; } else { client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH] + 25; } ent->health = client->ps.stats[STAT_HEALTH]; 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 client->ps.pm_flags |= PMF_RESPAWNED; trap_GetUsercmd(client - level.clients, &ent->client->pers.cmd); SetClientViewAngle(ent, spawn_angles); // don't allow full run speed for a bit client->ps.pm_flags |= PMF_TIME_KNOCKBACK; client->ps.pm_time = 100; client->respawnTime = level.time; client->inactivityTime = level.time + g_inactivity.integer * 1000; client->latched_buttons = 0; // set default animations client->ps.torsoAnim = TORSO_STAND; client->ps.legsAnim = LEGS_IDLE; if (level.intermissiontime) { // move players to intermission MoveClientToIntermission(ent); } else if (ent->client->sess.sessionTeam != TEAM_SPECTATOR) { G_KillBox(ent); // fire the targets of the spawn point G_UseTargets(spawnPoint, ent); // positively link the client, even if the command times are weird VectorCopy(ent->client->ps.origin, ent->r.currentOrigin); tent = G_TempEntity(ent->client->ps.origin, EV_PLAYER_TELEPORT_IN); tent->s.clientNum = ent->s.clientNum; trap_LinkEntity (ent); } // run a client frame to drop exactly to the floor, // initialize animations and other things client->ps.commandTime = level.totalTime - 100; client->pers.cmd.serverTime = level.totalTime; ClientThink(ent-g_entities); // run the presend to set anything else, follow spectators wait // until all clients have been reconnected after map_restart if (ent->client->sess.spectatorState != SPECTATOR_FOLLOW) { ClientEndFrame(ent); } // clear entity state values BG_PlayerStateToEntityState(&client->ps, &ent->s, qtrue); }
void BeginIntermission(edict_t * targ) { int i , n; edict_t *ent, *client; if (level.intermissiontime) return; /* already activated */ game.autosaved = false; /* respawn any dead clients */ for (i = 0; i < maxclients->value; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; if (client->health <= 0) respawn(client); } level.intermissiontime = level.time; level.changemap = targ->map; if (strstr(level.changemap, "*")) { if (coop->value) { for (i = 0; i < maxclients->value; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; /* strip players of all keys between units */ for (n = 0; n < MAX_ITEMS; n++) { if (itemlist[n].flags & IT_KEY) client->client->pers.inventory[n] = 0; } } } } else { if (!deathmatch->value) { level.exitintermission = 1; /* go immediately to the * next level */ return; } } level.exitintermission = 0; /* find an intermission spot */ ent = G_Find(NULL, FOFS(classname), "info_player_intermission"); if (!ent) { /* the map creator forgot to put in an * intermission point... */ ent = G_Find(NULL, FOFS(classname), "info_player_start"); if (!ent) ent = G_Find(NULL, FOFS(classname), "info_player_deathmatch"); } else { /* chose one of four spots */ i = rand() & 3; while (i--) { ent = G_Find(ent, FOFS(classname), "info_player_intermission"); if (!ent) /* wrap around the list */ ent = G_Find(ent, FOFS(classname), "info_player_intermission"); } } VectorCopy(ent->s.origin, level.intermission_origin); VectorCopy(ent->s.angles, level.intermission_angle); /* move all clients to the intermission point */ for (i = 0; i < maxclients->value; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; MoveClientToIntermission(client); } }
/* =========== 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 ============ */ void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles ) { int index; vec3_t spawn_origin, spawn_angles; gclient_t *client; int i; clientPersistant_t saved; clientSession_t savedSess; int persistant[ MAX_PERSISTANT ]; gentity_t *spawnPoint = NULL, *event; int flags; int savedPing; int teamLocal; int eventSequence; char userinfo[ MAX_INFO_STRING ]; vec3_t up = { 0.0f, 0.0f, 1.0f }, implant_dir, implant_angles, spawnPoint_velocity; int maxAmmo, maxClips; weapon_t weapon; qboolean fromImplant = qfalse, hatchingFailed = qfalse; index = ent - g_entities; client = ent->client; teamLocal = client->pers.teamSelection; //if client is dead and following teammate, stop following before spawning if( client->sess.spectatorClient != -1 ) { client->sess.spectatorClient = -1; client->sess.spectatorState = SPECTATOR_FREE; } // only start client if chosen a class and joined a team if( client->pers.classSelection == PCL_NONE && teamLocal == TEAM_NONE ) client->sess.spectatorState = SPECTATOR_FREE; else if( client->pers.classSelection == PCL_NONE ) client->sess.spectatorState = SPECTATOR_LOCKED; // if client is dead and following teammate, stop following before spawning if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) G_StopFollowing( ent ); if( origin != NULL ) VectorCopy( origin, spawn_origin ); if( angles != NULL ) VectorCopy( angles, spawn_angles ); // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client if( client->sess.spectatorState != SPECTATOR_NOT ) { if( teamLocal == TEAM_NONE ) spawnPoint = G_SelectSpectatorSpawnPoint( spawn_origin, spawn_angles ); else if( teamLocal == TEAM_ALIENS ) spawnPoint = G_SelectAlienLockSpawnPoint( spawn_origin, spawn_angles ); else if( teamLocal == TEAM_HUMANS ) spawnPoint = G_SelectHumanLockSpawnPoint( spawn_origin, spawn_angles ); } else { if( spawn == NULL ) { G_Error( "ClientSpawn: spawn is NULL\n" ); return; } spawnPoint = spawn; if( ent != spawn ) { if( !spawnPoint->client ) //might be a human { //start spawn animation on spawnPoint G_SetBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue ); if( spawnPoint->buildableTeam == TEAM_ALIENS ) spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME; else if( spawnPoint->buildableTeam == TEAM_HUMANS ) spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME; } else { qboolean crouch; int i; float zoffs = 0.0f; trace_t tr; vec3_t neworigin, mins, maxs; fromImplant = qtrue; //spawning from a human // move the origin a bit on the Z axis so the aliens jumps out of the chest, not knees // also prevents grangers from getting stuck in ceilings and floors crouch = spawnPoint->client->ps.pm_flags & PMF_DUCKED; switch( client->pers.classSelection ) { case PCL_ALIEN_BUILDER0: if( !crouch ) zoffs = 19.0f; else zoffs = -4.0f; break; case PCL_ALIEN_BUILDER0_UPG: if( !crouch ) zoffs = 16.5f; else zoffs = -4.0f; break; case PCL_ALIEN_LEVEL0: if( !crouch ) zoffs = 15.0f; else zoffs = -9.1f; break; } spawn_origin[ 2 ] += zoffs; // check if the spot would block BG_ClassBoundingBox( client->pers.classSelection, mins, maxs, NULL, NULL, NULL ); trap_Trace( &tr, spawn_origin, mins, maxs, spawn_origin, spawnPoint->s.number, MASK_PLAYERSOLID ); // try to unblock the player if( tr.startsolid ) { Com_Printf("DEBUG: player is stuck!\n"); for( i = 0; i < 16*2; i++ ) { float a, r; VectorCopy( spawn_origin, neworigin ); a = (float)i / 16.0f * 2.0f * M_PI; #define fmod(a,n) ((a)-(n)*floor((a)/(n))) r = ( i < 16 ? 5.5f : 11.0f ) * 1.0f / cos( fmod( a+0.25f*M_PI, 0.5f*M_PI ) - 0.25f*M_PI ); neworigin[ 0 ] += cos( a ) * r; neworigin[ 1 ] += sin( a ) * r; trap_Trace( &tr, neworigin, mins, maxs, neworigin, spawnPoint->s.number, MASK_PLAYERSOLID ); if( !tr.startsolid ) { Com_Printf("DEBUG: player position fixed at iteration %i\n",i); VectorCopy( neworigin, spawn_origin ); break; } } } //reward the player that implanted this one if( spawnPoint->client->impregnatedBy >= 0 ) { gentity_t *granger; granger = &g_entities[ spawnPoint->client->impregnatedBy ]; G_AddCreditToClient( granger->client, ALIEN_IMPREGNATION_REWARD, qtrue ); AddScore( granger, ALIEN_IMPREGNATION_REWARD_SCORE ); } // kill the human, set up angles and velocity for the new alien if( !BG_InventoryContainsUpgrade( UP_BATTLESUIT, spawnPoint->client->ps.stats ) //humans without battlesuits always die || spawnPoint->client->ps.stats[ STAT_HEALTH ] < ALIEN_HATCHING_MAX_BATTLESUIT_HEALTH ) //battlesuits survive if high hp { //save viewangles and spawn velocity for velocity calculation VectorCopy( spawnPoint->client->ps.viewangles, implant_angles ); AngleVectors( implant_angles, implant_dir, NULL, NULL ); VectorCopy( spawnPoint->client->ps.velocity, spawnPoint_velocity ); //fire a nice chest exploding effect event = G_TempEntity( spawnPoint->s.pos.trBase, EV_ALIEN_HATCH ); VectorCopy( implant_dir, event->s.angles ); //kill the player G_Damage( spawnPoint, NULL, ent, NULL, NULL, spawnPoint->client->ps.stats[ STAT_HEALTH ], DAMAGE_NO_ARMOR, MOD_ALIEN_HATCH ); } else //human survives { //clear impregnation so the human won't explode again spawnPoint->client->isImpregnated = qfalse; spawnPoint->client->isImplantMature = qfalse; //make a sound event = G_TempEntity( spawnPoint->s.pos.trBase, EV_ALIEN_HATCH_FAILURE ); //damage the human G_Damage( spawnPoint, NULL, ent, NULL, NULL, ALIEN_FAILED_HATCH_DAMAGE, DAMAGE_NO_ARMOR, MOD_ALIEN_HATCH ); //kill the newly spawned alien VectorCopy( spawnPoint->client->ps.viewangles, implant_angles ); implant_dir[0] = 0.0f; implant_dir[1] = 0.0f; implant_dir[2] = 0.0f; hatchingFailed = qtrue; } } } } // toggle the teleport bit so the client knows to not lerp flags = ( ent->client->ps.eFlags & EF_TELEPORT_BIT ) ^ EF_TELEPORT_BIT; G_UnlaggedClear( ent ); // 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 ]; eventSequence = client->ps.eventSequence; memset( client, 0, sizeof( *client ) ); client->pers = saved; client->sess = savedSess; client->ps.ping = savedPing; client->lastkilled_client = -1; for( i = 0; i < MAX_PERSISTANT; i++ ) client->ps.persistant[ i ] = persistant[ i ]; client->ps.eventSequence = eventSequence; // increment the spawncount so the client will detect the respawn client->ps.persistant[ PERS_SPAWN_COUNT ]++; client->ps.persistant[ PERS_SPECSTATE ] = client->sess.spectatorState; client->airOutTime = level.time + 12000; trap_GetUserinfo( index, userinfo, sizeof( userinfo ) ); client->ps.eFlags = flags; //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection ); ent->s.groundEntityNum = ENTITYNUM_NONE; ent->client = &level.clients[ index ]; ent->takedamage = qtrue; ent->inuse = qtrue; ent->classname = "player"; ent->r.contents = CONTENTS_BODY; ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags = 0; // calculate each client's acceleration ent->evaluateAcceleration = qtrue; client->ps.stats[ STAT_MISC ] = 0; client->buildTimer = 0; client->ps.eFlags = flags; client->ps.clientNum = index; BG_ClassBoundingBox( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL ); if( client->sess.spectatorState == SPECTATOR_NOT ) client->ps.stats[ STAT_MAX_HEALTH ] = BG_Class( ent->client->pers.classSelection )->health; else client->ps.stats[ STAT_MAX_HEALTH ] = 100; // clear entity values if( ent->client->pers.classSelection == PCL_HUMAN ) { BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats ); weapon = client->pers.humanItemSelection; } else if( client->sess.spectatorState == SPECTATOR_NOT ) weapon = BG_Class( ent->client->pers.classSelection )->startWeapon; else weapon = WP_NONE; maxAmmo = BG_Weapon( weapon )->maxAmmo; maxClips = BG_Weapon( weapon )->maxClips; client->ps.stats[ STAT_WEAPON ] = weapon; client->ps.ammo = maxAmmo; client->ps.clips = maxClips; // We just spawned, not changing weapons client->ps.persistant[ PERS_NEWWEAPON ] = 0; ent->client->ps.stats[ STAT_CLASS ] = ent->client->pers.classSelection; ent->client->ps.stats[ STAT_TEAM ] = ent->client->pers.teamSelection; ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE; ent->client->ps.stats[ STAT_STATE ] = 0; VectorSet( ent->client->ps.grapplePoint, 0.0f, 0.0f, 1.0f ); // health will count down towards max_health ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25; //if evolving scale health if( ent == spawn ) { ent->health *= ent->client->pers.evolveHealthFraction; client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction; } //clear the credits array for( i = 0; i < MAX_CLIENTS; i++ ) ent->credits[ i ] = 0; client->ps.stats[ STAT_STAMINA ] = STAMINA_MAX; //never impregnated after respawning client->isImpregnated = qfalse; client->isImplantMature = qfalse; G_SetOrigin( ent, spawn_origin ); VectorCopy( spawn_origin, client->ps.origin ); #define UP_VEL 150.0f #define F_VEL 50.0f //give aliens some spawn velocity if( client->sess.spectatorState == SPECTATOR_NOT && client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS ) { if( ent == spawn ) { //evolution particle system G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) ); } else if( !fromImplant ) //regular egg { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); if( spawnPoint->s.origin2[ 2 ] > 0.0f ) { vec3_t forward, dir; AngleVectors( spawn_angles, forward, NULL, NULL ); VectorScale( forward, F_VEL, forward ); VectorAdd( spawnPoint->s.origin2, forward, dir ); VectorNormalize( dir ); VectorScale( dir, UP_VEL, client->ps.velocity ); } G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 ); } else //implanted egg { VectorCopy( implant_angles, spawn_angles ); VectorScale( implant_dir, ALIEN_HATCHING_VELOCITY, client->ps.velocity ); VectorAdd( client->ps.velocity, spawnPoint_velocity, client->ps.velocity ); } } else if( client->sess.spectatorState == SPECTATOR_NOT && client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) { spawn_angles[ YAW ] += 180.0f; AngleNormalize360( spawn_angles[ YAW ] ); } // the respawned flag will be cleared after the attack and jump keys come up client->ps.pm_flags |= PMF_RESPAWNED; trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); G_SetClientViewAngle( ent, spawn_angles ); if( client->sess.spectatorState == SPECTATOR_NOT ) { trap_LinkEntity( ent ); // force the base weapon up if( client->pers.teamSelection == TEAM_HUMANS ) G_ForceWeaponChange( ent, weapon ); client->ps.weaponstate = WEAPON_READY; } // don't allow full run speed for a bit client->ps.pm_flags |= PMF_TIME_KNOCKBACK; client->ps.pm_time = 100; client->respawnTime = level.time; ent->nextRegenTime = level.time; client->inactivityTime = level.time + g_inactivity.integer * 1000; client->latched_buttons = 0; // set default animations client->ps.torsoAnim = TORSO_STAND; client->ps.legsAnim = LEGS_IDLE; if( level.intermissiontime ) MoveClientToIntermission( ent ); else { // fire the targets of the spawn point if( !spawn ) G_UseTargets( spawnPoint, ent ); // select the highest weapon number available, after any // spawn given items have fired client->ps.weapon = 1; for( i = WP_NUM_WEAPONS - 1; i > 0 ; i-- ) { if( BG_InventoryContainsWeapon( i, client->ps.stats ) ) { client->ps.weapon = i; break; } } } client->lastRantBombTime = level.time; // 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( client->sess.spectatorState == SPECTATOR_NOT ) { BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); trap_LinkEntity( ent ); } // must do this here so the number of active clients is calculated CalculateRanks( ); // run the presend to set anything else ClientEndFrame( ent ); // clear entity state values BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); // kill him instantly after respawning if hatching failed if( fromImplant && hatchingFailed ) { VectorCopy( spawnPoint->client->ps.velocity, client->ps.velocity ); client->ps.stats[ STAT_HEALTH ] = ent->health = 0; player_die( ent, NULL, spawnPoint, 0, MOD_ALIEN_HATCH_FAILED ); } }