📄 projectile.cpp
字号:
// ----------------------------------------------------------------------- //
//
// MODULE : Projectile.cpp
//
// PURPOSE : Projectile class - implementation
//
// CREATED : 9/25/97
//
// ----------------------------------------------------------------------- //
#include <stdio.h>
#include "Projectile.h"
#include "cpp_engineobjects_de.h"
#include "cpp_server_de.h"
#include "Impacts.h"
#include "generic_msg_de.h"
#include "ClientSmokeTrail.h"
#include "ObjectUtilities.h"
#include "Explosion.h"
#include "ClientSparksSFX.h"
#include "ClientWeaponSFX.h"
#include "ClientExplosionSFX.h"
#include "ClientServerShared.h"
#include "SfxMsgIds.h"
#include <mbstring.h>
#include "SoundTypes.h"
void BPrint(char*);
BEGIN_CLASS(CProjectile)
END_CLASS_DEFAULT_FLAGS(CProjectile, BaseClass, NULL, NULL, CF_HIDDEN)
// ----------------------------------------------------------------------- //
//
// ROUTINE: CProjectile::CProjectile
//
// PURPOSE: Constructor
//
// ----------------------------------------------------------------------- //
CProjectile::CProjectile(DBYTE nType) : BaseClass(nType)
{
AddAggregate(&m_damage);
m_fVelocity = 0.0f;
m_fDamage = 0.0f;
m_nRadius = 0;
m_fLifeTime = 10.0f;
VEC_SET(m_vInitScale, 1.0f, 1.0f, 1.0f);
m_hFiredFrom = DNULL;
m_nDamageType = DAMAGE_TYPE_NORMAL;
m_fStartTime = 0.0f;
m_bExplode = DFALSE;
m_bClientFX = DTRUE;
m_hHitObject = DNULL;
m_fImpactDuration = 1.0f;
m_fImpactScaleMin = 1.0f;
m_fImpactScaleMax = 1.0f;
m_bShockwave = DFALSE;
m_bSparks = DFALSE;
m_bExplosion = DFALSE;
m_fShockwaveDuration = 0.0f;
m_hstrShockwaveFilename = DNULL;
VEC_SET(m_vShockwaveScaleMin, 0.1f, 0.1f, 1.0f);
VEC_SET(m_vShockwaveScaleMax, 1.0f, 1.0f, 1.0f);
m_hLight = NULL;
m_bSmokeTrail = DFALSE;
m_hSmokeTrail = DNULL;
m_pProjectileFilename = DNULL;
m_pProjectileSkin = DNULL;
m_hSound = DNULL;
m_dwClientID = 0;
VEC_SET(m_vDims, 1, 1, 1);
VEC_SET(m_vLightColor, 1, 1, 1);
m_dwFlags = FLAG_VISIBLE | FLAG_TOUCH_NOTIFY | FLAG_REMOVEIFOUTSIDE | FLAG_FORCECLIENTUPDATE;
if (nType == OT_MODEL)
m_dwFlags |= FLAG_SHADOW | FLAG_MODELGOURAUDSHADE | FLAG_RAYHIT;
// Particle trail values
VEC_SET(m_vTrailOffset, 0.0f, 0.0f, 0.0f);
m_fTrailScale = 1.0f;
m_dwTrailScaleFlags = 0;
m_dwTrailFXID = OBJFX_NONE;
m_dwTrailFXFlags = 0;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CProjectile::~CProjectile
//
// PURPOSE: Desctructor
//
// ----------------------------------------------------------------------- //
CProjectile::~CProjectile()
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return;
if (m_hLight)
pServerDE->RemoveObject(m_hLight);
if (m_hSmokeTrail)
pServerDE->RemoveObject(m_hSmokeTrail);
if (m_hstrShockwaveFilename)
pServerDE->FreeString(m_hstrShockwaveFilename);
if (m_hSound)
{ pServerDE->KillSound(m_hSound); m_hSound = DNULL; }
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CProjectile::EngineMessageFn
//
// PURPOSE: Handle engine messages
//
// ----------------------------------------------------------------------- //
DDWORD CProjectile::EngineMessageFn(DDWORD messageID, void *pData, DFLOAT fData)
{
switch(messageID)
{
case MID_UPDATE:
{
if (!Update((DVector *)pData))
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return 0;
pServerDE->RemoveObject(m_hObject);
}
break;
}
case MID_PRECREATE:
{
ObjectCreateStruct *ocs = (ObjectCreateStruct*)pData;
m_dwClientID = ocs->m_UserData;
ocs = DNULL;
DDWORD dwRet = BaseClass::EngineMessageFn(messageID, pData, fData);
if (fData != PRECREATE_SAVEGAME)
PostPropRead((ObjectCreateStruct*)pData);
return dwRet;
}
case MID_INITIALUPDATE:
{
if (fData != INITIALUPDATE_SAVEGAME)
InitialUpdate((DVector *)pData);
break;
}
case MID_TOUCHNOTIFY:
{
HandleTouch((HOBJECT)pData);
break;
}
case MID_LINKBROKEN:
{
HOBJECT hObj = (HOBJECT)pData;
BreakLink(hObj);
break;
}
case MID_SAVEOBJECT:
Save((HMESSAGEWRITE)pData, (DDWORD)fData);
break;
case MID_LOADOBJECT:
Load((HMESSAGEREAD)pData, (DDWORD)fData);
break;
default : break;
}
return BaseClass::EngineMessageFn(messageID, pData, fData);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CProjectile::BreakLink
//
// PURPOSE: Breaks a link of an object
//
// ----------------------------------------------------------------------- //
void CProjectile::BreakLink(HOBJECT hObj)
{
if(m_hHitObject == hObj)
m_hHitObject = DNULL;
else if(m_hFiredFrom == hObj)
m_hFiredFrom = DNULL;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CProjectile::Init
//
// PURPOSE: Initialize a projectile
//
// ----------------------------------------------------------------------- //
void CProjectile::Setup(DVector *vDir, DBYTE nType, DFLOAT fDamage, DFLOAT fVelocity,
int nRadius, HOBJECT hFiredFrom)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return;
VEC_COPY(m_vDir, *vDir);
m_fDamage = fDamage;
m_fVelocity = fVelocity;
m_nRadius = nRadius;
m_hFiredFrom = hFiredFrom;
pServerDE->CreateInterObjectLink( m_hObject, m_hFiredFrom );
m_nWeaponType = nType;
DVector vVel;
VEC_MULSCALAR(vVel, m_vDir, m_fVelocity);
// Set the rotation of the projectile...
DRotation rRot;
pServerDE->AlignRotation(&rRot, &m_vDir, DNULL);
pServerDE->SetObjectRotation(m_hObject, &rRot);
// And away we go...
pServerDE->SetVelocity(m_hObject, &vVel);
pServerDE->SetObjectFlags(m_hObject, m_dwFlags);
// Add smoke trail
if (m_bSmokeTrail) AddSmokeTrail(vVel);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: PostPropRead()
//
// PURPOSE: Update properties
//
// ----------------------------------------------------------------------- //
void CProjectile::PostPropRead(ObjectCreateStruct *pStruct)
{
if (!pStruct) return;
if (m_pProjectileFilename)
_mbscpy((unsigned char*)pStruct->m_Filename, (const unsigned char*)m_pProjectileFilename);
else
_mbscpy((unsigned char*)pStruct->m_Filename, (const unsigned char*)"Models\\Ammo\\Grenade.abc");
if (m_pProjectileSkin)
_mbscpy((unsigned char*)pStruct->m_SkinName, (const unsigned char*)m_pProjectileSkin);
else
_mbscpy((unsigned char*)pStruct->m_SkinName, (const unsigned char*)"Skins\\Ammo\\Grenade.dtx");
pStruct->m_NextUpdate = 0.001f;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CProjectile::InitialUpdate()
//
// PURPOSE: Do first update
//
// ----------------------------------------------------------------------- //
DBOOL CProjectile::InitialUpdate(DVector*)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return DFALSE;
pServerDE->SetNextUpdate(m_hObject, (DFLOAT)0.001);
m_fStartTime = pServerDE->GetTime();
pServerDE->SetObjectDims(m_hObject, &m_vDims);
pServerDE->SetForceIgnoreLimit(m_hObject, 0.0f);
pServerDE->SetFrictionCoefficient(m_hObject, 18.0);
pServerDE->ScaleObject(m_hObject, &m_vInitScale);
// Initialize damage
m_damage.Init(m_hObject);
m_damage.SetHitPoints(5.0f); // A minor number of hitpoints
m_damage.SetApplyDamagePhysics(DFALSE);
// Mark this object as savable
DDWORD dwFlags = pServerDE->GetObjectUserFlags(m_hObject);
dwFlags |= USRFLG_SAVEABLE | USRFLG_SINGULARITY_ATTRACT;
pServerDE->SetObjectUserFlags(m_hObject, dwFlags);
// Create a particle trail
if(m_dwTrailFXID)
{
HMESSAGEWRITE hMessage = pServerDE->StartSpecialEffectMessage(this);
pServerDE->WriteToMessageByte(hMessage, SFX_OBJECTFX_ID);
pServerDE->WriteToMessageObject(hMessage, m_hObject);
pServerDE->WriteToMessageVector(hMessage, &m_vTrailOffset);
pServerDE->WriteToMessageFloat(hMessage, m_fTrailScale);
pServerDE->WriteToMessageDWord(hMessage, m_dwTrailScaleFlags);
pServerDE->WriteToMessageDWord(hMessage, m_dwTrailFXID);
pServerDE->WriteToMessageDWord(hMessage, m_dwTrailFXFlags);
pServerDE->EndMessage2(hMessage, MESSAGE_GUARANTEED);
}
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CProjectile::Update()
//
// PURPOSE: Do update
//
// ----------------------------------------------------------------------- //
DBOOL CProjectile::Update(DVector *pMovement)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE) return DFALSE;
pServerDE->SetNextUpdate(m_hObject, (DFLOAT)0.001);
// pServerDE->BPrint("hit points %f", m_damage.GetHitPoints());
if (m_bExplode || m_damage.IsDead())
{
Explode();
return DFALSE;
}
if (m_fLifeTime > 0)
{
DFLOAT fTime = pServerDE->GetTime();
if(fTime > (m_fStartTime + m_fLifeTime))
{
return DFALSE;
}
}
DVector vVel, vPos;
pServerDE->GetVelocity(m_hObject, &vVel);
pServerDE->GetObjectPos(m_hObject, &vPos);
if (m_hSmokeTrail)
{
pServerDE->SetObjectPos(m_hSmokeTrail, &vPos);
}
if (m_hLight)
{
pServerDE->SetObjectPos(m_hLight, &vPos);
}
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CProjectile::HandleTouch()
//
// PURPOSE: Handle touch notify message
//
// ----------------------------------------------------------------------- //
void CProjectile::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;
// return if it hit another of this same class
if (pServerDE->GetObjectClass(hObj) == pServerDE->GetObjectClass(m_hObject))
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;
}
}
m_bExplode = DTRUE;
m_hHitObject = hObj;
// GK 8/4/98
// Keep a link to this object in case it blows up for some reason (so m_hHitObject is never invalid)
pServerDE->CreateInterObjectLink(m_hObject, hObj);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CProjectile::Explode()
//
// PURPOSE: Creates the impact and does damage
//
// ----------------------------------------------------------------------- //
void CProjectile::Explode()
{
if (!g_pServerDE) return;
DVector vPos;
g_pServerDE->GetObjectPos(m_hObject, &vPos);
AddImpact(vPos, vPos, m_hHitObject);
if(m_nRadius)
{
DamageObjectsWithinRadius();
}
else if (m_hHitObject)
{
// Send damage message to object...
DamageObject(m_hFiredFrom, this, m_hHitObject, m_fDamage, m_vDir, vPos, m_nDamageType);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -