void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) { gentity_t *tent; qboolean noAngles; noAngles = (angles[0] > 999999.0); // use temp events at source and destination to prevent the effect // from getting dropped by a second player event if ( player->client->sess.sessionTeam != TEAM_SPECTATOR && player->client->ps.pm_type != PM_SPECTATOR) { tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); tent->s.clientNum = player->s.clientNum; tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN ); tent->s.clientNum = player->s.clientNum; } // unlink to make sure it can't possibly interfere with G_KillBox trap_UnlinkEntity (player); VectorCopy ( origin, player->client->ps.origin ); player->client->ps.origin[2] += 1; if (!noAngles) { // spit the player out AngleVectors( angles, player->client->ps.velocity, NULL, NULL ); VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity ); player->client->ps.pm_time = 160; // hold time player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; // set angles SetClientViewAngle(player, angles); } // toggle the teleport bit so the client knows to not lerp player->client->ps.eFlags ^= EF_TELEPORT_BIT; //unlagged - backward reconciliation #3 // we don't want players being backward-reconciled back through teleporters G_ResetHistory( player ); //unlagged - backward reconciliation #3 // kill anything at the destination if ( player->client->sess.sessionTeam != TEAM_SPECTATOR && player->client->ps.pm_type != PM_SPECTATOR ) { G_KillBox (player); } // save results of pmove BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue ); // use the precise origin for linking VectorCopy( player->client->ps.origin, player->r.currentOrigin ); if ( player->client->sess.sessionTeam != TEAM_SPECTATOR && player->client->ps.pm_type != PM_SPECTATOR ) { trap_LinkEntity (player); } }
/* =========== PlayerSpawn Called every time a player is placed fresh in the world: after the first PlayerBegin, and after each respawn Initializes all non-persistant parts of playerState ============ */ void PlayerSpawn(gentity_t *ent) { int index; vec3_t spawn_origin, spawn_angles; gplayer_t *player; int i; playerPersistant_t saved; playerSession_t savedSess; int persistant[MAX_PERSISTANT]; gentity_t *spawnPoint; gentity_t *tent; int flags; int savedPing; // char *savedAreaBits; int accuracy_hits, accuracy_shots; int eventSequence; int startWeapon, startAmmo; index = ent - g_entities; player = ent->player; VectorClear(spawn_origin); // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this player if ( player->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 ( player->sess.sessionTeam, player->pers.teamState.state, spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT)); } else { // the first spawn should be at a good looking spot if ( player->pers.initialSpawn && player->pers.localClient ) { spawnPoint = SelectInitialSpawnPoint(spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT)); } else { // don't spawn near existing origin if possible spawnPoint = SelectSpawnPoint ( player->ps.origin, spawn_origin, spawn_angles, !!(ent->r.svFlags & SVF_BOT)); } } player->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->player->ps.eFlags & (EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED); flags ^= EF_TELEPORT_BIT; // clear everything but the persistant data saved = player->pers; savedSess = player->sess; savedPing = player->ps.ping; // savedAreaBits = player->areabits; accuracy_hits = player->accuracy_hits; accuracy_shots = player->accuracy_shots; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { persistant[i] = player->ps.persistant[i]; } eventSequence = player->ps.eventSequence; Com_Memset (player, 0, sizeof(*player)); player->pers = saved; player->sess = savedSess; player->ps.ping = savedPing; // player->areabits = savedAreaBits; player->accuracy_hits = accuracy_hits; player->accuracy_shots = accuracy_shots; player->lastkilled_player = -1; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { player->ps.persistant[i] = persistant[i]; } player->ps.eventSequence = eventSequence; // increment the spawncount so the client will detect the respawn player->ps.persistant[PERS_SPAWN_COUNT]++; player->ps.persistant[PERS_TEAM] = player->sess.sessionTeam; player->airOutTime = level.time + 12000; // set max health player->pers.maxHealth = PlayerHandicap( player ); // clear entity values player->ps.stats[STAT_MAX_HEALTH] = player->pers.maxHealth; player->ps.eFlags = flags; player->ps.contents = CONTENTS_BODY; player->ps.collisionType = ( g_playerCapsule.integer == 1 ) ? CT_CAPSULE : CT_AABB; ent->s.groundEntityNum = ENTITYNUM_NONE; ent->player = &level.players[index]; ent->takedamage = qtrue; ent->inuse = qtrue; ent->classname = "player"; ent->clipmask = MASK_PLAYERSOLID; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags = 0; ent->player->headless = qfalse; VectorCopy (playerMins, player->ps.mins); VectorCopy (playerMaxs, player->ps.maxs); player->ps.playerNum = index; if ( g_instaGib.integer == 1 ) { startWeapon = WP_RAILGUN; startAmmo = 50; } else if ( g_instaGib.integer == 2 ) { startWeapon = WP_ROCKET_LAUNCHER; startAmmo = 50; } else { startWeapon = WP_MACHINEGUN; startAmmo = 100; } player->ps.stats[STAT_WEAPONS] = ( 1 << startWeapon ); player->ps.ammo[startWeapon] = startAmmo; player->ps.stats[STAT_WEAPONS] |= ( 1 << WP_GAUNTLET ); player->ps.ammo[WP_GAUNTLET] = -1; player->ps.ammo[WP_GRAPPLING_HOOK] = -1; // health will count down towards max_health ent->health = player->ps.stats[STAT_HEALTH] = player->ps.stats[STAT_MAX_HEALTH] = MAX_HEALTH; G_SetOrigin( ent, spawn_origin ); VectorCopy( spawn_origin, player->ps.origin ); // the respawned flag will be cleared after the attack and jump keys come up player->ps.pm_flags |= PMF_RESPAWNED; trap_GetUsercmd( player - level.players, &ent->player->pers.cmd ); SetPlayerViewAngle( ent, spawn_angles ); // don't allow full run speed for a bit player->ps.pm_flags |= PMF_TIME_KNOCKBACK; player->ps.pm_time = 100; player->respawnTime = level.time; player->inactivityTime = level.time + g_inactivity.integer * 1000; player->latched_buttons = 0; // set default animations player->ps.torsoAnim = TORSO_STAND; player->ps.legsAnim = LEGS_IDLE; if (!level.intermissiontime) { if (ent->player->sess.sessionTeam != TEAM_SPECTATOR) { G_KillBox(ent); // force the base weapon up player->ps.weapon = startWeapon; player->ps.weaponstate = WEAPON_READY; // fire the targets of the spawn point G_UseTargets(spawnPoint, ent); // select the highest weapon number available, after any spawn given items have fired player->ps.weapon = 1; for (i = WP_NUM_WEAPONS - 1 ; i > 0 ; i--) { if (player->ps.stats[STAT_WEAPONS] & (1 << i)) { player->ps.weapon = i; break; } } // positively link the player, even if the command times are weird VectorCopy(ent->player->ps.origin, ent->r.currentOrigin); tent = G_TempEntity(ent->player->ps.origin, EV_PLAYER_TELEPORT_IN); tent->s.playerNum = ent->s.playerNum; trap_LinkEntity (ent); } } else { // move players to intermission MovePlayerToIntermission(ent); } // run a player frame to drop exactly to the floor, // initialize animations and other things player->ps.commandTime = level.time - 100; ent->player->pers.cmd.serverTime = level.time; PlayerThink( ent-g_entities ); // run the presend to set anything else, follow spectators wait // until all players have been reconnected after map_restart if ( ent->player->sess.spectatorState != SPECTATOR_FOLLOW ) { PlayerEndFrame( ent ); } // clear entity state values BG_PlayerStateToEntityState( &player->ps, &ent->s, qtrue ); // we don't want players being backward-reconciled to the place they died G_ResetHistory( ent ); }
void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles, qboolean spit ) { gentity_t *tent; // use temp events at source and destination to prevent the effect // from getting dropped by a second player event /*freeze if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) { freeze*/ if ( (g_gametype.integer == GT_FREEZE && !is_spectator( player->client )) || (g_gametype.integer != GT_FREEZE && player->client->sess.sessionTeam != TEAM_SPECTATOR) ) { //freeze tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); tent->s.clientNum = player->s.clientNum; tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN ); tent->s.clientNum = player->s.clientNum; } // unlink to make sure it can't possibly interfere with G_KillBox //player->relink = 0; trap_UnlinkEntity (player); VectorCopy ( origin, player->client->ps.origin ); player->client->ps.origin[2] += 1; // spit the player out if (spit == qtrue) { AngleVectors( angles, player->client->ps.velocity, NULL, NULL ); VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity ); player->client->ps.pm_time = 160; // hold time player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; } // toggle the teleport bit so the client knows to not lerp player->client->ps.eFlags ^= EF_TELEPORT_BIT; //unlagged - backward reconciliation #3 // we don't want players being backward-reconciled back through teleporters G_ResetHistory( player ); //unlagged - backward reconciliation #3 // set angles if (player->client->pers.fixedTeleporterAngles == qfalse) SetClientViewAngle( player, angles ); // kill anything at the destination /*freeze if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) { freeze*/ if ( (g_gametype.integer == GT_FREEZE && !is_spectator( player->client )) || (g_gametype.integer != GT_FREEZE && player->client->sess.sessionTeam != TEAM_SPECTATOR) ) { //freeze G_KillBox (player); } // save results of pmove BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue ); // use the precise origin for linking VectorCopy( player->client->ps.origin, player->r.currentOrigin ); /*freeze if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) { freeze*/ if ( (g_gametype.integer == GT_FREEZE && !is_spectator( player->client )) || (g_gametype.integer != GT_FREEZE && player->client->sess.sessionTeam != TEAM_SPECTATOR) ) { //freeze trap_LinkEntity (player); } }
void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles ) { gentity_t *tent; // use temp events at source and destination to prevent the effect // from getting dropped by a second player event #ifndef SMOKINGUNS if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) { #else if ( player->client->sess.sessionTeam < TEAM_SPECTATOR ) { #endif tent = G_TempEntity( player->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); tent->s.clientNum = player->s.clientNum; tent = G_TempEntity( origin, EV_PLAYER_TELEPORT_IN ); tent->s.clientNum = player->s.clientNum; } // unlink to make sure it can't possibly interfere with G_KillBox trap_UnlinkEntity (player); VectorCopy ( origin, player->client->ps.origin ); player->client->ps.origin[2] += 1; // spit the player out AngleVectors( angles, player->client->ps.velocity, NULL, NULL ); VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity ); player->client->ps.pm_time = 160; // hold time player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; // toggle the teleport bit so the client knows to not lerp player->client->ps.eFlags ^= EF_TELEPORT_BIT; #ifdef SMOKINGUNS //unlagged - backward reconciliation #3 // we don't want players being backward-reconciled back through teleporters G_ResetHistory( player ); //unlagged - backward reconciliation #3 #endif // set angles SetClientViewAngle( player, angles ); // kill anything at the destination #ifndef SMOKINGUNS if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) { #else if ( player->client->sess.sessionTeam < TEAM_SPECTATOR ) { #endif G_KillBox (player); #ifdef SMOKINGUNS // Tequila comment: G_KillBox will set dontTelefrag as needed if (player->client->dontTelefrag) { #ifdef DEBUG_TELEFRAG_CASE G_Printf(S_COLOR_MAGENTA "TeleportPlayer: Telefrag case delayed at respawn for %s...\n",player->client->pers.netname); #endif trap_SendServerCommand( player->s.clientNum, va("print \"Go away %s\n\"",player->client->pers.netname) ); // So we will link the player entity later with normal content player->r.contents = 0; } #endif } // save results of pmove BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue ); // use the precise origin for linking VectorCopy( player->client->ps.origin, player->r.currentOrigin ); #ifndef SMOKINGUNS if ( player->client->sess.sessionTeam != TEAM_SPECTATOR ) { #else if ( player->client->sess.sessionTeam < TEAM_SPECTATOR ) { #endif trap_LinkEntity (player); } } /*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16) Point teleporters at these. Now that we don't have teleport destination pads, this is just an info_notnull */ void SP_misc_teleporter_dest( gentity_t *ent ) { } #ifdef SMOKINGUNS // Imported from WoP OpenSource project //=========================================================== /*QUAKED misc_externalmodel (1 0 0) (-16 -16 -16) (16 16 16) "model" arbitrary .md3 file to display "wait" time in seconds before the animation begins */ #define ANIMATION_THINKTIME 50 static void Think_AnimationExternalmodel( gentity_t *ent ) { if(ent->animationEnd>ent->animationStart) { ent->s.frame = (int)((float)level.time*0.001f*ent->animationFPS)%(ent->animationEnd-ent->animationStart); ent->s.frame += ent->animationStart; ent->nextthink = level.time + ANIMATION_THINKTIME; } } void SP_misc_externalmodel( gentity_t *ent ) { ent->s.modelindex = G_ModelIndex( ent->model ); // VectorSet (ent->mins, -16, -16, -16); // VectorSet (ent->maxs, 16, 16, 16); trap_LinkEntity (ent); G_SetOrigin( ent, ent->s.origin ); VectorCopy( ent->s.angles, ent->s.apos.trBase ); if(ent->animationEnd>ent->animationStart && ent->animationFPS>0.0f) { ent->think = Think_AnimationExternalmodel; ent->nextthink = level.time + ANIMATION_THINKTIME; // Tequila: Support for new entity features if (ent->wait>0.0f) ent->nextthink += (int)(ent->wait*1000); } } #endif //=========================================================== /*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16) "model" arbitrary .md3 file to display */ void SP_misc_model( gentity_t *ent ) { #if 0 ent->s.modelindex = G_ModelIndex( ent->model ); VectorSet (ent->mins, -16, -16, -16); VectorSet (ent->maxs, 16, 16, 16); trap_LinkEntity (ent); G_SetOrigin( ent, ent->s.origin ); VectorCopy( ent->s.angles, ent->s.apos.trBase ); #else G_FreeEntity( ent ); #endif } //=========================================================== void locateCamera( gentity_t *ent ) { vec3_t dir; gentity_t *target; gentity_t *owner; owner = G_PickTarget( ent->target ); if ( !owner ) { G_Printf( "Couldn't find target for misc_portal_surface\n" ); G_FreeEntity( ent ); return; } ent->r.ownerNum = owner->s.number; // frame holds the rotate speed if ( owner->spawnflags & 1 ) { ent->s.frame = 25; } else if ( owner->spawnflags & 2 ) { ent->s.frame = 75; } #ifndef SMOKINGUNS // swing camera ? if ( owner->spawnflags & 4 ) { // set to 0 for no rotation at all ent->s.powerups = 0; } else { ent->s.powerups = 1; } #else // set to 0 for no rotation at all ent->s.powerups = 1; #endif // clientNum holds the rotate offset ent->s.clientNum = owner->s.clientNum; VectorCopy( owner->s.origin, ent->s.origin2 ); // see if the portal_camera has a target target = G_PickTarget( owner->target ); if ( target ) { VectorSubtract( target->s.origin, owner->s.origin, dir ); VectorNormalize( dir ); } else { G_SetMovedir( owner->s.angles, dir ); } ent->s.eventParm = DirToByte( dir ); }
/** 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); }