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 |