📄 shellcasing.cpp
字号:
//----------------------------------------------------------
//
// MODULE : SHELLCASING.CPP
//
// PURPOSE : defines classes for ejected shells
//
// CREATED : 1/29/98
//
//----------------------------------------------------------
// Includes....
#include <stdio.h>
#include <string.h>
#include "serverobj_de.h"
#include "ShellCasing.h"
#include "cpp_server_de.h"
#include "ObjectUtilities.h"
#include "generic_msg_de.h"
#include "SoundTypes.h"
void BPrint(char *msg);
DLink CShellCasing::m_Head;
DDWORD CShellCasing::m_dwNumShells = 0;
BEGIN_CLASS(CShellCasing)
END_CLASS_DEFAULT_FLAGS(CShellCasing, BaseClass, NULL, NULL, CF_HIDDEN)
// ----------------------------------------------------------------------- //
//
// ROUTINE: CShellCasing::CShellCasing
//
// PURPOSE: Initialize
//
// ----------------------------------------------------------------------- //
CShellCasing::CShellCasing() : BaseClass(OT_MODEL)
{
m_hFiredFrom = 0;
m_fExpireTime = 0.0f;
m_bFiredFromLeft = DFALSE;
m_bInVisible = DTRUE;
if( m_dwNumShells == 0 )
{
dl_TieOff( &m_Head );
}
m_nBounceCount = 2; // Set maximum bounces
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CShellCasing::~CShellCasing
//
// PURPOSE: Destructor
//
// ----------------------------------------------------------------------- //
CShellCasing::~CShellCasing()
{
if( m_Link.m_pData && m_dwNumShells > 0 )
{
dl_Remove( &m_Link );
m_dwNumShells--;
}
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CShellCasing::ObjectMessageFn
//
// PURPOSE: Handle object messages
//
// ----------------------------------------------------------------------- //
DDWORD CShellCasing::ObjectMessageFn(HOBJECT hSender, DDWORD messageID, HMESSAGEREAD hRead)
{
if( g_pServerDE )
{
switch(messageID)
{
case MID_DAMAGE:
{
g_pServerDE->RemoveObject(m_hObject);
break;
}
default: break;
}
}
return BaseClass::ObjectMessageFn (hSender, messageID, hRead);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CShellCasing::EngineMessageFn
//
// PURPOSE: Handle engine messages
//
// ----------------------------------------------------------------------- //
DDWORD CShellCasing::EngineMessageFn(DDWORD messageID, void *pData, DFLOAT lData)
{
switch(messageID)
{
case MID_UPDATE:
{
if (!Update())
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return 0;
pServerDE->RemoveObject(m_hObject);
}
break;
}
case MID_TOUCHNOTIFY:
{
HandleTouch((HOBJECT)pData);
break;
}
case MID_INITIALUPDATE:
{
InitialUpdate();
break;
}
default : break;
}
return BaseClass::EngineMessageFn(messageID, pData, lData);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CShellCasing::Setup
//
// PURPOSE: Set up a shell casing with the information needed
//
// ----------------------------------------------------------------------- //
void CShellCasing::Setup(HOBJECT hFiredFrom)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return;
m_hFiredFrom = hFiredFrom;
// insert it into the list
dl_Insert( &m_Head, &m_Link );
m_Link.m_pData = ( void * )this;
m_dwNumShells++;
// Check if too many marks...
if( m_dwNumShells > MAX_SHELLS )
{
CShellCasing *pShell;
// Delete the oldest mark...
pShell = ( CShellCasing * )m_Head.m_pPrev->m_pData;
if( pShell )
{
// Remove it from linked list...
dl_Remove( m_Head.m_pPrev );
// No data...
pShell->m_Link.m_pData = NULL;
}
m_dwNumShells--;
}
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CShellCasing::InitialUpdate
//
// PURPOSE: Do initial updating
//
// ----------------------------------------------------------------------- //
DBOOL CShellCasing::InitialUpdate()
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE || !m_hObject) return DFALSE;
m_fExpireTime = pServerDE->GetTime() + 20.0f;
pServerDE->SetObjectFlags(m_hObject, /*| FLAG_GRAVITY*/ FLAG_TOUCH_NOTIFY);
m_bInVisible = DTRUE;
pServerDE->SetForceIgnoreLimit(m_hObject, 0.1f);
pServerDE->SetFrictionCoefficient(m_hObject, 18.0);
// Set up angular velocities
// m_fPitchVel = m_fYawVel = 0.0f;
m_fPitchVel = pServerDE->Random(-MATH_CIRCLE * 2, MATH_CIRCLE * 2);
m_fYawVel = pServerDE->Random(-MATH_CIRCLE * 2, MATH_CIRCLE * 2);
m_fPitch = m_fYaw = 0.0f;
pServerDE->SetNextUpdate(m_hObject, (DFLOAT)0.001);
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CShellCasing::Init
//
// PURPOSE: Update the velocity
//
// ----------------------------------------------------------------------- //
void CShellCasing::Init(DBOOL bFiredFromLeft)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE || !m_hObject) return;
m_bFiredFromLeft = bFiredFromLeft;
DRotation rRot;
DVector vU, vR, vF;
pServerDE->GetObjectRotation(m_hObject, &rRot);
pServerDE->GetRotationVectors(&rRot, &vU, &vR, &vF);
DVector vVel;
if(m_bFiredFromLeft)
VEC_NEGATE(vR, vR);
DFLOAT fUpVel = pServerDE->Random(60.0f, 90.0f);
VEC_MULSCALAR(vU, vU, fUpVel);
DFLOAT fRightVel = pServerDE->Random(50.0f, 70.0f);
VEC_MULSCALAR(vR, vR, fRightVel);
DFLOAT fForwardVel = pServerDE->Random(10.0f, 25.0f);
VEC_MULSCALAR(vF, vF, fForwardVel);
VEC_ADD(vVel, vU, vR);
VEC_ADD(vVel, vVel, vF);
pServerDE->SetVelocity(m_hObject, &vVel);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CShellCasing::Update
//
// PURPOSE: Update the impact
//
// ----------------------------------------------------------------------- //
DBOOL CShellCasing::Update()
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE || !m_hObject) return DFALSE;
DFLOAT fTime = pServerDE->GetTime();
if (fTime >= m_fExpireTime)
return DFALSE;
pServerDE->GetObjectPos(m_hObject, &m_vLastPos);
if (m_bInVisible)
{
m_bInVisible = DFALSE;
pServerDE->SetObjectFlags(m_hObject, FLAG_VISIBLE | FLAG_TOUCH_NOTIFY);
}
DVector vVel;
DVector vForce;
DRotation rRot;
pServerDE->GetVelocity(m_hObject, &vVel);
pServerDE->GetObjectRotation(m_hObject, &rRot);
// If the gravity is not turned on... manually move the shell
if(!(pServerDE->GetObjectFlags(m_hObject) & FLAG_GRAVITY))
{
pServerDE->GetGlobalForce(&vForce);
// VEC_NORM(vForce);
VEC_MULSCALAR(vForce, vForce, 0.004f);
VEC_ADD(vVel, vVel, vForce);
pServerDE->SetVelocity(m_hObject, &vVel);
}
// If velocity slows enough, and we're on the ground, just stop bouncing and just wait to expire.
if (VEC_MAG(vVel) < 5.0)
{
// Stop the spinning
pServerDE->SetupEuler(&rRot, 0, m_fYaw, 0);
pServerDE->SetObjectRotation(m_hObject, &rRot);
// Clear touch notify flag
pServerDE->SetObjectFlags(m_hObject, FLAG_VISIBLE | FLAG_GRAVITY);
pServerDE->SetNextUpdate(m_hObject, m_fExpireTime - fTime);
// shell is at rest, we can add a check here to see if we really want
// to keep it around depending on detail settings.
/* ObjectList *ol = pServerDE->FindObjectsTouchingSphere(&m_vLastPos, 40.0f);
int count = 0;
if (ol)
{
ObjectLink* pLink = ol->m_pFirstLink;
while(pLink)
{
count++;
pLink = pLink->m_pNext;
if (count > 20)
break;
}
pServerDE->RelinquishList(ol);
}
if (count > 20)
return DFALSE;*/
}
else
{
if (m_fPitchVel != 0 || m_fYawVel != 0)
{
DFLOAT fDeltaTime = pServerDE->GetFrameTime();
m_fPitch += m_fPitchVel * fDeltaTime;
m_fYaw += m_fYawVel * fDeltaTime;
pServerDE->SetupEuler(&rRot, m_fPitch, m_fYaw, 0.0f);
pServerDE->SetObjectRotation(m_hObject, &rRot);
}
pServerDE->SetNextUpdate(m_hObject, (DFLOAT)0.001);
}
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CShellCasing::HandleTouch()
//
// PURPOSE: Handle touch notify message
//
// ----------------------------------------------------------------------- //
void CShellCasing::HandleTouch(HOBJECT hObj)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE || !m_hObject) return;
// return if it hit a non solid object
if (hObj == m_hFiredFrom || (hObj != pServerDE->GetWorldObject() && !(pServerDE->GetObjectFlags(hObj) & FLAG_SOLID))) // Ignore non-solid objects
return;
// Only bounce so many times..
if (m_nBounceCount <=0)
return;
// Cast a ray from our last known position to see what we hit
IntersectQuery iq;
IntersectInfo ii;
DVector vVel;
pServerDE->GetVelocity(m_hObject, &vVel);
VEC_COPY(iq.m_From, m_vLastPos); // Get start point at the last known position.
VEC_MULSCALAR(iq.m_To, vVel, 1.1f);
VEC_ADD(iq.m_To, iq.m_To, iq.m_From); // Get destination point slightly past where we should be
iq.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID;
iq.m_FilterFn = NULL;
iq.m_pUserData = NULL;
// Hit something!
if (pServerDE->IntersectSegment(&iq, &ii))
{
// Compute new velocity reflected off of the surface.
DVector vNormal;
VEC_COPY(vNormal, ii.m_Plane.m_Normal);
DFLOAT r = VEC_DOT(vVel, vNormal) * 0.3f;
if (r > -100.0f)
r = 0;
else
{
VEC_MULSCALAR(vNormal, vNormal, r);
VEC_SUB(vVel, vVel, vNormal);
// Adjust the bouncing..
m_fPitchVel = pServerDE->Random(-MATH_CIRCLE * 2, MATH_CIRCLE * 2);
m_fYawVel = pServerDE->Random(-MATH_CIRCLE * 2, MATH_CIRCLE * 2);
}
VEC_MULSCALAR(vVel, vVel, 0.6f); // Lose some energy in the bounce.
pServerDE->SetVelocity(m_hObject, &vVel);
m_nBounceCount--;
// Play a bounce sound...
if (m_nBounceCount)
PlaySoundFromObject(m_hObject, "Sounds\\Weapons\\Shelldrop.wav", 150.0f, SOUNDPRIORITY_MISC_MEDIUM, DFALSE, DFALSE, DFALSE, 100);
// Turn on the gravity so the engine can take control of the movement and friction
if(!m_nBounceCount)
pServerDE->SetObjectFlags(m_hObject, FLAG_VISIBLE | FLAG_GRAVITY | FLAG_TOUCH_NOTIFY);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -