//=========== (C) Copyright 1996-2002, Valve, L.L.C. All rights reserved. =========== // // The copyright to the contents herein is the property of Valve, L.L.C. // The contents may be used and/or copied only with the written permission of // Valve, L.L.C., or in accordance with the terms and conditions stipulated in // the agreement/contract under which the contents have been supplied. // // Purpose: Functionality for the observer chase camera // // $Workfile: $ // $Date: $ // //----------------------------------------------------------------------------- // $Log: $ // // $NoKeywords: $ //============================================================================= #include "extdll.h" #include "util.h" #include "cbase.h" #include "player.h" #include "pm_shared/pm_shared.h" #include "mod/AvHPlayer.h" #include "mod/AvHGamerules.h" const float kNextTargetInterval = .2f; // Find the next client in the game for this player to spectate bool CBasePlayer::Observer_FindNextPlayer(bool inReverse) { // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching // only a subset of the players. e.g. Make it check the target's team. bool theSuccess = false; int iStart; if ( m_hObserverTarget ) iStart = ENTINDEX( m_hObserverTarget->edict() ); else iStart = ENTINDEX( edict() ); int iCurrent = iStart; m_hObserverTarget = NULL; if(this->entindex() == 1) { int a = 0; } int iDir = inReverse ? -1 : 1; AvHPlayer* theThisAvHPlayer = dynamic_cast(this); do { iCurrent += iDir; // Loop through the clients if (iCurrent > gpGlobals->maxClients) iCurrent = 1; if (iCurrent < 1) iCurrent = gpGlobals->maxClients; CBaseEntity *pEnt = UTIL_PlayerByIndex( iCurrent ); if ( !pEnt ) continue; if ( pEnt == this ) continue; // Don't spec observers or invisible players if ( ((CBasePlayer*)pEnt)->IsObserver() || (pEnt->pev->effects & EF_NODRAW)) continue; // MOD AUTHORS: Add checks on target here. AvHPlayer* thePotentialTargetPlayer = dynamic_cast(pEnt); if(theThisAvHPlayer && thePotentialTargetPlayer) { if(!thePotentialTargetPlayer->GetIsRelevant()) { continue; } // Don't allow spectating of other team when we could come back in if(((theThisAvHPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theThisAvHPlayer->GetPlayMode() == PLAYMODE_REINFORCING)) && (thePotentialTargetPlayer->pev->team != this->pev->team)) { continue; } if(theThisAvHPlayer->GetPlayMode() != PLAYMODE_OBSERVER) { if(GetGameRules()->GetIsTournamentMode() && (thePotentialTargetPlayer->pev->team != this->pev->team) && (this->pev->team != TEAM_IND)) { continue; } } // Don't allow spectating of players in top down mode if(thePotentialTargetPlayer->GetIsInTopDownMode()) { continue; } // Don't allow spectating opposite teams in tournament mode //if(GetGameRules()->GetIsTournamentMode()) //{ //} m_hObserverTarget = pEnt; } break; } while ( iCurrent != iStart ); // Did we find a target? if ( m_hObserverTarget ) { // Store the target in pev so the physics DLL can get to it if (pev->iuser1 != OBS_ROAMING) pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); // Move to the target UTIL_SetOrigin( pev, m_hObserverTarget->pev->origin ); //ALERT( at_console, "Now Tracking %s\n", STRING( m_hObserverTarget->pev->classname ) ); m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; theSuccess = true; } else { //ALERT( at_console, "No observer targets.\n" ); } return theSuccess; } void CBasePlayer::Observer_SpectatePlayer(int index) { CBaseEntity* pEnt = UTIL_PlayerByIndex(index); AvHPlayer* thePotentialTargetPlayer = dynamic_cast(pEnt); AvHPlayer* theThisAvHPlayer = dynamic_cast(this); if (theThisAvHPlayer == NULL || thePotentialTargetPlayer == NULL) { return; } if(!thePotentialTargetPlayer->GetIsRelevant()) { return; } // Don't allow spectating of other team when we could come back in if(((theThisAvHPlayer->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT) || (theThisAvHPlayer->GetPlayMode() == PLAYMODE_REINFORCING)) && (thePotentialTargetPlayer->pev->team != this->pev->team)) { return; } if(theThisAvHPlayer->GetPlayMode() != PLAYMODE_OBSERVER) { if(GetGameRules()->GetIsTournamentMode() && (thePotentialTargetPlayer->pev->team != this->pev->team) && (this->pev->team != TEAM_IND)) { return; } } // Don't allow spectating of players in top down mode if(thePotentialTargetPlayer->GetIsInTopDownMode()) { return; } m_hObserverTarget = pEnt; pev->iuser2 = index; } // Handle buttons in observer mode void CBasePlayer::Observer_HandleButtons() { // Removed by mmcguire. // This is all handled through the client side UI. /* // Slow down mouse clicks if ( m_flNextObserverInput > gpGlobals->time ) return; // Only do this if spectating AvHPlayer* thePlayer = dynamic_cast(this); ASSERT(thePlayer); bool theIsObserving = (thePlayer->GetPlayMode() == PLAYMODE_OBSERVER); // Jump changes from modes: Chase to Roaming if ( m_afButtonPressed & IN_JUMP ) { if ( pev->iuser1 == OBS_CHASE_LOCKED ) { Observer_SetMode( OBS_CHASE_FREE ); } else if ( pev->iuser1 == OBS_CHASE_FREE ) { if(theIsObserving) { Observer_SetMode(OBS_ROAMING); } else { Observer_SetMode(OBS_IN_EYE); } } else if ( pev->iuser1 == OBS_ROAMING ) { Observer_SetMode( OBS_IN_EYE ); } else if ( pev->iuser1 == OBS_IN_EYE ) { if(theIsObserving) { Observer_SetMode(OBS_MAP_FREE); } else { Observer_SetMode(OBS_CHASE_LOCKED); } } else if ( pev->iuser1 == OBS_MAP_FREE ) { Observer_SetMode( OBS_MAP_CHASE ); } else { Observer_SetMode( OBS_CHASE_FREE ); // don't use OBS_CHASE_LOCKED anymore } m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; } // Attack moves to the next player if ( (m_afButtonPressed & IN_ATTACK) || ((m_afButtonPressed & IN_MOVERIGHT) && (pev->iuser1 != OBS_ROAMING)) ) { if(Observer_FindNextPlayer( false )) { m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; } else { Observer_SetMode( OBS_CHASE_FREE ); } } // Attack2 moves to the prev player if ( (m_afButtonPressed & IN_ATTACK2) || ((m_afButtonPressed & IN_MOVELEFT) && (pev->iuser1 != OBS_ROAMING)) ) { if(Observer_FindNextPlayer( true )) { m_flNextObserverInput = gpGlobals->time + kNextTargetInterval; } else { Observer_SetMode( OBS_CHASE_FREE ); } } */ } // Attempt to change the observer mode void CBasePlayer::Observer_SetMode( int iMode ) { // Limit some modes if we're not observing AvHPlayer* thePlayer = dynamic_cast(this); ASSERT(thePlayer); bool theIsObserving = (thePlayer->GetPlayMode() == PLAYMODE_OBSERVER); if(!theIsObserving) { if((iMode == OBS_ROAMING) /*|| (iMode == OBS_MAP_FREE) || (iMode == OBS_MAP_CHASE)*/) { return; } } // Just abort if we're changing to the mode we're already in if ( iMode == pev->iuser1 ) return; // Removed by mmcguire. // is valid mode ? if ( iMode < OBS_CHASE_LOCKED || iMode > OBS_IN_EYE ) iMode = OBS_IN_EYE; // now it is // if we are not roaming, we need a valid target to track if ( (iMode != OBS_ROAMING) && (m_hObserverTarget == NULL) ) { Observer_FindNextPlayer(); // if we didn't find a valid target switch to roaming if (m_hObserverTarget == NULL) { iMode = OBS_ROAMING; } } // set spectator mode pev->iuser1 = iMode; // set target if not roaming if (iMode == OBS_ROAMING) pev->iuser2 = 0; else pev->iuser2 = ENTINDEX( m_hObserverTarget->edict() ); // Make sure our target is valid (go backward then forward) Observer_FindNextPlayer(true); Observer_FindNextPlayer(false); }