📄 rotatingdoor.cpp
字号:
// ----------------------------------------------------------------------- //
//
// MODULE : RotatingDoor.CPP
//
// PURPOSE : A RotatingDoor object
//
// CREATED : 12/3/97
//
// ----------------------------------------------------------------------- //
// Includes...
#include "RotatingDoor.h"
#include "ObjectUtilities.h"
#include "SoundTypes.h"
BEGIN_CLASS(RotatingDoor)
ADD_REALPROP_FLAG(MoveDist, 0.0f, PF_HIDDEN) // hide some of our
ADD_VECTORPROP_FLAG(MoveDir, PF_HIDDEN) // parent's properties
ADD_VECTORPROP_FLAG(RotationPoint, 0) // point to rotate around
ADD_VECTORPROP_FLAG(RotationAngles, 0) // where to rotate to
ADD_BOOLPROP(BoxPhysics, DFALSE) // Door does NOT use "box physics"
ADD_BOOLPROP(PushPlayerBack, DTRUE)
END_CLASS_DEFAULT(RotatingDoor, Door, NULL, NULL)
// ----------------------------------------------------------------------- //
//
// ROUTINE: RotatingDoor::RotatingDoor()
//
// PURPOSE: Initialize object
//
// ----------------------------------------------------------------------- //
RotatingDoor::RotatingDoor() : Door()
{
VEC_INIT(m_vRotationPoint);
VEC_INIT(m_vRotationAngles);
VEC_INIT(m_vOpenAngles);
VEC_INIT(m_vClosedAngles);
VEC_INIT(m_vOriginalPos);
m_nOpenDirX = 0;
m_nOpenDirY = 0;
m_nOpenDirZ = 0;
m_fPitch = 0.0f;
m_fYaw = 0.0f;
m_fRoll = 0.0f;
m_bPushPlayerBack = DTRUE;
}
// --------------------------------------------------------------------------- //
//
// ROUTINE: RotatingDoor::EngineMessageFn()
//
// PURPOSE: Handler for engine messages
//
// --------------------------------------------------------------------------- //
DDWORD RotatingDoor::EngineMessageFn(DDWORD messageID, void *pData, float fData)
{
switch (messageID)
{
case MID_PRECREATE:
{
// Need to call base class to have the object name read in before
// we call PostPropRead()
DDWORD dwRet = Door::EngineMessageFn(messageID, pData, fData);
if (fData == PRECREATE_WORLDFILE || fData == PRECREATE_STRINGPROP)
{
ReadProp((ObjectCreateStruct*)pData);
}
// Convert speeds from degrees to radians
m_fSpeed = MATH_DEGREES_TO_RADIANS(m_fSpeed);
m_fClosingSpeed = MATH_DEGREES_TO_RADIANS(m_fClosingSpeed);
return dwRet;
}
case MID_INITIALUPDATE:
{
if (fData != INITIALUPDATE_SAVEGAME)
InitialUpdate();
break;
}
case MID_SAVEOBJECT:
Save((HMESSAGEWRITE)pData, (DDWORD)fData);
break;
case MID_LOADOBJECT:
Load((HMESSAGEREAD)pData, (DDWORD)fData);
break;
default : break;
}
return Door::EngineMessageFn(messageID, pData, fData);
}
// --------------------------------------------------------------------------- //
//
// ROUTINE: RotatingDoor::ReadProp()
//
// PURPOSE: Reads RotatingDoor properties
//
// --------------------------------------------------------------------------- //
DBOOL RotatingDoor::ReadProp(ObjectCreateStruct *)
{
CServerDE* pServerDE = GetServerDE();
if (!pServerDE) return DFALSE;
GenericProp genProp;
if (g_pServerDE->GetPropGeneric("RotationAngles", &genProp) == DE_OK)
{
VEC_COPY(m_vRotationAngles, genProp.m_Vec);
}
if (g_pServerDE->GetPropGeneric("RotationPoint", &genProp) == DE_OK)
{
VEC_COPY(m_vRotationPoint, genProp.m_Vec);
}
DVector vTemp;
pServerDE->GetPropRotationEuler("Rotation", &vTemp);
m_fPitch = vTemp.x;
m_fYaw = vTemp.y;
m_fRoll = vTemp.z;
if (g_pServerDE->GetPropGeneric("PushPlayerBack", &genProp) == DE_OK)
{
m_bPushPlayerBack = genProp.m_Bool;
}
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: RotatingDoor::InitialUpdate()
//
// PURPOSE: First update
//
// ----------------------------------------------------------------------- //
void RotatingDoor::InitialUpdate()
{
CServerDE* pServerDE = GetServerDE();
if (!pServerDE) return;
// Set open/closed angle...
VEC_SET(m_vClosedAngles, m_fPitch, m_fYaw, m_fRoll);
m_vOpenAngles.x = DEG2RAD(m_vRotationAngles.x) + m_fPitch;
m_vOpenAngles.y = DEG2RAD(m_vRotationAngles.y) + m_fYaw;
m_vOpenAngles.z = DEG2RAD(m_vRotationAngles.z) + m_fRoll;
// Save the object's original position...
pServerDE->GetObjectPos(m_hObject, &m_vOriginalPos);
// The door must rotate at least 1 degree...
const DFLOAT c_fMinDelta = DEG2RAD(1.0f);
// Determine direction to open door in X...
DFLOAT fOffset = m_vClosedAngles.x - m_vOpenAngles.x;
if (fOffset > c_fMinDelta)
{
m_nOpenDirX = -1;
}
else if (fOffset < c_fMinDelta)
{
m_nOpenDirX = 1;
}
// Determine direction to open door in Y...
fOffset = m_vClosedAngles.y - m_vOpenAngles.y;
if (fOffset > c_fMinDelta)
{
m_nOpenDirY = -1;
}
else if (fOffset < c_fMinDelta)
{
m_nOpenDirY = 1;
}
// Determine direction to open door in Z...
fOffset = m_vClosedAngles.z - m_vOpenAngles.z;
if (fOffset > c_fMinDelta)
{
m_nOpenDirZ = -1;
}
else if (fOffset < c_fMinDelta)
{
m_nOpenDirZ = 1;
}
if (m_bPushPlayerBack)
pServerDE->SetForceIgnoreLimit(m_hObject, 0.0f);
}
// --------------------------------------------------------------------------- //
//
// ROUTINE: RotatingDoor::Opening()
//
// PURPOSE: Handles the RotatingDoor opening state
//
// --------------------------------------------------------------------------- //
void RotatingDoor::Opening()
{
CServerDE* pServerDE = GetServerDE();
if (!pServerDE) return;
if (!m_bStartedMoving)
{
m_bStartedMoving = DTRUE;
StartSound(m_hstrOpenBusySound, DTRUE);
SetPortalState(DTRUE);
}
DBOOL bDoneInX = DFALSE;
DBOOL bDoneInY = DFALSE;
DBOOL bDoneInZ = DFALSE;
// Keep track of current rotation and position in case the door is blocked
DRotation rCurRot;
DVector vCurPos;
pServerDE->GetObjectRotation(m_hObject, &rCurRot);
pServerDE->GetObjectPos(m_hObject, &vCurPos);
DFLOAT fLastPitch = m_fPitch;
DFLOAT fLastYaw = m_fYaw;
DFLOAT fLastRoll = m_fRoll;
// Calculate new pitch, yaw, and roll...
bDoneInX = CalcAngle(m_fPitch, m_vClosedAngles.x, m_vOpenAngles.x, m_nOpenDirX, m_fSpeed);
bDoneInY = CalcAngle(m_fYaw, m_vClosedAngles.y, m_vOpenAngles.y, m_nOpenDirY, m_fSpeed);
bDoneInZ = CalcAngle(m_fRoll, m_vClosedAngles.z, m_vOpenAngles.z, m_nOpenDirZ, m_fSpeed);
// Rotate the object...
DoRotation();
if (m_bDoorBlocked)
{
pServerDE->SetObjectRotation(m_hObject, &rCurRot);
pServerDE->MoveObject(m_hObject, &vCurPos);
m_fPitch = fLastPitch;
m_fYaw = fLastYaw;
m_fRoll = fLastRoll;
}
else if (bDoneInX && bDoneInY && bDoneInZ)
{
if (m_hstrOpenStopSound)
{
PlaySoundFromObject(m_hObject, pServerDE->GetStringData(m_hstrOpenStopSound), 1000, SOUNDPRIORITY_MISC_MEDIUM);
}
SetOpen();
}
}
// --------------------------------------------------------------------------- //
//
// ROUTINE: RotatingDoor::Closing()
//
// PURPOSE: Handles the RotatingDoor closing state
//
// --------------------------------------------------------------------------- //
void RotatingDoor::Closing()
{
CServerDE* pServerDE = GetServerDE();
if (!pServerDE) return;
DBOOL bDoneInX = DFALSE;
DBOOL bDoneInY = DFALSE;
DBOOL bDoneInZ = DFALSE;
// Keep track of current rotation and position in case the door is blocked
DRotation rCurRot;
DVector vCurPos;
pServerDE->GetObjectRotation(m_hObject, &rCurRot);
pServerDE->GetObjectPos(m_hObject, &vCurPos);
DFLOAT fLastPitch = m_fPitch;
DFLOAT fLastYaw = m_fYaw;
DFLOAT fLastRoll = m_fRoll;
// Calculate new pitch, yaw, and roll...
bDoneInX = CalcAngle(m_fPitch, m_vOpenAngles.x, m_vClosedAngles.x, -m_nOpenDirX, m_fClosingSpeed);
bDoneInY = CalcAngle(m_fYaw, m_vOpenAngles.y, m_vClosedAngles.y, -m_nOpenDirY, m_fClosingSpeed);
bDoneInZ = CalcAngle(m_fRoll, m_vOpenAngles.z, m_vClosedAngles.z, -m_nOpenDirZ, m_fClosingSpeed);
// Rotate the object...
DoRotation();
if (m_bDoorBlocked)
{
pServerDE->SetObjectRotation(m_hObject, &rCurRot);
pServerDE->MoveObject(m_hObject, &vCurPos);
m_fPitch = fLastPitch;
m_fYaw = fLastYaw;
m_fRoll = fLastRoll;
}
else if (bDoneInX && bDoneInY && bDoneInZ)
{
if (m_hstrCloseStopSound)
{
PlaySoundFromObject(m_hObject, pServerDE->GetStringData(m_hstrCloseStopSound), 1000, SOUNDPRIORITY_MISC_MEDIUM);
}
SetClosed();
}
}
// --------------------------------------------------------------------------- //
//
// ROUTINE: RotatingDoor::DoRotation()
//
// PURPOSE: Do the rotation calculation based on the current values of
// m_fPitch, m_fYaw, and m_fRoll
//
// --------------------------------------------------------------------------- //
void RotatingDoor::DoRotation()
{
CServerDE* pServerDE = GetServerDE();
if (!pServerDE) return;
DVector vDes, vPoint, vPos;
pServerDE->GetObjectPos(m_hObject, &vPos);
DRotation rRot;
pServerDE->SetupEuler(&rRot, m_fPitch, m_fYaw, m_fRoll);
VEC_SUB(vPoint, m_vOriginalPos, m_vRotationPoint);
DMatrix mat;
pServerDE->SetupRotationMatrix(&mat, &rRot);
MatVMul_H(&vDes, &mat, &vPoint);
DVector vOriginTranslation;
VEC_SUB(vOriginTranslation, vDes, vPoint);
VEC_ADD(vPos, m_vOriginalPos, vOriginTranslation);
// Set the object's new rotation and position...
pServerDE->RotateObject(m_hObject, &rRot);
pServerDE->MoveObject(m_hObject, &vPos);
}
// --------------------------------------------------------------------------- //
//
// ROUTINE: RotatingDoor::CalcAngle()
//
// PURPOSE: Calculate the new value of fAngle
//
// --------------------------------------------------------------------------- //
DBOOL RotatingDoor::CalcAngle(DFLOAT & fAngle, DFLOAT fInitial, DFLOAT fTarget, int nDir, DFLOAT fSpeed)
{
CServerDE* pServerDE = GetServerDE();
if (!pServerDE) return DFALSE;
DBOOL bRet = DFALSE; // Are we at the target angle?
DFLOAT fPercent = 1.0f - (fTarget - fAngle) / (fTarget - fInitial);
DFLOAT fAmount = GetWaveValue(fSpeed, fPercent, m_dwWaveform) * pServerDE->GetFrameTime();
// Calculate percentage moved so far
if (nDir != 0)
{
if (nDir > 0)
{
if (fAngle < fTarget)
{
fAngle += fAmount;
}
else
{
fAngle = fTarget;
bRet = DTRUE;
}
}
else
{
if (fAngle > fTarget)
{
fAngle -= fAmount;
}
else
{
fAngle = fTarget;
bRet = DTRUE;
}
}
}
if (nDir != 0)
{
if (nDir > 0)
{
if (fAngle < fTarget)
{
fAngle += fAmount;
}
else
{
fAngle = fTarget;
bRet = DTRUE;
}
}
else
{
if (fAngle > fTarget)
{
fAngle -= fAmount;
}
else
{
fAngle = fTarget;
bRet = DTRUE;
}
}
}
else
{
bRet = DTRUE;
}
return bRet;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: RotatingDoor::Save
//
// PURPOSE: Save the object
//
// ----------------------------------------------------------------------- //
void RotatingDoor::Save(HMESSAGEWRITE hWrite, DDWORD dwSaveFlags)
{
CServerDE* pServerDE = GetServerDE();
if (!pServerDE || !hWrite) return;
pServerDE->WriteToMessageVector(hWrite, &m_vRotationAngles);
pServerDE->WriteToMessageVector(hWrite, &m_vRotationPoint);
pServerDE->WriteToMessageVector(hWrite, &m_vOpenAngles);
pServerDE->WriteToMessageVector(hWrite, &m_vClosedAngles);
pServerDE->WriteToMessageVector(hWrite, &m_vOriginalPos);
pServerDE->WriteToMessageDWord(hWrite, m_nOpenDirX);
pServerDE->WriteToMessageDWord(hWrite, m_nOpenDirY);
pServerDE->WriteToMessageDWord(hWrite, m_nOpenDirZ);
pServerDE->WriteToMessageFloat(hWrite, m_fPitch);
pServerDE->WriteToMessageFloat(hWrite, m_fYaw);
pServerDE->WriteToMessageFloat(hWrite, m_fRoll);
pServerDE->WriteToMessageByte(hWrite, m_bPushPlayerBack);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: RotatingDoor::Load
//
// PURPOSE: Load the object
//
// ----------------------------------------------------------------------- //
void RotatingDoor::Load(HMESSAGEREAD hRead, DDWORD dwLoadFlags)
{
CServerDE* pServerDE = GetServerDE();
if (!pServerDE || !hRead) return;
pServerDE->ReadFromMessageVector(hRead, &m_vRotationAngles);
pServerDE->ReadFromMessageVector(hRead, &m_vRotationPoint);
pServerDE->ReadFromMessageVector(hRead, &m_vOpenAngles);
pServerDE->ReadFromMessageVector(hRead, &m_vClosedAngles);
pServerDE->ReadFromMessageVector(hRead, &m_vOriginalPos);
m_nOpenDirX = (short)pServerDE->ReadFromMessageDWord(hRead);
m_nOpenDirY = (short)pServerDE->ReadFromMessageDWord(hRead);
m_nOpenDirZ = (short)pServerDE->ReadFromMessageDWord(hRead);
m_fPitch = pServerDE->ReadFromMessageFloat(hRead);
m_fYaw = pServerDE->ReadFromMessageFloat(hRead);
m_fRoll = pServerDE->ReadFromMessageFloat(hRead);
m_bPushPlayerBack = pServerDE->ReadFromMessageByte(hRead);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -