Well, I have answered this
question a few times, so I figured I may as well formalize it and make a real tutorial.
The problem is: How do you do a Team Fortress style spawning where the users are stuck
looking at the map from an info_intermission until they pick a class, then spawn
afterwards? Took me a while to get this to work properly, and you may need to modify it to
fit your needs, but here's what I did... First, I wrote these
two functions for CBasePlayer:
void CBasePlayer:: StartObserving( void ) {
if (observerflag)
return;
EnableControl(FALSE);
observerflag = TRUE;
RemoveAllItems( TRUE );
pev->deadflag = DEAD_DEAD;
edict_t *pSpot, *pNewSpot;
int iRand;
if ( pev->view_ofs == g_vecZero )
{
// don't accept subsequent attempts to StartObserving()
return;
}
pSpot = FIND_ENTITY_BY_CLASSNAME( NULL, "info_intermission");
if ( !FNullEnt( pSpot ) )
{
// at least one intermission spot in the world.
iRand = RANDOM_LONG( 0, 3 );
while ( iRand > 0 )
{
pNewSpot = FIND_ENTITY_BY_CLASSNAME( pSpot, "info_intermission");
if ( pNewSpot )
{
pSpot = pNewSpot;
}
iRand--;
}
StartObserver( pSpot->v.origin, pSpot->v.v_angle );
}
else
{
// no intermission spot. Push them up in the air, looking down at their corpse
TraceResult tr;
UTIL_TraceLine( pev->origin, pev->origin + Vector( 0, 0, 128 ), ignore_monsters,
edict(), &tr );
StartObserver( tr.vecEndPos, UTIL_VecToAngles( tr.vecEndPos - pev->origin ) );
return;
}
}
void CBasePlayer::StopObserving( void ) {
if (!observerflag)
return;
EnableControl(TRUE);
pev->deadflag = DEAD_NO;
observerflag = FALSE;
pev->button = 0;
m_iRespawnFrames = 0;
respawn(pev, !(m_afPhysicsFlags &
PFLAG_OBSERVER) );
pev->nextthink = -1;
}
StartObserving is basically just a copy of StartDeathCam with a
couple exceptions. First, I set the player's deadflag to DEAD_DEAD since in StartDeathCam,
this has already happened. I'm not sure if this is necessary, but its best to be safe. I
think it might make you invisible (best not to have people joining just floating in the
world!). Second, I called EnableControl(FALSE). This one took me a long time to figure
out. Once you do this, your player will be freezed in his current position, only able to
look around, but not to move. The rest of the code is pretty much the same as
StartDeathCam, except I removed the CopyBodyToQue commands (this drops a copy of
the player's model into the world).
The next function, StopObserving, sets the player back up to allow
him control, visibility, etc.
The observerflag variable both allows me to kick out of
Start/StopObserving when it is already in action, and allows me to bypass PlayerDeathThink
when in observer mode. I put the following line right at the beginning of
PlayerDeathThink:
if (observerflag)
return;
And don't forget to declare observerflag and initialize it to FALSE
as well!
Now, that should be all you need to do to CBasePlayer. Depending on
why you're doing this, the rest may vary, but if you're just forcing players to choose a
class before being able to run around, call StartObserving from the end of InitHUD with
the line:
pPlayer->StartObserving();
Hopefully you've been thinking ahead, and have already created your
menu (see the menu tutorial) to allow the class selection, so at the
end of your class selection code (in ClientCommand of course), call StopObserving.
Well, that should hopefully do it. Please let me know if there's
anything wrong in this tutorial. I wrote it from my code, not the other way around, so I
may have missed something :)
- Blake Grant |