504 lines
14 KiB
C++
504 lines
14 KiB
C++
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Crytek Source code
|
|
// Copyright (c) Crytek 2001-2004
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include <IEntitySystem.h>
|
|
#include "Game.h"
|
|
#include "AdvCamSystem.h" // CAdvCamSystem
|
|
#include "XPlayer.h" // CPlayer
|
|
#include "Cry_Math.h" // TMatrix_tpl
|
|
#include "XEntityProcessingCmd.h" // CXEntityProcessingCmd for ProcessKeys
|
|
|
|
CAdvCamSystem::CAdvCamSystem(CXGame *pGame)
|
|
{
|
|
m_pScriptObject=NULL;
|
|
m_pGame=pGame;
|
|
m_eiPlayerA=INVALID_WID;
|
|
m_eiPlayerB=INVALID_WID;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Initialize the AdvCamSystem-container.
|
|
bool CAdvCamSystem::Init()
|
|
{
|
|
IEntity *entity = GetEntity();
|
|
entity->GetScriptObject()->SetValue("type", "advcamsystem");
|
|
// set camera
|
|
entity->SetCamera(m_pGame->GetSystem()->GetIEntitySystem()->CreateEntityCamera());
|
|
entity->GetCamera()->GetCamera().Init(m_pGame->GetSystem()->GetIRenderer()->GetWidth(),m_pGame->GetSystem()->GetIRenderer()->GetHeight());
|
|
entity->SetNeedUpdate(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Update the camera.
|
|
void CAdvCamSystem::Update( void )
|
|
{
|
|
//the server doesn't need to update AdvCamSystem
|
|
if(!m_pGame->IsClient())
|
|
return;
|
|
|
|
Vec3 vSrcPos, vDstPos;
|
|
Vec3 vSrcPos2, vDstPos2;
|
|
|
|
if(m_pScriptObject)
|
|
{
|
|
_SmartScriptObject sm(m_pGame->GetScriptSystem(),true);
|
|
_SmartScriptObject current(m_pGame->GetScriptSystem(),true);
|
|
_SmartScriptObject future(m_pGame->GetScriptSystem(),true);
|
|
|
|
// get the current state
|
|
int currentState = 0;
|
|
int futureState = 0;
|
|
float blendFactor = 0;
|
|
m_pEntity->GetScriptObject()->GetValue("currentState", currentState);
|
|
m_pEntity->GetScriptObject()->GetValue("futureState", futureState);
|
|
m_pEntity->GetScriptObject()->GetValue("blendFactor", blendFactor);
|
|
m_pEntity->GetScriptObject()->GetValue("states", sm);
|
|
sm->GetAt(currentState, current);
|
|
sm->GetAt(futureState, future);
|
|
|
|
CalcCameraVectors(current, vSrcPos, vDstPos);
|
|
CalcCameraVectors(future, vSrcPos2, vDstPos2);
|
|
|
|
vSrcPos = (1.0f - blendFactor) * vSrcPos + blendFactor * vSrcPos2;
|
|
vDstPos = (1.0f - blendFactor) * vDstPos + blendFactor * vDstPos2;
|
|
|
|
float currentRadius;
|
|
float futureRadius;
|
|
|
|
current->GetValue("max_radius", currentRadius);
|
|
future->GetValue("max_radius", futureRadius);
|
|
m_fMaxRadius = (1.0f - blendFactor) * currentRadius + blendFactor * futureRadius;
|
|
current->GetValue("min_radius", currentRadius);
|
|
future->GetValue("min_radius", futureRadius);
|
|
m_fMinRadius = (1.0f - blendFactor) * currentRadius + blendFactor * futureRadius;
|
|
}
|
|
|
|
|
|
|
|
Vec3 vDir=vDstPos-vSrcPos;
|
|
|
|
if (vDir.Length() < m_fMinRadius)
|
|
{
|
|
vDir.Normalize();
|
|
vSrcPos = vDstPos - vDir * m_fMinRadius;
|
|
}
|
|
Ang3 vAngles=ConvertVectorToCameraAnglesSnap180(vDir);
|
|
|
|
m_pEntity->SetAngles(vAngles);
|
|
m_pEntity->SetPos(vSrcPos);
|
|
|
|
|
|
IEntity *pEntity =GetEntity();
|
|
IEntityCamera *pEC =pEntity->GetCamera();
|
|
Vec3 v3Angles =pEntity->GetAngles();
|
|
|
|
if(pEC)
|
|
{
|
|
pEC->SetAngles(v3Angles);
|
|
|
|
pEC->SetPos(pEntity->GetPos()); // swing up and down - just for testing
|
|
}
|
|
}
|
|
|
|
void CAdvCamSystem::OnSetAngles( const Vec3d &ang )
|
|
{
|
|
/*if(m_pGame->m_pClient->GetPlayerID()==GetEntity()->GetId() || m_pGame->m_pClient->m_bLocalHost)
|
|
m_pGame->m_pClient->m_PlayerProcessingCmd.SetDeltaAngles(ang);*/
|
|
|
|
}
|
|
|
|
|
|
IScriptObject *CAdvCamSystem::GetScriptObject()
|
|
{
|
|
return m_pScriptObject;
|
|
}
|
|
|
|
void CAdvCamSystem::SetScriptObject(IScriptObject *object)
|
|
{
|
|
m_pScriptObject=object;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Save upcast.
|
|
bool CAdvCamSystem::QueryContainerInterface(ContainerInterfaceType desired_interface, void **ppInterface )
|
|
{
|
|
|
|
if (desired_interface == CIT_IADVCAMSYSTEM)
|
|
{
|
|
*ppInterface = (void *) this;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
*ppInterface = 0;
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
void CAdvCamSystem::GetEntityDesc( CEntityDesc &desc ) const
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Process input.
|
|
void CAdvCamSystem::ProcessKeys( CXEntityProcessingCmd &epc )
|
|
{
|
|
if(m_eiPlayerA && m_eiPlayerB)
|
|
{
|
|
// get entities
|
|
IEntitySystem *pEntitySystem=m_pGame->m_pSystem->GetIEntitySystem(); assert(pEntitySystem);
|
|
IEntity *pEntityA = pEntitySystem->GetEntity(m_eiPlayerA); assert(pEntityA);if(!pEntityA)return;
|
|
IEntity *pEntityB = pEntitySystem->GetEntity(m_eiPlayerB); assert(pEntityB);if(!pEntityB)return;
|
|
|
|
// get player containers of the entities
|
|
CPlayer *pPlayerA = NULL;
|
|
pEntityA->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void **) &pPlayerA); assert(pPlayerA);
|
|
CPlayer *pPlayerB = NULL;
|
|
pEntityB->GetContainer()->QueryContainerInterface(CIT_IPLAYER,(void **) &pPlayerB); assert(pPlayerB);
|
|
|
|
// determine which direction we are moving in
|
|
// build camera matrix
|
|
Vec3 vCamAngles;
|
|
Matrix33 matCamera;
|
|
vCamAngles = m_pEntity->GetAngles();
|
|
matCamera.SetRotationAA(gf_DEGTORAD*vCamAngles.z, Vec3(0,0,1));
|
|
Matrix33 matPlayerA;
|
|
vCamAngles = pEntityA->GetAngles();
|
|
matPlayerA.SetRotationAA(gf_DEGTORAD*vCamAngles.z, Vec3(0,0,1));
|
|
Matrix33 matPlayerB;
|
|
vCamAngles = pEntityB->GetAngles();
|
|
matPlayerB.SetRotationAA(gf_DEGTORAD*vCamAngles.z, Vec3(0,0,1));
|
|
|
|
// we have to make a copy, because the function is called twice per frame. We modify the actions in the epc, so this
|
|
// would cause side effects the second time running through the function.
|
|
CXEntityProcessingCmd epcCopyA = epc;
|
|
CXEntityProcessingCmd epcCopyB = epc;
|
|
|
|
_SmartScriptObject sm(m_pGame->GetScriptSystem(),true);
|
|
_SmartScriptObject current(m_pGame->GetScriptSystem(),true);
|
|
int currentState = 0;
|
|
float blendFactor = 0;
|
|
m_pEntity->GetScriptObject()->GetValue("currentState", currentState);
|
|
m_pEntity->GetScriptObject()->GetValue("states", sm);
|
|
sm->GetAt(currentState, current);
|
|
|
|
bool linked_a;
|
|
|
|
current->GetValue("linked_a", linked_a);
|
|
|
|
Vec3 vMoveDirA;
|
|
|
|
if (linked_a)
|
|
vMoveDirA = CalcPlayerMoveDirection(matCamera, 0);
|
|
else
|
|
vMoveDirA = CalcPlayerMoveDirection(matCamera, 0);
|
|
|
|
Vec3 vMoveDirB = CalcPlayerMoveDirection(matCamera, 1);
|
|
|
|
// vector from player A to player B
|
|
Vec3 vToB = pEntityB->GetPos()-pEntityA->GetPos();
|
|
|
|
// if player a is outside the follow radius, we move into the direction of player b
|
|
float fDistance = vToB.Length();
|
|
if (fDistance > m_fMaxRadius)
|
|
{
|
|
float weight = (fDistance - m_fMaxRadius)/10.0f;
|
|
//vToB.Normalize();
|
|
|
|
if (GetLengthSquared(vMoveDirB) > 0.01)
|
|
{
|
|
vMoveDirA += (weight)*vToB;
|
|
}
|
|
else if (GetLengthSquared(vMoveDirA) > 0.01)
|
|
{
|
|
vMoveDirB += -(weight)*vToB;
|
|
}
|
|
}
|
|
|
|
// get input system
|
|
ISystem *pSystem = m_pGame->GetSystem();
|
|
IInput *pInput = pSystem->GetIInput();
|
|
|
|
if (pInput->JoyButtonPressed(7))
|
|
{
|
|
bool isBlending;
|
|
m_pEntity->GetScriptObject()->GetValue("isBlending", isBlending);
|
|
if (!isBlending)
|
|
{
|
|
int currentState;
|
|
m_pEntity->GetScriptObject()->GetValue("currentState", currentState);
|
|
|
|
if (currentState == 8)
|
|
{
|
|
m_pEntity->GetScriptObject()->SetValue("isBlending", true);
|
|
m_pEntity->GetScriptObject()->SetValue("futureState", 9);
|
|
}
|
|
}
|
|
}
|
|
if (pInput->JoyButtonPressed(6))
|
|
{
|
|
bool isBlending;
|
|
m_pEntity->GetScriptObject()->GetValue("isBlending", isBlending);
|
|
if (!isBlending)
|
|
{
|
|
int currentState;
|
|
m_pEntity->GetScriptObject()->GetValue("currentState", currentState);
|
|
|
|
if (currentState == 8)
|
|
{
|
|
m_pEntity->GetScriptObject()->SetValue("isBlending", true);
|
|
m_pEntity->GetScriptObject()->SetValue("futureState", 10);
|
|
}
|
|
}
|
|
}
|
|
if (!pInput->JoyButtonPressed(6) && !pInput->JoyButtonPressed(7))
|
|
{
|
|
bool isBlending;
|
|
m_pEntity->GetScriptObject()->GetValue("isBlending", isBlending);
|
|
if (!isBlending)
|
|
{
|
|
int currentState;
|
|
m_pEntity->GetScriptObject()->GetValue("currentState", currentState);
|
|
|
|
if (currentState != 8)
|
|
{
|
|
m_pEntity->GetScriptObject()->SetValue("isBlending", true);
|
|
m_pEntity->GetScriptObject()->SetValue("futureState", 8);
|
|
}
|
|
}
|
|
}
|
|
|
|
// hack begin
|
|
m_pGame->m_pClient->SetPlayerID(pPlayerA->GetEntity()->GetId());
|
|
if (GetLengthSquared(vMoveDirA) > 1.0f)
|
|
vMoveDirA.Normalize();
|
|
|
|
m_pGame->m_pSystem->GetIScriptSystem()->SetGlobalValue("p_speed_run", vMoveDirA.Length()*5.0f);
|
|
// hack end
|
|
|
|
SetMoveDirection(*pPlayerA, *pEntityA, epcCopyA, vMoveDirA, linked_a);
|
|
|
|
// hack begin
|
|
m_pGame->m_pClient->SetPlayerID(pPlayerB->GetEntity()->GetId());
|
|
if (GetLengthSquared(vMoveDirB) > 1.0f)
|
|
vMoveDirB.Normalize();
|
|
|
|
m_pGame->m_pSystem->GetIScriptSystem()->SetGlobalValue("p_speed_run", vMoveDirB.Length()*5.0f);
|
|
// hack end
|
|
|
|
SetMoveDirection(*pPlayerB, *pEntityB, epcCopyB, vMoveDirB, true);
|
|
|
|
// hack
|
|
m_pGame->m_pClient->SetPlayerID(GetEntity()->GetId());
|
|
}
|
|
}
|
|
|
|
bool CAdvCamSystem::Write(CStream &stm,EntityCloneState *cs)
|
|
{
|
|
if(!stm.Write(m_eiPlayerA)) return false;
|
|
if(!stm.Write(m_eiPlayerB)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CAdvCamSystem::Read(CStream &stm)
|
|
{
|
|
if(!stm.Read(m_eiPlayerA)) return false;
|
|
if(!stm.Read(m_eiPlayerB)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CAdvCamSystem::SetMinRadius(float radius)
|
|
{
|
|
m_fMinRadius = radius;
|
|
}
|
|
|
|
void CAdvCamSystem::SetMaxRadius(float radius)
|
|
{
|
|
m_fMaxRadius = radius;
|
|
}
|
|
|
|
Vec3 CAdvCamSystem::CalcPlayerMoveDirection(const Matrix33 &matCamera, unsigned int joyID) const
|
|
{
|
|
Vec3 vMoveDir;
|
|
|
|
vMoveDir.Set(0,0,0);
|
|
|
|
// get input system
|
|
ISystem *pSystem = m_pGame->GetSystem();
|
|
assert(pSystem); if (!pSystem) return vMoveDir;
|
|
IInput *pInput = pSystem->GetIInput();
|
|
assert(pInput); if (!pInput) return vMoveDir;
|
|
|
|
Vec3 vControllerDir = (pInput)->JoyGetAnalog1Dir(joyID);
|
|
|
|
vMoveDir.x = vControllerDir.y * matCamera(0, 1) - vControllerDir.x * matCamera(0,0);
|
|
vMoveDir.y = vControllerDir.y * matCamera(1, 1) - vControllerDir.x * matCamera(1,0);
|
|
|
|
return vMoveDir;
|
|
}
|
|
|
|
void CAdvCamSystem::CalcCameraVectors(_SmartScriptObject &scriptObject, Vec3& vSrcPos, Vec3& vDstPos)
|
|
{
|
|
CScriptObjectVector oVec(m_pGame->GetScriptSystem(),true);
|
|
|
|
Vec3 src_a_offset(0, 0, 0);
|
|
float src_origin = 0.0f;
|
|
Vec3 src_b_offset(0, 0, 0);
|
|
Vec3 src_ab_offset_m(0, 0, 0);
|
|
Vec3 src_ab_offset_fac(0, 0, 0);
|
|
|
|
Vec3 dst_a_offset(0, 0, 0);
|
|
float dst_origin = 1.0f;
|
|
Vec3 dst_b_offset(0, 0, 0);
|
|
Vec3 dst_ab_offset_m(0, 0, 0);
|
|
Vec3 dst_ab_offset_fac(0, 0, 0);
|
|
|
|
#define GETVAL(Name) { scriptObject->GetValue(#Name,Name); }
|
|
#define GETVEC(Name) { if(scriptObject->GetValue(#Name,*oVec))Name=oVec.Get(); }
|
|
|
|
GETVEC(src_a_offset)
|
|
GETVAL(src_origin)
|
|
GETVEC(src_b_offset)
|
|
GETVEC(src_ab_offset_m)
|
|
GETVEC(src_ab_offset_fac)
|
|
|
|
GETVEC(dst_a_offset)
|
|
GETVAL(dst_origin)
|
|
GETVEC(dst_b_offset)
|
|
GETVEC(dst_ab_offset_m)
|
|
GETVEC(dst_ab_offset_fac)
|
|
|
|
vSrcPos.Set(0, 0, 0);
|
|
vDstPos.Set(0, 0, 0);
|
|
|
|
Vec3 vA(0,0,0),vB(0,0,0);
|
|
Matrix33 baseA_m, baseB_m, baseAB_m, baseAB_fac;
|
|
|
|
baseA_m.SetIdentity(); baseB_m.SetIdentity(); baseAB_m.SetIdentity(); baseAB_fac.SetIdentity();
|
|
|
|
if(m_eiPlayerA)
|
|
{
|
|
IEntitySystem *pEntitySystem=m_pGame->m_pSystem->GetIEntitySystem(); assert(pEntitySystem);
|
|
IEntity *pEntity=pEntitySystem->GetEntity(m_eiPlayerA); assert(pEntity);if(!pEntity)return;
|
|
|
|
vA=pEntity->GetPos();
|
|
|
|
Ang3 vAnglesA=pEntity->GetAngles();
|
|
|
|
baseA_m.SetRotationAA(gf_DEGTORAD*vAnglesA.z,Vec3(0,0,1));
|
|
}
|
|
|
|
if(m_eiPlayerB)
|
|
{
|
|
IEntitySystem *pEntitySystem=m_pGame->m_pSystem->GetIEntitySystem(); assert(pEntitySystem);
|
|
IEntity *pEntity=pEntitySystem->GetEntity(m_eiPlayerB); assert(pEntity);if(!pEntity)return;
|
|
|
|
vB=pEntity->GetPos();
|
|
|
|
Ang3 vAnglesB=pEntity->GetAngles();
|
|
|
|
baseB_m.SetRotationAA(gf_DEGTORAD*vAnglesB.z,Vec3(0,0,1));
|
|
}
|
|
|
|
{
|
|
Vec3 vA2B=vB-vA;
|
|
Vec3 vCross=vA2B^Vec3(0.0f,0.0f,1.0f);
|
|
|
|
baseAB_fac(0,0)=vCross.x;
|
|
baseAB_fac(1,0)=vCross.y;
|
|
baseAB_fac(2,0)=vCross.z;
|
|
baseAB_fac(0,1)=vA2B.x;
|
|
baseAB_fac(1,1)=vA2B.y;
|
|
baseAB_fac(2,1)=vA2B.z;
|
|
baseAB_fac(0,2)=0.0f;
|
|
baseAB_fac(1,2)=0.0f;
|
|
baseAB_fac(2,2)=1.0f;
|
|
}
|
|
|
|
{
|
|
Vec3 vA2B=vB-vA; vA2B.Normalize();
|
|
Vec3 vCross=vA2B^Vec3(0.0f,0.0f,1.0f);
|
|
|
|
baseAB_m(0,0)=vCross.x;
|
|
baseAB_m(1,0)=vCross.y;
|
|
baseAB_m(2,0)=vCross.z;
|
|
baseAB_m(0,1)=vA2B.x;
|
|
baseAB_m(1,1)=vA2B.y;
|
|
baseAB_m(2,1)=vA2B.z;
|
|
baseAB_m(0,2)=0.0f;
|
|
baseAB_m(1,2)=0.0f;
|
|
baseAB_m(2,2)=1.0f;
|
|
}
|
|
|
|
vSrcPos+= vB*src_origin+vA*(1.0f-src_origin);
|
|
vSrcPos+= baseA_m*src_a_offset;
|
|
vSrcPos+= baseB_m*src_b_offset;
|
|
vSrcPos+= baseAB_m*src_ab_offset_m;
|
|
vSrcPos+= baseAB_fac*src_ab_offset_fac;
|
|
|
|
vDstPos += vB*dst_origin+vA*(1.0f-dst_origin);
|
|
vDstPos += baseA_m*dst_a_offset;
|
|
vDstPos += baseB_m*dst_b_offset;
|
|
vDstPos += baseAB_m*dst_ab_offset_m;
|
|
vDstPos += baseAB_fac*dst_ab_offset_fac;
|
|
}
|
|
|
|
void CAdvCamSystem::SetMoveDirection(CPlayer &player, const IEntity &entity, CXEntityProcessingCmd &epc, const Vec3 &vMoveDir, bool linked) const
|
|
{
|
|
// we always move forward, so clear the processing command
|
|
epc.Reset();
|
|
|
|
if (linked)
|
|
{
|
|
if (GetLengthSquared(vMoveDir) > 0.01f)
|
|
{
|
|
Ang3 vAngles;
|
|
epc.AddAction(ACTION_MOVE_FORWARD);
|
|
vAngles=ConvertVectorToCameraAnglesSnap180(vMoveDir);
|
|
epc.SetDeltaAngles(Vec3(0, 0, vAngles.z));
|
|
}
|
|
else
|
|
{
|
|
epc.SetDeltaAngles(entity.GetAngles());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// get direction from other controller
|
|
ISystem *pSystem = m_pGame->GetSystem();
|
|
IInput *pInput = pSystem->GetIInput();
|
|
|
|
Vec3 vMoveDir2 = pInput->JoyGetAnalog1Dir(0);
|
|
if (GetLengthSquared(vMoveDir2) > 0.01f)
|
|
{
|
|
if (vMoveDir2.y < -0.1f)
|
|
epc.AddAction(ACTION_MOVE_FORWARD);
|
|
else if (vMoveDir2.y > 0.1f)
|
|
epc.AddAction(ACTION_MOVE_BACKWARD);
|
|
}
|
|
Vec3 vControllerDir = pInput->JoyGetAnalog2Dir(0);
|
|
Ang3 vAngles = entity.GetAngles();
|
|
|
|
if (fabs(vMoveDir2.x) > 0.1)
|
|
vAngles.z -= vMoveDir2.x*4.0f;
|
|
|
|
epc.SetDeltaAngles(Vec3(0, 0, vAngles.z));
|
|
}
|
|
|
|
player.ProcessCmd(0, epc); // first parameter is not used
|
|
player.ProcessAngles(epc);
|
|
} |