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

📄 wreckingball.cpp

📁 Blood 2全套源码
💻 CPP
字号:
//----------------------------------------------------------
//
// MODULE  : WRECKINGBALL.CPP
//
// PURPOSE : A Wrecking ball for the construction level.
//
// CREATED : 3/28/98
//
//----------------------------------------------------------

// Includes....
#include <stdio.h>
#include <string.h>
#include "serverobj_de.h"
#include "WreckingBall.h"
#include "cpp_server_de.h"
#include "ClientCastLineSFX.h"
#include "ObjectUtilities.h"
#include <mbstring.h>

void BPrint(char*);

BEGIN_CLASS(WreckingBall)
END_CLASS_DEFAULT_FLAGS(WreckingBall, B2BaseClass, NULL, NULL, CF_ALWAYSLOAD)


#define CHAIN_LENGTH	580
#define BEAM_LENGTH		180
#define CRAIN_HEIGHT	330
#define CHAIN_FRICTION	0.2f

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	WreckingBall::WreckingBall
//
//	PURPOSE:	Initialize
//
// ----------------------------------------------------------------------- //

WreckingBall::WreckingBall() : B2BaseClass(OT_MODEL)
{
 	AddAggregate(&m_damage);	// Just so it'll move when you shoot it.
	m_hCrane = DNULL;
	m_hChain = DNULL;
	m_bFirstUpdate	= DTRUE;
	VEC_INIT(m_vLastAttachPoint);
	VEC_INIT(m_vMomentum);
	m_fDamage = 20000.0f;		// That ought to do it.
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	WreckingBall::~WreckingBall
//
//	PURPOSE:	Destructor
//
// ----------------------------------------------------------------------- //

WreckingBall::~WreckingBall()
{
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	WreckingBall::EngineMessageFn
//
//	PURPOSE:	Handle engine messages
//
// ----------------------------------------------------------------------- //

DDWORD WreckingBall::EngineMessageFn(DDWORD messageID, void *pData, DFLOAT fData)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE) return 0;

	switch(messageID)
	{
		case MID_UPDATE:
		{
			if (!Update((DVector *)pData))
			{
				pServerDE->RemoveObject(m_hObject);
			}
			break;
		}

		case MID_PRECREATE:
		{
			DDWORD dwRet = B2BaseClass::EngineMessageFn(messageID, pData, fData);

			ObjectCreateStruct* pStruct = (ObjectCreateStruct*)pData;
			if (pStruct)
			{
				_mbscpy((unsigned char*)pStruct->m_Filename, (const unsigned char*)"models\\worldobjects\\wreckingball.abc");
				_mbscpy((unsigned char*)pStruct->m_SkinName, (const unsigned char*)"skins\\worldobjects\\wreckingball.dtx");
				_mbscpy((unsigned char*)pStruct->m_Name, (const unsigned char*)"WreckingBall");
				pStruct->m_NextUpdate = 0.01f;
				pStruct->m_Flags = FLAG_VISIBLE | FLAG_SOLID | FLAG_SHADOW | FLAG_TOUCH_NOTIFY | FLAG_MODELGOURAUDSHADE;
			}			
			return dwRet;
			break;
		}

		case MID_INITIALUPDATE:
		{
			InitialUpdate((DVector *)pData);
			break;
		}

		case MID_TOUCHNOTIFY:
		{
			HOBJECT hObj = (HOBJECT)pData;
			DVector vVel, vPos;
			pServerDE->GetVelocity(m_hObject, &vVel);
			pServerDE->GetObjectPos(m_hObject, &vPos);

			DFLOAT fRadius = 300.0f;
			ObjectList *ol = pServerDE->FindObjectsTouchingSphere(&vPos, fRadius);

			if (ol)
			{
				ObjectLink* pLink = ol->m_pFirstLink;
				while(pLink)
				{
					HOBJECT hObj = pLink->m_hObject;
					short nType = pServerDE->GetObjectType(hObj);

					if (nType == OT_WORLDMODEL)
					{
						DamageObject(m_hObject, this, hObj, m_fDamage, vVel, vPos, DAMAGE_TYPE_NORMAL); 
//						PlaySoundFromPos(&vPos, "sounds\\exp_tnt.wav", 2000, SOUNDTYPE_MISC, SOUNDPRIORITY_HIGH );
					}
				
					pLink = pLink->m_pNext;
				}
				
				pServerDE->RelinquishList(ol);
			}

			// Damage anything we touch
//			DamageObjectsInRadius(m_hObject, this, vPos, 400.0f, m_fDamage, DAMAGE_TYPE_NORMAL);
//			DamageObject(m_hObject, this, hObj, m_fDamage, vVel, vPos, DAMAGE_TYPE_NORMAL); 
			break;
		}

		default : break;
	}


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


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	WreckingBall::InitialUpdate
//
//	PURPOSE:	Do initial updating
//
// ----------------------------------------------------------------------- //

DBOOL WreckingBall::InitialUpdate(DVector*)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE || !m_hObject) return DFALSE;

	DVector vDims;
	m_damage.Init(m_hObject);
	m_damage.SetMass(5000);
	
	pServerDE->GetModelAnimUserDims(m_hObject, &vDims, 0);
	pServerDE->SetObjectDims(m_hObject, &vDims);

	pServerDE->SetForceIgnoreLimit(m_hObject, 0.0f);
	pServerDE->SetBlockingPriority(m_hObject, 50);

	pServerDE->SetNextUpdate(m_hObject, (DFLOAT)0.01);
	return DTRUE;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	WreckingBall::FirstUpdate
//
//	PURPOSE:	Do First updating
//
// ----------------------------------------------------------------------- //

void WreckingBall::FirstUpdate()
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE) return;

	// Try to find a crane
    ObjectList* pTargets = pServerDE->FindNamedObjects("crane");

	if (!pTargets || pTargets->m_nInList <= 0) 
	{
		return;
	}

	// Use the first object
	if (!(m_hCrane = pTargets->m_pFirstLink->m_hObject)) return;

	// clean up	
	pServerDE->RelinquishList(pTargets);

	// Get initial attach point
	DVector vAttachPoint, vPos;
	ComputeAttachPoint(&vAttachPoint);
	VEC_COPY(vPos, vAttachPoint);
	vPos.y -= CHAIN_LENGTH;
	pServerDE->TeleportObject(m_hObject, &vPos);

	// Make a chain
	DrawChain(&vAttachPoint);

	VEC_COPY(m_vLastAttachPoint, vAttachPoint);
}

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	WreckingBall::Update
//
//	PURPOSE:	Update the impact
//
// ----------------------------------------------------------------------- //

DBOOL WreckingBall::Update(DVector* pMovement)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE || !m_hObject) return DFALSE;

	pServerDE->SetNextUpdate(m_hObject, (DFLOAT)0.01);

	if (m_bFirstUpdate)
	{
		FirstUpdate();
		m_bFirstUpdate = DFALSE;
	}

	// If there is no crane, we have no business existing.
	if (!m_hCrane) return DFALSE;

	DVector vAttachPoint, vPos;
	ComputeAttachPoint(&vAttachPoint);

	pServerDE->GetObjectPos(m_hObject, &vPos);
	
	// Move the ball

	// Fake the y height based on X and Z distances so chain is always the same length
	DFLOAT fY, fX, fZ;
	fX = (vPos.x - vAttachPoint.x) * (vPos.x - vAttachPoint.x);
	fZ = (vPos.z - vAttachPoint.z) * (vPos.z - vAttachPoint.z);

	fY = (DFLOAT)sqrt(CHAIN_LENGTH*CHAIN_LENGTH - fX - fZ);
	vPos.y = vAttachPoint.y - fY;
	pServerDE->MoveObject(m_hObject, &vPos);

	// Calculate new X & Z acceleration
	DVector vAccel;

	// Acceleration towards the center based on how far away the ball is
	VEC_SUB(vAccel, vPos, vAttachPoint);
	vAccel.y = 0.0f;
	VEC_NEGATE(vAccel, vAccel);

	pServerDE->SetAcceleration(m_hObject, &vAccel);

	// Apply friction if the crane isn't moving
	if (VEC_DISTSQR(m_vLastAttachPoint, vAttachPoint) < 1.0f)
	{
		DVector vVel, vDamp;

		DFLOAT fFriction = -pServerDE->GetFrameTime() * CHAIN_FRICTION;
		pServerDE->GetVelocity(m_hObject, &vVel);
		VEC_COPY(vDamp, vVel);
		VEC_MULSCALAR(vDamp, vDamp, fFriction);

		VEC_ADD(vVel, vVel, vDamp);
		pServerDE->SetVelocity(m_hObject, &vVel);
	}

	// Update the chain position
	if (m_hChain)
	{
		DVector vF, vU;
		DRotation rRot;
		VEC_SET(vU, 0, 1, 0);
		VEC_SUB(vF, vPos, vAttachPoint);
		pServerDE->AlignRotation(&rRot, &vF, &vU);
		pServerDE->SetObjectRotation(m_hChain, &rRot);
		pServerDE->TeleportObject(m_hChain, &vAttachPoint);
	}

	VEC_COPY(m_vLastAttachPoint, vAttachPoint);

	return DTRUE;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	WreckingBall::ComputeAttachPoint
//
//	PURPOSE:	determines where the attach point on the crane is.
//
// ----------------------------------------------------------------------- //

void WreckingBall::ComputeAttachPoint(DVector* pvAttachPoint)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE || !m_hObject) return;

	DRotation rRot;
	DVector vF, vR, vU, vPos;

	pServerDE->GetObjectRotation(m_hCrane, &rRot);
	pServerDE->GetObjectPos(m_hCrane, &vPos);
    pServerDE->GetRotationVectors(&rRot, &vU, &vR, &vF);
	vF.x = -vF.x;

	// Compute how far along the beam (vF) and how hight (vU) the attach point is.
	VEC_MULSCALAR(vF, vF, BEAM_LENGTH);
	VEC_MULSCALAR(vU, vU, CRAIN_HEIGHT);
	VEC_ADD(*pvAttachPoint, vPos, vF);
	VEC_ADD(*pvAttachPoint, *pvAttachPoint, vU);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	WreckingBall::DrawChain
//
//	PURPOSE:	Cast a line from the attach point to the ball
//
// ----------------------------------------------------------------------- //
DBOOL WreckingBall::DrawChain(DVector *pvAttachPoint)
{
	CServerDE* pServerDE = GetServerDE();
	if (!pServerDE) return DFALSE;
    
    // Cast a Ray Forward From the camera (DebugOnly)
//    if (m_hChain) pServerDE->RemoveObject(m_hChain);
    
	ObjectCreateStruct theStruct;
	INIT_OBJECTCREATESTRUCT(theStruct);

	DVector vPos;
	DRotation rRot;
    
	pServerDE->GetObjectPos(m_hObject, &vPos);
	pServerDE->GetObjectRotation(m_hObject, &rRot);
    
	VEC_COPY(theStruct.m_Pos, *pvAttachPoint);
	ROT_COPY(theStruct.m_Rotation, rRot);

	HCLASS hClass = pServerDE->GetClass("CClientCastLineSFX");
	CClientCastLineSFX* pLine = DNULL;

	if (hClass)
	{
		pLine = (CClientCastLineSFX*)pServerDE->CreateObject(hClass, &theStruct);
		if (!pLine) return DFALSE;
	}

	DVector vColor;
	VEC_SET(vColor, 0.0f, 0.0f, 0.0f);          // Black line
	pLine->Setup(vColor, vColor, 1.0f, 1.0f, m_hObject);
    
	m_hChain = pLine->m_hObject;
    
    return DTRUE;
}

⌨️ 快捷键说明

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