📄 gameprojectiles.cpp
字号:
// ----------------------------------------------------------------------- //
//
// MODULE : GameProjectile.cpp
//
// PURPOSE : Game Projectile classs - implementation
//
// CREATED : 10/3/97
//
// ----------------------------------------------------------------------- //
#include "GameProjectiles.h"
#include "cpp_server_de.h"
#include "SharedDefs.h"
#include "ObjectUtilities.h"
#include "ClientSparksSFX.h"
#include "VolumeBrushTypes.h"
#include "Gib.h"
#include "ClientServerShared.h"
#include "ClientExplosionSFX.h"
#include "SFXMsgIds.h"
#include "destructable.h"
#include "PlayerObj.h"
#include "zealotai.h"
#include "stdio.h"
void BPrint(char*);
BEGIN_CLASS(CGrenade)
END_CLASS_DEFAULT_FLAGS(CGrenade, CProjectile, NULL, NULL, CF_HIDDEN)
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGrenade::CGrenade()
//
// PURPOSE: Constructor
//
// ----------------------------------------------------------------------- //
CGrenade::CGrenade() : CProjectile()
{
m_bShockwave = DFALSE;
m_bExplosion = DTRUE;
m_fLifeTime = 3.0f;
m_pProjectileFilename = "Models\\Ammo\\Grenade.abc";
m_pProjectileSkin = "Skins\\Ammo\\Grenade.dtx";
m_nDamageType = DAMAGE_TYPE_EXPLODE;
VEC_SET(m_vShockwaveScaleMin, 0.1f, 0.1f, 0.0f);
VEC_SET(m_vShockwaveScaleMax, 2.0f, 2.0f, 0.0f);
m_dwFlags = m_dwFlags | FLAG_GRAVITY;
// Set up angular velocities
m_fPitchVel = m_fYawVel = 0.0f;
m_fPitch = m_fYaw = 0.0f;
m_nBounceCount = 5;
m_hSound = 0;
m_dwTrailFXID = OBJFX_SMOKETRAIL_1;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGrenade::Update()
//
// PURPOSE: Do update
//
// ----------------------------------------------------------------------- //
DBOOL CGrenade::Update(DVector *pMovement)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return DFALSE;
// Play a sound if we don't have one playing already
if(!m_hSound)
m_hSound = PlaySoundFromObject(m_hObject, "Sounds\\Weapons\\assault\\projectile.wav", 600.0f,
SOUNDPRIORITY_MISC_MEDIUM, DTRUE, DTRUE, DFALSE, 100, DFALSE, DFALSE);
// Save position for bounce calculations
pServerDE->GetObjectPos(m_hObject, &m_LastPos);
DBOOL bRet = CProjectile::Update(pMovement);
DVector vVel;
DRotation rRot;
pServerDE->GetVelocity( m_hObject ,&vVel );
pServerDE->GetObjectRotation( m_hObject, &rRot );
// If velocity slows enough, just stop bouncing and just wait to expire.
if (VEC_MAG(vVel) < 5.0)
{
m_fPitchVel = 0;
m_fYawVel = 0;
// Stop the spinning
pServerDE->SetupEuler(&rRot, 0, m_fYaw, 0);
pServerDE->SetObjectRotation(m_hObject, &rRot);
}
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);
}
}
// We've expired, explode now if we're a grenade.
if (!bRet && m_dwFlags & FLAG_GRAVITY || m_damage.IsDead())
{
if(m_hSound)
{ pServerDE->KillSound(m_hSound); m_hSound = 0; }
Explode();
}
return bRet;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGrenade::HandleTouch()
//
// PURPOSE: Handle touch notify message
//
// ----------------------------------------------------------------------- //
void CGrenade::HandleTouch(HOBJECT hObj)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return;
if ((m_nBounceCount == 5) && pServerDE->IsKindOf(pServerDE->GetObjectClass(hObj), pServerDE->GetClass("CBaseCharacter")))
{
CBaseCharacter *pObj = (CBaseCharacter*)pServerDE->HandleToObject(hObj);
if(pObj->IsDead()) return;
CProjectile::HandleTouch(hObj); // Explode on impact type.
}
else // Gravity on, so it's a regular grenade.. bounce it off of stuff
{
if (hObj == m_hFiredFrom) return; // Let it get out of our bounding box...
// return if it hit a non solid object
if (hObj != pServerDE->GetWorldObject() && !(pServerDE->GetObjectFlags(hObj) & FLAG_SOLID)) // Ignore non-solid objects
return;
if (m_nBounceCount <= 0) return;
// Cast a ray from our last known position to see what we hit
DVector vVel, vPos;
pServerDE->GetVelocity(m_hObject, &vVel);
pServerDE->GetObjectPos( m_hObject, &vPos );
CollisionInfo colInfo;
pServerDE->GetLastCollision( &colInfo );
// Compute new velocity reflected off of the surface.
DVector vNormal;
if( colInfo.m_hPoly )
{
VEC_COPY(vNormal, colInfo.m_Plane.m_Normal);
DFLOAT r = ( VEC_DOT(vVel, vNormal) * 0.3f );
VEC_MULSCALAR(vNormal, vNormal, r);
// Play a bounce sound...
PlaySoundFromObject(m_hObject, "Sounds\\Weapons\\assault\\altbounce.wav", 750, SOUNDPRIORITY_MISC_MEDIUM);
VEC_SUB(vVel, vVel, vNormal);
// Adjust the bouncing..
m_fPitchVel = pServerDE->Random(-MATH_CIRCLE, MATH_CIRCLE);
m_fYawVel = pServerDE->Random(-MATH_CIRCLE, MATH_CIRCLE);
VEC_MULSCALAR(vVel, vVel, 0.5f); // Lose some energy in the bounce.
pServerDE->SetVelocity(m_hObject, &vVel);
}
else
{
VEC_INIT( vVel );
pServerDE->SetVelocity( m_hObject, &vVel );
// Play a bounce sound...
PlaySoundFromObject(m_hObject, "Sounds\\Weapons\\assault\\altbounce.wav", 750, SOUNDPRIORITY_MISC_MEDIUM);
}
m_nBounceCount--;
}
}
#ifdef _ADD_ON
BEGIN_CLASS(CGasGrenade)
END_CLASS_DEFAULT_FLAGS(CGasGrenade, CProjectile, NULL, NULL, CF_HIDDEN)
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGasGrenade::CGasGrenade()
//
// PURPOSE: Constructor
//
// ----------------------------------------------------------------------- //
CGasGrenade::CGasGrenade() : CProjectile()
{
m_bShockwave = DFALSE;
m_bExplosion = DTRUE;
m_fLifeTime = 3.0f;
m_pProjectileFilename = "Models\\Ammo\\Grenade.abc";
m_pProjectileSkin = "Skins\\Ammo\\Grenade.dtx";
m_nDamageType = DAMAGE_TYPE_EXPLODE;
VEC_SET(m_vShockwaveScaleMin, 0.1f, 0.1f, 0.0f);
VEC_SET(m_vShockwaveScaleMax, 2.0f, 2.0f, 0.0f);
m_dwFlags = m_dwFlags | FLAG_GRAVITY;
// Set up angular velocities
m_fPitchVel = m_fYawVel = 0.0f;
m_fPitch = m_fYaw = 0.0f;
m_nBounceCount = 5;
m_bSmoking = DFALSE;
m_fSmokeTime = 0.0f;
m_hSound = 0;
m_dwTrailFXID = OBJFX_GREEN_SMOKE;
m_fLastWonkyTime = 0.0f;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGasGrenade::Update()
//
// PURPOSE: Do update
//
// ----------------------------------------------------------------------- //
DBOOL CGasGrenade::Update(DVector *pMovement)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return DFALSE;
// Play a sound if we don't have one playing already
if(!m_hSound && !m_bSmoking)
m_hSound = PlaySoundFromObject(m_hObject, "Sounds\\Weapons\\assault\\projectile.wav", 600.0f, SOUNDPRIORITY_MISC_MEDIUM, DTRUE, DTRUE, DFALSE, 100, DFALSE, DFALSE);
// See if we should blow up yet...
pServerDE->SetNextUpdate(m_hObject, (DFLOAT)0.001);
// Damage anyone who gets close to the smoke and give them wonky vision
// **** NOTE: THIS MUST BE BEFORE THE NEXT TWO CHECKS ****
if(m_bSmoking)
{
DFLOAT fTime = pServerDE->GetTime();
if(fTime > (m_fSmokeTime + GAS_GRENADE_SMOKE_TIME))
return DFALSE;
if(fTime > (m_fLastWonkyTime + GAS_GRENADE_DAMAGE_DELAY))
{
m_fLastWonkyTime = fTime;
DamageAndWonky(WONKY_VISION_DEFAULT_TIME);
}
return DTRUE;
}
if((m_fLifeTime > 0) && (pServerDE->GetTime() > (m_fStartTime + m_fLifeTime)))
m_bExplode = DTRUE;
if(m_bExplode || m_damage.IsDead())
{
if(m_hSound)
{ pServerDE->KillSound(m_hSound); m_hSound = 0; }
m_bSmoking = DTRUE;
m_fSmokeTime = pServerDE->GetTime();
Explode();
// Turn off the gravity for the object and make it invisible
DDWORD dwFlags = pServerDE->GetObjectFlags(m_hObject);
dwFlags &= ~(FLAG_GRAVITY | FLAG_VISIBLE);
pServerDE->SetObjectFlags(m_hObject, dwFlags);
// Stop the object in its current position
DVector vVel;
VEC_INIT(vVel);
pServerDE->SetVelocity( m_hObject, &vVel );
}
// Save position for bounce calculations
pServerDE->GetObjectPos(m_hObject, &m_LastPos);
DBOOL bRet = CProjectile::Update(pMovement);
DVector vVel;
DRotation rRot;
pServerDE->GetVelocity( m_hObject ,&vVel );
pServerDE->GetObjectRotation( m_hObject, &rRot );
// If velocity slows enough, just stop bouncing and just wait to expire.
if (VEC_MAG(vVel) < 5.0)
{
m_fPitchVel = 0;
m_fYawVel = 0;
// Stop the spinning
pServerDE->SetupEuler(&rRot, 0, m_fYaw, 0);
pServerDE->SetObjectRotation(m_hObject, &rRot);
}
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);
}
}
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGasGrenade::HandleTouch()
//
// PURPOSE: Handle touch notify message
//
// ----------------------------------------------------------------------- //
void CGasGrenade::HandleTouch(HOBJECT hObj)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return;
if (hObj == m_hFiredFrom) return; // Let it get out of our bounding box...
// return if it hit a non solid object
if (hObj != pServerDE->GetWorldObject() && !(pServerDE->GetObjectFlags(hObj) & FLAG_SOLID)) // Ignore non-solid objects
return;
// See if we hit the sky...
HCLASS hClassObj = pServerDE->GetObjectClass(hObj);
HCLASS hClassWorld = pServerDE->GetObjectClass(pServerDE->GetWorldObject());
if (pServerDE->IsKindOf(hClassObj, hClassWorld))
{
CollisionInfo info;
pServerDE->GetLastCollision(&info);
SurfaceType eType = GetSurfaceType(info.m_hObject, info.m_hPoly);
if (eType == SURFTYPE_SKY)
{
pServerDE->RemoveObject(m_hObject);
return;
}
}
// Handle the special case of directly hitting a base character in mid air
if ((m_nBounceCount == 5) && pServerDE->IsKindOf(pServerDE->GetObjectClass(hObj), pServerDE->GetClass("CBaseCharacter")))
{
CBaseCharacter *pObj = (CBaseCharacter*)pServerDE->HandleToObject(hObj);
if(pObj->IsDead()) return;
m_bExplode = DTRUE;
m_hHitObject = hObj;
}
else // Gravity on, so it's a regular grenade.. bounce it off of stuff
{
if (m_nBounceCount <= 0) return;
// Cast a ray from our last known position to see what we hit
DVector vVel, vPos;
pServerDE->GetVelocity(m_hObject, &vVel);
pServerDE->GetObjectPos( m_hObject, &vPos );
CollisionInfo colInfo;
pServerDE->GetLastCollision( &colInfo );
// Compute new velocity reflected off of the surface.
DVector vNormal;
if( colInfo.m_hPoly )
{
VEC_COPY(vNormal, colInfo.m_Plane.m_Normal);
DFLOAT r = ( VEC_DOT(vVel, vNormal) * 0.3f );
VEC_MULSCALAR(vNormal, vNormal, r);
// Play a bounce sound...
PlaySoundFromObject(m_hObject, "Sounds\\Weapons\\assault\\altbounce.wav", 750, SOUNDPRIORITY_MISC_MEDIUM);
VEC_SUB(vVel, vVel, vNormal);
// Adjust the bouncing..
m_fPitchVel = pServerDE->Random(-MATH_CIRCLE, MATH_CIRCLE);
m_fYawVel = pServerDE->Random(-MATH_CIRCLE, MATH_CIRCLE);
VEC_MULSCALAR(vVel, vVel, 0.5f); // Lose some energy in the bounce.
pServerDE->SetVelocity(m_hObject, &vVel);
}
else
{
VEC_INIT( vVel );
pServerDE->SetVelocity( m_hObject, &vVel );
// Play a bounce sound...
PlaySoundFromObject(m_hObject, "Sounds\\Weapons\\assault\\altbounce.wav", 750, SOUNDPRIORITY_MISC_MEDIUM);
}
m_nBounceCount--;
}
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGasGrenade::AddExplosion()
//
// PURPOSE: Add an explosion
//
// ----------------------------------------------------------------------- //
void CGasGrenade::AddExplosion(DVector vPos, DVector vNormal)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return;
DDWORD nType = EXP_GAS_GRENADE;
DVector vUp;
VEC_SET(vUp, 0.0f, 1.0f, 0.0f);
HMESSAGEWRITE hMessage = pServerDE->StartInstantSpecialEffectMessage(&vPos);
pServerDE->WriteToMessageByte(hMessage, SFX_EXPLOSIONFX_ID);
pServerDE->WriteToMessageVector(hMessage, &vPos);
pServerDE->WriteToMessageVector(hMessage, &vUp);
pServerDE->WriteToMessageDWord(hMessage, nType);
pServerDE->EndMessage2(hMessage, MESSAGE_GUARANTEED);
PlaySoundFromPos(&vPos, "Sounds\\Weapons\\c4\\explosion_1.wav", 1000.0f, SOUNDPRIORITY_MISC_MEDIUM);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -