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

📄 spawner.cpp

📁 Blood 2全套源码
💻 CPP
字号:
// ----------------------------------------------------------------------- //
//
// MODULE  : Spawner.cpp
//
// PURPOSE : Spawner class - implementation
//
// CREATED : 6/24/98
//
// ----------------------------------------------------------------------- //

#include "cpp_server_de.h"
#include "ObjectUtilities.h"
#include "Spawner.h"
#include "SFXMsgIds.h"
#include "ClientServerShared.h"
#include <mbstring.h>
#include "SoundTypes.h"


BEGIN_CLASS(Spawner)
	ADD_STRINGPROP(SpawnObject, "")
	ADD_VECTORPROP_VAL(MinVelocity, 0, 500, 0)
	ADD_VECTORPROP_VAL(MaxVelocity, 0, 500, 0)
	ADD_STRINGPROP(Sound, "")
	ADD_REALPROP(SoundRadius, 500.0f)
	ADD_BOOLPROP(UseTriggerObjPos, DTRUE)
	ADD_BOOLPROP(StartActive, DFALSE)
	ADD_LONGINTPROP(RespawnCount, -1)
	ADD_REALPROP(RespawnRate, 1)
	ADD_BOOLPROP(CreateRiftEffect, DFALSE)
END_CLASS_DEFAULT(Spawner, B2BaseClass, NULL, NULL)


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	Spawner::Spawner
//
//	PURPOSE:	Constructor
//
// ----------------------------------------------------------------------- //

Spawner::Spawner() : B2BaseClass(OT_NORMAL)
{
	VEC_SET(m_vMinVelocity, -100.0f, 400.0f, -100.0f);
	VEC_SET(m_vMaxVelocity, 100.0f, 600.0f, 100.0f);

	m_hstrSpawnObject   = DNULL;
	m_hstrSound			= DNULL;
	m_fSoundRadius		= 500.0f;
	m_bUseTriggerObjPos	= DFALSE;
	m_bStartActive      = DFALSE;
	m_dwRespawnCount    = -1;
	m_fRespawnRate      = 1;
	m_bCreateRiftEffect = DFALSE;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	Spawner::~Spawner
//
//	PURPOSE:	Destructor
//
// ----------------------------------------------------------------------- //

Spawner::~Spawner()
{
	if (m_hstrSpawnObject)
		g_pServerDE->FreeString( m_hstrSpawnObject );

	if( m_hstrSound )
 		g_pServerDE->FreeString( m_hstrSound );
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	Spawner::EngineMessageFn
//
//	PURPOSE:	Handler for engine messages
//
// ----------------------------------------------------------------------- //

DDWORD Spawner::EngineMessageFn(DDWORD messageID, void *pData, DFLOAT fData)
{
	switch(messageID)
	{
		case MID_PRECREATE:
		{
			if (fData == 1.0f)
			{
				ReadProp((ObjectCreateStruct*)pData);
			}

			break;
		}
		case MID_INITIALUPDATE:
		{
			if (m_bStartActive)
			{
				g_pServerDE->SetNextUpdate(m_hObject, m_fRespawnRate);
			}
			else
			{
				g_pServerDE->SetNextUpdate(m_hObject, 0.0f);
			}
			DDWORD dwUsrFlags = g_pServerDE->GetObjectUserFlags(m_hObject);
			g_pServerDE->SetObjectUserFlags(m_hObject, dwUsrFlags | USRFLG_SAVEABLE);

			break;
		}

		case MID_UPDATE:
		{
			Update();
			break;
		}

		case MID_SAVEOBJECT:
			Save((HMESSAGEWRITE)pData, (DDWORD)fData);
			break;

		case MID_LOADOBJECT:
			Load((HMESSAGEREAD)pData, (DDWORD)fData);
			break;

		default : break;
	}


	return B2BaseClass::EngineMessageFn(messageID, pData, fData);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	Spawner::ReadProp
//
//	PURPOSE:	Reads spawner properties
//
// ----------------------------------------------------------------------- //

DBOOL Spawner::ReadProp(ObjectCreateStruct *pStruct)
{
	GenericProp genProp;

	if (g_pServerDE->GetPropGeneric("SpawnObject", &genProp) == DE_OK)
	{
		if (genProp.m_String[0]) m_hstrSpawnObject = g_pServerDE->CreateString(genProp.m_String);
	}

	if (g_pServerDE->GetPropGeneric("MinVelocity", &genProp) == DE_OK)
	{
		VEC_COPY(m_vMinVelocity, genProp.m_Vec)
	}

	if (g_pServerDE->GetPropGeneric("MaxVelocity", &genProp) == DE_OK)
	{
		VEC_COPY(m_vMaxVelocity, genProp.m_Vec)
	}

	if (g_pServerDE->GetPropGeneric("Sound", &genProp) == DE_OK)
	{
		if (genProp.m_String[0]) m_hstrSound = g_pServerDE->CreateString(genProp.m_String);
	}

	if (g_pServerDE->GetPropGeneric("SoundRadius", &genProp) == DE_OK)
	{
		m_fSoundRadius = genProp.m_Float;
	}

	if (g_pServerDE->GetPropGeneric("UseTriggerObjPos", &genProp) == DE_OK)
	{
		m_bUseTriggerObjPos = genProp.m_Bool;
	}

	if (g_pServerDE->GetPropGeneric("StartActive", &genProp) == DE_OK)
	{
		m_bStartActive = genProp.m_Bool;
	}

	if (g_pServerDE->GetPropGeneric("CreateRiftEffect", &genProp) == DE_OK)
	{
		m_bCreateRiftEffect = genProp.m_Bool;
	}

	if (g_pServerDE->GetPropGeneric("RespawnCount", &genProp) == DE_OK)
	{
		m_dwRespawnCount = genProp.m_Long;
	}

	if (g_pServerDE->GetPropGeneric("RespawnRate", &genProp) == DE_OK)
	{
		m_fRespawnRate = genProp.m_Float;
	}

	return DTRUE;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	Spawner::ObjectMessageFn
//
//	PURPOSE:	Handle messages from objects
//
// ----------------------------------------------------------------------- //

DDWORD Spawner::ObjectMessageFn( HOBJECT hSender, DDWORD messageID, HMESSAGEREAD hRead )
{
	switch( messageID )
	{
		case MID_TRIGGER:
		{
			// Read the message's hstring, discard
			HSTRING hMsg = g_pServerDE->ReadFromMessageHString( hRead );

			if (hMsg)
			{
				char* sMsg = g_pServerDE->GetStringData(hMsg);

				// Look for an "activate" message
				if (sMsg)
				{
					if (_mbsicmp((const unsigned char*)sMsg, (const unsigned char*)"START") == 0)
					{
						g_pServerDE->SetNextUpdate(m_hObject, m_fRespawnRate);
						g_pServerDE->FreeString(hMsg);
						return B2BaseClass::ObjectMessageFn(hSender, messageID, hRead);
					}
					else if (_mbsicmp((const unsigned char*)sMsg, (const unsigned char*)"STOP") == 0)
					{
						g_pServerDE->SetNextUpdate(m_hObject, 0);
						g_pServerDE->FreeString(hMsg);
						return B2BaseClass::ObjectMessageFn(hSender, messageID, hRead);
					}
					else if (_mbsicmp((const unsigned char*)sMsg, (const unsigned char*)"SINGLE") == 0)
					{
						if (m_dwRespawnCount > 0)
						{
							m_dwRespawnCount--;
							SpawnObject(NULL);
						}

						g_pServerDE->FreeString(hMsg);
						return B2BaseClass::ObjectMessageFn(hSender, messageID, hRead);
					}
				}

				g_pServerDE->FreeString(hMsg);
			}

			// Spawn the object
			SpawnObject(hSender);

			break;
		}

		default : break;
	}

	return B2BaseClass::ObjectMessageFn(hSender, messageID, hRead);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SpawnObject
//
//	PURPOSE:	Spawns an object of any class
//
// ----------------------------------------------------------------------- //

HOBJECT SpawnObject( char *pszSpawnString, DVector *pvPos, DRotation *prRot, DVector *pvVel )
{
	char *pszObjClass = NULL;

	if( !g_pServerDE || !pszSpawnString )
		return DNULL;

	// Class name should be the first token in the string, validate it
	pszObjClass = strtok( pszSpawnString, " " );
	if( !pszObjClass )	return DNULL;

	HCLASS hClass = g_pServerDE->GetClass( pszObjClass );
	if( !hClass ) return DNULL;

	ObjectCreateStruct ocStruct;
	INIT_OBJECTCREATESTRUCT(ocStruct);

	VEC_COPY( ocStruct.m_Pos, *pvPos );
	ROT_COPY( ocStruct.m_Rotation, *prRot );

	// Remainder of the string could be string props
	pszSpawnString = strtok( NULL, "" );

	// Create the object...
	HOBJECT hObj = DNULL;
	if (BaseClass *pObj = g_pServerDE->CreateObjectProps( hClass, &ocStruct, pszSpawnString ))
		hObj = g_pServerDE->ObjectToHandle(pObj);

	// Set it's initial velocity
	if (hObj && pvVel) 
		g_pServerDE->SetVelocity(hObj, pvVel);

	return hObj;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	Spawner::Update
//
//	PURPOSE:	Handle updating the spawner
//
// ----------------------------------------------------------------------- //

void Spawner::Update()
{
	// Update the respawn counter...

	if (m_dwRespawnCount >= 1)
	{
		m_dwRespawnCount--;
	}


	// Spawn the object...

	SpawnObject(NULL);


	// Set the next update as necessary...

	if (m_dwRespawnCount != 0)
	{
		g_pServerDE->SetNextUpdate(m_hObject, m_fRespawnRate);
	}
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	Spawner::SpawnObject
//
//	PURPOSE:	Spawns an object
//
// ----------------------------------------------------------------------- //

DBOOL Spawner::SpawnObject(HOBJECT hSender)
{
	// Sanity checks
	if (!m_hstrSpawnObject) return(DFALSE);

	// Local variables
	DVector vPos;
	DRotation rRot;
	DVector vVel;

	VEC_INIT(vVel);

	char szSpawn[MAX_GP_STRING_LEN+1];

	szSpawn[0] = '\0';

	if (m_bUseTriggerObjPos && hSender)
	{
		g_pServerDE->GetObjectPos( hSender, &vPos );
		g_pServerDE->GetObjectRotation( hSender, &rRot );
	}
	else
	{
		g_pServerDE->GetObjectPos( m_hObject, &vPos );
		g_pServerDE->GetObjectRotation( m_hObject, &rRot );
	}

	// Now spawn objects specified in the properties
	if (m_hstrSpawnObject)
	{
		char *pString = g_pServerDE->GetStringData(m_hstrSpawnObject);
		if (!pString) return(DFALSE);

		_mbsncpy((unsigned char*)szSpawn, (const unsigned char*)pString, MAX_GP_STRING_LEN);
		DVector vVel;
		vVel.x = g_pServerDE->Random(m_vMinVelocity.x, m_vMaxVelocity.x);
		vVel.y = g_pServerDE->Random(m_vMinVelocity.y, m_vMaxVelocity.y);
		vVel.z = g_pServerDE->Random(m_vMinVelocity.z, m_vMaxVelocity.z);
		::SpawnObject(szSpawn, &vPos, &rRot, &vVel);
	}

	if (m_bCreateRiftEffect)
	{
		DVector		vU, vR, vF;
		g_pServerDE->GetRotationVectors(&rRot, &vU, &vR, &vF);

		HMESSAGEWRITE hMessage = g_pServerDE->StartInstantSpecialEffectMessage(&vPos);
		g_pServerDE->WriteToMessageByte(hMessage, SFX_EXPLOSIONFX_ID);

		g_pServerDE->WriteToMessageVector(hMessage, &vPos);
		g_pServerDE->WriteToMessageVector(hMessage, &vF);
		g_pServerDE->WriteToMessageDWord(hMessage, EXP_RIFT_1);

		g_pServerDE->EndMessage(hMessage);
	}

	// Play spawn sound
	if( m_hstrSound )
	{
		char* pSound = g_pServerDE->GetStringData(m_hstrSound);
		if (pSound)
		{
			PlaySoundFromPos( &vPos, pSound, m_fSoundRadius, SOUNDPRIORITY_MISC_LOW );
		}
	}

	// All done
	return(DTRUE);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	Spawner::Save
//
//	PURPOSE:	Saves the spawner object
//
// ----------------------------------------------------------------------- //

void Spawner::Save(HMESSAGEWRITE hWrite, DDWORD dwSaveFlags)
{
	if (!hWrite) return;

	g_pServerDE->WriteToMessageHString(hWrite, m_hstrSound);
	g_pServerDE->WriteToMessageHString(hWrite, m_hstrSpawnObject);

	g_pServerDE->WriteToMessageVector(hWrite, &m_vMinVelocity);
	g_pServerDE->WriteToMessageVector(hWrite, &m_vMaxVelocity);

	g_pServerDE->WriteToMessageFloat(hWrite, m_fSoundRadius);
	g_pServerDE->WriteToMessageFloat(hWrite, m_fRespawnRate);

	g_pServerDE->WriteToMessageByte(hWrite, m_bUseTriggerObjPos);
	g_pServerDE->WriteToMessageByte(hWrite, m_bStartActive);
	g_pServerDE->WriteToMessageByte(hWrite, m_bCreateRiftEffect);

	g_pServerDE->WriteToMessageDWord(hWrite, m_dwRespawnCount);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	Spawner::Load
//
//	PURPOSE:	Loads the spawner object
//
// ----------------------------------------------------------------------- //

void Spawner::Load(HMESSAGEREAD hRead, DDWORD dwLoadFlags)
{
	if (!hRead) return;

	m_hstrSound       = g_pServerDE->ReadFromMessageHString(hRead);
	m_hstrSpawnObject = g_pServerDE->ReadFromMessageHString(hRead);

	g_pServerDE->ReadFromMessageVector(hRead, &m_vMinVelocity);
	g_pServerDE->ReadFromMessageVector(hRead, &m_vMaxVelocity);

	m_fSoundRadius = g_pServerDE->ReadFromMessageFloat(hRead);
	m_fRespawnRate = g_pServerDE->ReadFromMessageFloat(hRead);

	m_bUseTriggerObjPos = g_pServerDE->ReadFromMessageByte(hRead);
	m_bStartActive      = g_pServerDE->ReadFromMessageByte(hRead);
	m_bCreateRiftEffect = g_pServerDE->ReadFromMessageByte(hRead);

	m_dwRespawnCount = g_pServerDE->ReadFromMessageDWord(hRead);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -