/* * G_TeleportPlayer */ void G_TeleportPlayer( edict_t *player, edict_t *dest ) { int i; vec3_t velocity; mat3_t axis; float speed; gclient_t *client = player->r.client; if( !dest ) { return; } if( !client ) { return; } // draw the teleport entering effect G_TeleportEffect( player, false ); // // teleport the player // // from racesow - use old pmove velocity VectorCopy( client->old_pmove.velocity, velocity ); velocity[2] = 0; // ignore vertical velocity speed = VectorLengthFast( velocity ); AnglesToAxis( dest->s.angles, axis ); VectorScale( &axis[AXIS_FORWARD], speed, client->ps.pmove.velocity ); VectorCopy( dest->s.angles, client->ps.viewangles ); VectorCopy( dest->s.origin, client->ps.pmove.origin ); // set the delta angle for ( i = 0; i < 3; i++ ) client->ps.pmove.delta_angles[i] = ANGLE2SHORT( client->ps.viewangles[i] ) - client->ucmd.angles[i]; client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT; client->ps.pmove.pm_time = 1; // force the minimum no control delay player->s.teleported = true; // update the entity from the pmove VectorCopy( client->ps.viewangles, player->s.angles ); VectorCopy( client->ps.pmove.origin, player->s.origin ); VectorCopy( client->ps.pmove.origin, player->s.old_origin ); VectorCopy( client->ps.pmove.origin, player->olds.origin ); VectorCopy( client->ps.pmove.velocity, player->velocity ); // unlink to make sure it can't possibly interfere with KillBox GClip_UnlinkEntity( player ); // kill anything at the destination KillBox( player ); GClip_LinkEntity( player ); // add the teleport effect at the destination G_TeleportEffect( player, true ); }
/* * G_Teleport * * Teleports client to specified position * If client is not spectator teleporting is only done if position is free and teleport effects are drawn. */ static bool G_Teleport( edict_t *ent, vec3_t origin, vec3_t angles ) { int i; if( !ent->r.inuse || !ent->r.client ) return false; if( ent->r.client->ps.pmove.pm_type != PM_SPECTATOR ) { trace_t tr; G_Trace( &tr, origin, ent->r.mins, ent->r.maxs, origin, ent, MASK_PLAYERSOLID ); if( tr.fraction != 1.0f || tr.startsolid ) return false; G_TeleportEffect( ent, false ); } VectorCopy( origin, ent->s.origin ); VectorCopy( origin, ent->s.old_origin ); VectorCopy( origin, ent->olds.origin ); ent->s.teleported = qtrue; VectorClear( ent->velocity ); ent->r.client->ps.pmove.pm_time = 1; ent->r.client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT; if( ent->r.client->ps.pmove.pm_type != PM_SPECTATOR ) G_TeleportEffect( ent, true ); // set angles VectorCopy( angles, ent->s.angles ); VectorCopy( angles, ent->r.client->ps.viewangles ); // set the delta angle for( i = 0; i < 3; i++ ) ent->r.client->ps.pmove.delta_angles[i] = ANGLE2SHORT( ent->r.client->ps.viewangles[i] ) - ent->r.client->ucmd.angles[i]; return true; }
/* * ClientDisconnect * Called when a player drops from the server. * Will not be called between levels. */ void ClientDisconnect( edict_t *ent, const char *reason ) { int team; if( !ent->r.client || !ent->r.inuse ) return; // always report in RACE mode if( GS_RaceGametype() || ( ent->r.client->team != TEAM_SPECTATOR && ( GS_MatchState() == MATCH_STATE_PLAYTIME || GS_MatchState() == MATCH_STATE_POSTMATCH ) ) ) G_AddPlayerReport( ent, GS_MatchState() == MATCH_STATE_POSTMATCH ); for( team = TEAM_PLAYERS; team < GS_MAX_TEAMS; team++ ) G_Teams_UnInvitePlayer( team, ent ); if( !level.gametype.disableObituaries || !(ent->r.svflags & SVF_FAKECLIENT ) ) { if( !reason ) G_PrintMsg( NULL, "%s" S_COLOR_WHITE " disconnected\n", ent->r.client->netname ); else G_PrintMsg( NULL, "%s" S_COLOR_WHITE " disconnected (%s" S_COLOR_WHITE ")\n", ent->r.client->netname, reason ); } // send effect if( ent->s.team > TEAM_SPECTATOR ) G_TeleportEffect( ent, false ); ent->r.client->team = TEAM_SPECTATOR; G_ClientRespawn( ent, true ); // respawn as ghost ent->movetype = MOVETYPE_NOCLIP; // allow freefly // let the gametype scripts know this client just disconnected G_Gametype_ScoreEvent( ent->r.client, "disconnect", NULL ); G_FreeAI( ent ); AI_EnemyRemoved( ent ); ent->r.inuse = false; ent->r.svflags = SVF_NOCLIENT; memset( ent->r.client, 0, sizeof( *ent->r.client ) ); ent->r.client->ps.playerNum = PLAYERNUM( ent ); trap_ConfigString( CS_PLAYERINFOS+PLAYERNUM( ent ), "" ); GClip_UnlinkEntity( ent ); G_Match_CheckReadys(); }
static void old_teleporter_touch( edict_t *self, edict_t *other, cplane_t *plane, int surfFlags ) { edict_t *dest; int i; vec3_t velocity, angles; mat3_t axis; float speed; vec3_t org; if( !other->r.client ) return; if( self->s.team && self->s.team != other->s.team ) return; if( other->r.client->ps.pmove.pm_type > PM_SPECTATOR ) return; if( self->spawnflags & 1 && other->r.client->ps.pmove.pm_type != PM_SPECTATOR ) return; // match countdown if( GS_MatchState() == MATCH_STATE_COUNTDOWN ) return; // wait delay if( self->timeStamp > level.time ) return; self->timeStamp = level.time + ( self->wait * 1000 ); dest = G_Find( NULL, FOFS( targetname ), self->target ); if( !dest ) { if( developer->integer ) G_Printf( "Couldn't find destination.\n" ); return; } if( self->s.modelindex ) { org[0] = self->s.origin[0] + 0.5 * ( self->r.mins[0] + self->r.maxs[0] ); org[1] = self->s.origin[1] + 0.5 * ( self->r.mins[1] + self->r.maxs[1] ); org[2] = self->s.origin[2] + 0.5 * ( self->r.mins[2] + self->r.maxs[2] ); } else VectorCopy( self->s.origin, org ); // play custom sound if any (played from the teleporter entrance) if( self->noise_index ) G_PositionedSound( org, CHAN_AUTO, self->noise_index, ATTN_NORM ); // draw the teleport entering effect G_TeleportEffect( other, false ); // // teleport the player // VectorCopy( other->r.client->ps.pmove.velocity, velocity ); velocity[2] = 0; // ignore vertical velocity speed = VectorLengthFast( velocity ); // if someone enters a portal backwards, inverse the destination YAW angle #if 0 VectorCopy( other->s.angles, angles ); angles[PITCH] = 0; AngleVectors( angles, axis[0], NULL, NULL ); VectorSubtract( org, other->s.origin, org ); VectorCopy( dest->s.angles, angles ); if( DotProduct( org, axis[0] ) < 0 ) angles[YAW] = anglemod( angles[YAW] - 180 ); #else VectorCopy( dest->s.angles, angles ); #endif AnglesToAxis( dest->s.angles, axis ); VectorScale( &axis[AXIS_FORWARD], speed, other->r.client->ps.pmove.velocity ); VectorCopy( angles, other->r.client->ps.viewangles ); VectorCopy( dest->s.origin, other->r.client->ps.pmove.origin ); // set the delta angle for( i = 0; i < 3; i++ ) other->r.client->ps.pmove.delta_angles[i] = ANGLE2SHORT( other->r.client->ps.viewangles[i] ) - other->r.client->ucmd.angles[i]; other->r.client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT; other->s.teleported = qtrue; other->r.client->ps.pmove.pm_time = 1; // force the minimum no control delay // update the entity from the pmove VectorCopy( other->r.client->ps.viewangles, other->s.angles ); VectorCopy( other->r.client->ps.pmove.origin, other->s.origin ); VectorCopy( other->r.client->ps.pmove.origin, other->s.old_origin ); VectorCopy( other->r.client->ps.pmove.origin, other->olds.origin ); VectorCopy( other->r.client->ps.pmove.velocity, other->velocity ); // unlink to make sure it can't possibly interfere with KillBox GClip_UnlinkEntity( other ); // kill anything at the destination if( !KillBox( other ) ) { } GClip_LinkEntity( other ); // add the teleport effect at the destination G_TeleportEffect( other, true ); }