⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 projectile.cpp

📁 Blood 2全套源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// ----------------------------------------------------------------------- //
//
// 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 + -