302 lines
7.1 KiB
C++
302 lines
7.1 KiB
C++
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Crytek Source code
|
|
// Copyright (c) Crytek 2001-2004
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include <IEntitySystem.h>
|
|
#include "Game.h"
|
|
#include "spectator.h"
|
|
#include "XEntityProcessingCmd.h"
|
|
#include "XServer.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CSpectator::CSpectator(CXGame *pGame) :m_vAngles(0,0,0)
|
|
{
|
|
m_pScriptObject=NULL;
|
|
m_pGame=pGame;
|
|
m_eiHost=0;
|
|
m_fLastTargetSwitch=0.0f;
|
|
|
|
m_AreaUser.SetGame( pGame );
|
|
m_AreaUser.SetEntity( GetEntity() );
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CSpectator::~CSpectator(void)
|
|
{
|
|
m_pGame->m_XAreaMgr.ExitAllAreas( m_AreaUser );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Initialize the spectator-container.
|
|
bool CSpectator::Init()
|
|
{
|
|
IEntity *entity = GetEntity();
|
|
|
|
entity->GetScriptObject()->SetValue("type", "spectator");
|
|
// set camera
|
|
entity->SetCamera(m_pGame->GetSystem()->GetIEntitySystem()->CreateEntityCamera());
|
|
entity->GetCamera()->GetCamera().Init(m_pGame->GetSystem()->GetIRenderer()->GetWidth(),m_pGame->GetSystem()->GetIRenderer()->GetHeight());
|
|
m_pTimer=m_pGame->GetSystem()->GetITimer();
|
|
entity->SetNeedUpdate(true);
|
|
|
|
entity->SetNetPresence(true); // needed to sync m_eiHost
|
|
|
|
m_roll = 0;
|
|
|
|
float fMass=100.0f;
|
|
float fHeight=1.2f;
|
|
float fEyeHeight=1.7f;
|
|
float sphere_height=0.6f;
|
|
float radius=0.6f;
|
|
float fGravity=0.0f;
|
|
|
|
entity->CreateLivingEntity(fMass,fHeight,fEyeHeight,sphere_height,radius,-1,fGravity,true,true);
|
|
|
|
pe_player_dynamics pd;
|
|
pd.bActive = 1;
|
|
pd.kAirControl=1.0f;
|
|
pd.bSwimming=1;
|
|
entity->GetPhysics()->SetParams(&pd);
|
|
|
|
{
|
|
pe_params_flags pf;
|
|
|
|
pf.flagsAND=~(lef_push_players | lef_push_objects);
|
|
|
|
entity->GetPhysics()->SetParams(&pf);
|
|
}
|
|
|
|
{
|
|
pe_params_part pp;
|
|
|
|
pp.ipart=0;
|
|
pp.flagsAND=0;
|
|
|
|
entity->GetPhysics()->SetParams(&pp);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Update the camera.
|
|
void CSpectator::Update()
|
|
{
|
|
IEntity *pEntity=GetEntity();
|
|
|
|
m_pGame->ConstrainToSandbox(pEntity); // limit in the world boundaries
|
|
|
|
if(m_pGame->m_pServer) // detect if player was removed (not 100% accurate, might switch to different player)
|
|
{
|
|
bool bReset=false;
|
|
|
|
IEntity *pHost = m_pGame->GetSystem()->GetIEntitySystem()->GetEntity(m_eiHost);
|
|
|
|
if(pHost)
|
|
{
|
|
IEntityContainer *pICnt=pHost->GetContainer();
|
|
|
|
if(pICnt)
|
|
{
|
|
CPlayer *pPlayer;
|
|
|
|
if(!pICnt->QueryContainerInterface(CIT_IPLAYER,(void **)&pPlayer))
|
|
bReset=true;
|
|
}
|
|
else bReset=true;
|
|
}
|
|
else bReset=true;
|
|
|
|
if(bReset)
|
|
ResetHostId(); // host entity was removed
|
|
}
|
|
|
|
// only a client has to set the camera
|
|
if(m_pGame->IsClient())
|
|
{
|
|
IEntityCamera *pEC;
|
|
Vec3d v3Angles;
|
|
|
|
if(m_eiHost!=0)
|
|
return;
|
|
|
|
pEC=pEntity->GetCamera();
|
|
if(pEC)
|
|
{
|
|
pEC->SetAngles(m_vAngles);
|
|
pEC->SetPos(pEntity->GetPos()+Vec3(0,0,0.6f)); // 1.7m eye height
|
|
}
|
|
|
|
// update areas only for local spectator
|
|
if(IsMySpectator())
|
|
{
|
|
m_AreaUser.SetEntity(GetEntity());
|
|
m_pGame->m_XAreaMgr.UpdatePlayer( m_AreaUser );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
EntityId CSpectator::GetHostId() const
|
|
{
|
|
return m_eiHost;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CSpectator::ResetHostId()
|
|
{
|
|
m_eiHost=0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CSpectator::OnSetAngles( const Vec3d &ang ) {}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IScriptObject *CSpectator::GetScriptObject()
|
|
{
|
|
return m_pScriptObject;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CSpectator::SetScriptObject(IScriptObject *object)
|
|
{
|
|
m_pScriptObject=object;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Save upcast.
|
|
bool CSpectator::QueryContainerInterface(ContainerInterfaceType desired_interface, void **ppInterface )
|
|
{
|
|
if (desired_interface == CIT_ISPECTATOR)
|
|
{
|
|
*ppInterface = (void *) this;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
*ppInterface = 0;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CSpectator::GetEntityDesc( CEntityDesc &desc ) const
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Process input.
|
|
void CSpectator::ProcessKeys(CXEntityProcessingCmd &epc)
|
|
{
|
|
if(epc.CheckAction(ACTION_FIRE0))
|
|
{
|
|
if(m_pGame->m_pServer && (m_pTimer->GetCurrTime()-m_fLastTargetSwitch>1))
|
|
{
|
|
epc.RemoveAction(ACTION_FIRE0);
|
|
|
|
m_pGame->m_pServer->m_ServerRules.OnSpectatorSwitchModeRequest(m_pEntity);
|
|
m_fLastTargetSwitch=m_pTimer->GetCurrTime();
|
|
}
|
|
}
|
|
|
|
if(m_eiHost!=0)
|
|
return;
|
|
|
|
// fly-mode
|
|
Vec3d angles=epc.GetDeltaAngles();
|
|
|
|
m_vAngles=angles;
|
|
|
|
m_vAngles.x = max(m_vAngles.x,-65);
|
|
m_vAngles.x = min(m_vAngles.x,65);
|
|
|
|
epc.SetDeltaAngles(m_vAngles);
|
|
|
|
Vec3d pos=m_pEntity->GetPos();
|
|
|
|
int strafe = 0, move = 0;
|
|
if(epc.CheckAction(ACTION_MOVE_FORWARD)) move = 1;
|
|
if(epc.CheckAction(ACTION_MOVE_BACKWARD)) move = -1;
|
|
if(epc.CheckAction(ACTION_MOVE_LEFT)) strafe = -1;
|
|
if(epc.CheckAction(ACTION_MOVE_RIGHT)) strafe = 1;
|
|
|
|
|
|
Vec3d d;
|
|
|
|
d.x = (float)(move*cry_cosf(DEG2RAD(m_vAngles.z-90)));
|
|
d.y = (float)(move*cry_sinf(DEG2RAD(m_vAngles.z-90)));
|
|
|
|
d.x *= (float)cry_cosf(DEG2RAD(-m_vAngles.x));
|
|
d.y *= (float)cry_cosf(DEG2RAD(-m_vAngles.x));
|
|
d.z = (float)(move*cry_sinf(DEG2RAD(-m_vAngles.x)));
|
|
|
|
d.x += (float)(strafe*cry_cosf(DEG2RAD(m_vAngles.z-180)));
|
|
d.y += (float)(strafe*cry_sinf(DEG2RAD(m_vAngles.z-180)));
|
|
|
|
float curtime = m_pGame->m_pSystem->GetITimer()->GetFrameTime();
|
|
|
|
if (strafe==0)
|
|
{
|
|
m_roll = m_roll/(1+(float)cry_sqrtf(curtime*1000.0f)/25);
|
|
}
|
|
else
|
|
{
|
|
m_roll += strafe*curtime/-0.03f;
|
|
float maxroll = 3.0f;
|
|
if(m_roll>maxroll) m_roll = (float)maxroll;
|
|
if(m_roll<-maxroll) m_roll = (float)-maxroll;
|
|
};
|
|
|
|
m_vAngles.y = m_roll;
|
|
|
|
// move entity by physics
|
|
if(curtime)
|
|
{
|
|
pe_action_move motion;
|
|
|
|
motion.dt=curtime;
|
|
motion.dir=d*12.0f; // spectator speed is 12x
|
|
|
|
m_pEntity->GetPhysics()->Action(&motion);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CSpectator::Write(CStream &stm,EntityCloneState *cs)
|
|
{
|
|
return stm.Write(m_eiHost);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CSpectator::Read(CStream &stm)
|
|
{
|
|
return stm.Read(m_eiHost);
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CSpectator::IsMySpectator() const
|
|
{
|
|
if(!m_pGame->m_pClient) return false;
|
|
return (m_pEntity->GetId()==m_pGame->m_pClient->GetPlayerId());
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CSpectator::OnEntityNetworkUpdate( const EntityId &idViewerEntity, const Vec3d &v3dViewer, uint32 &inoutPriority,
|
|
EntityCloneState &inoutCloneState ) const
|
|
{
|
|
bool bLocalPlayer = inoutCloneState.m_bLocalplayer;
|
|
|
|
if(!bLocalPlayer) // spectators are not sent to other player
|
|
inoutPriority=0; // no update at all
|
|
}
|