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

📄 destructable.cpp

📁 Blood 2全套源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//----------------------------------------------------------
//
// MODULE  : Destructable.cpp
//
// PURPOSE : Destructable class
//
// CREATED : 9/23/97
//
//----------------------------------------------------------

#include <stdio.h>
#include <math.h>
#include "BloodServerShell.h"
#include "Destructable.h"
#include "cpp_server_de.h"
#include "generic_msg_de.h"
#include "Projectile.h"
#include "PlayerObj.h"
#include "Trigger.h"
#include "Spawner.h"
#include "PhysicalAttributes.h"
#include "sfxmsgids.h"
#include "ai_mgr.h"

DLink CDestructable::m_DestructableHead;
DDWORD CDestructable::m_dwNumDestructables = 0;


#define TRIGGER_MSG_KILL		"KILL"

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::CDestructable
//
//	PURPOSE:	Constructor
//
// ----------------------------------------------------------------------- //

CDestructable::CDestructable() : Aggregate()
{
	m_hObject					= DNULL;
//	pOwner					= DNULL;

	m_bDead						= DFALSE;
	m_bApplyDamagePhysics		= DTRUE;
	m_fMass						= 1.0;
	m_fHitPoints				= 1;
	m_fDeathHitPoints			= 1;
	m_fMaxHitPoints				= 1;
	m_fMaxMegaHitPoints			= 1;
	m_fArmorPoints				= 0.0;
	m_fMaxArmorPoints			= 1.0;
	m_fMaxNecroArmorPoints		= 1.0;
	m_fResistance				= 1.0;

	m_nLastDamageType			= DAMAGE_TYPE_NORMAL;
	m_fLastDamagePercent		= 0.0f;
	m_fLastDamageAmount			= 0.0f;
	VEC_INIT(m_vLastDamageDirection);

	m_hstrDamageTriggerTarget	= DNULL;
	m_hstrDamageTriggerMessage	= DNULL;
	m_hstrDeathTriggerTarget	= DNULL;
	m_hstrDeathTriggerMessage	= DNULL;

	m_hstrSpawnObject			= DNULL;
	VEC_INIT(m_vSpawnObjectVel);
	
	m_bGodMode					= DFALSE;
	m_bNighInvulnerable			= DFALSE;
	m_hWhoKilledMeLast			= DNULL;
	m_bTriggerOnly				= DFALSE;

	m_fDeathDelay				= 0.0f;

	m_Link.m_pData				= DNULL;
	if( m_dwNumDestructables == 0 )
	{
		dl_TieOff( &m_DestructableHead );
	}

	m_hLastDamager = DNULL;
	m_nNodeHit = 0;
	m_nSideHit = 0;

	// Init these [gk]
	m_pInventoryMgr	= DNULL;
	m_pAnim_Sound = DNULL;

	m_bAddVelocity = DFALSE;
	VEC_INIT(m_vAddVelocity);

	m_bDestructable			= DTRUE;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::~CDestructable
//
//	PURPOSE:	Destructable
//
// ----------------------------------------------------------------------- //

CDestructable::~CDestructable()
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE) return;

	if (m_hstrDamageTriggerTarget)
	{
		pServerDE->FreeString(m_hstrDamageTriggerTarget);
	}

	if (m_hstrDamageTriggerMessage)
	{
		pServerDE->FreeString(m_hstrDamageTriggerMessage);
	}

	if (m_hstrDeathTriggerTarget)
	{
		pServerDE->FreeString(m_hstrDeathTriggerTarget);
	}

	if (m_hstrDeathTriggerMessage)
	{
		pServerDE->FreeString(m_hstrDeathTriggerMessage);
	}

	if (m_hstrSpawnObject)
	{
		pServerDE->FreeString(m_hstrSpawnObject);
	}

	if( m_Link.m_pData && m_dwNumDestructables > 0 )
	{
		dl_Remove( &m_Link );
		m_dwNumDestructables--;
	}
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::EngineMessageFn
//
//	PURPOSE:	Handle message from the engine
//
// ----------------------------------------------------------------------- //
		
DDWORD CDestructable::EngineMessageFn(LPBASECLASS pObject, DDWORD messageID, void *pData, DFLOAT fData)
{
	if (!g_pServerDE) return 0;

	switch(messageID)
	{
		case MID_PRECREATE:
			if (fData == PRECREATE_WORLDFILE || fData == PRECREATE_STRINGPROP)
			{
				ReadProp(pObject, (ObjectCreateStruct*)pData);
			}
			break;

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

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

		case MID_UPDATE:
			{
				m_fLastDamagePercent = 0.0f;	// Reset cumulative damage;
				m_fLastDamageAmount = 0.0f;

				if (m_bDead && m_fDeathDelay > 0)
					m_fDeathDelay -= g_pServerDE->GetFrameTime();

				// Just in case..
				if (m_fHitPoints > m_fMaxMegaHitPoints)
					m_fHitPoints = m_fMaxMegaHitPoints;
				if (m_fArmorPoints > m_fMaxNecroArmorPoints)
					m_fArmorPoints = m_fMaxNecroArmorPoints;
			}
			break;

		case MID_LINKBROKEN:
			{
				HOBJECT hObj = (HOBJECT)pData;
				if (hObj == m_hLastDamager)
				{
					m_hLastDamager = DNULL;
				}
			}
			break;
	}

	return Aggregate::EngineMessageFn(pObject, messageID, pData, fData);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::ObjectMessageFn
//
//	PURPOSE:	Handle object-to-object messages
//
// ----------------------------------------------------------------------- //

DDWORD CDestructable::ObjectMessageFn(LPBASECLASS pObject, HOBJECT hSender, DDWORD messageID, HMESSAGEREAD hRead)
{
	switch(messageID)
	{
		case MID_DAMAGE:
		{
			HandleDamage(hSender, hRead);
			break;
		}

		case MID_REPAIR:
		{
			HandleRepair(hSender, hRead);
			break;
		}

		case MID_HEAL:
		{
			HandleHeal(hSender, hRead);
			break;
		}

		case MID_TRIGGER:
		{
			HandleTrigger(hSender, hRead);
			break;
		}

		default : break;
	}

	return Aggregate::ObjectMessageFn(pObject, hSender, messageID, hRead);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::ReadProp
//
//	PURPOSE:	Set property value
//
// ----------------------------------------------------------------------- //

DBOOL CDestructable::ReadProp(BaseClass *pObject, ObjectCreateStruct *pStruct)
{
	GenericProp genProp;
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pStruct || !pServerDE) return DFALSE;

	char buf[MAX_CS_FILENAME_LEN];

	buf[0] = '\0';
	pServerDE->GetPropString("DamageTriggerTarget", buf, MAX_CS_FILENAME_LEN);
	if (buf[0]) m_hstrDamageTriggerTarget = pServerDE->CreateString(buf);

	buf[0] = '\0';
	pServerDE->GetPropString("DamageTriggerMessage", buf, MAX_CS_FILENAME_LEN);
	if (buf[0]) m_hstrDamageTriggerMessage = pServerDE->CreateString(buf);

	buf[0] = '\0';
	pServerDE->GetPropString("DeathTriggerTarget", buf, MAX_CS_FILENAME_LEN);
	if (buf[0]) m_hstrDeathTriggerTarget = pServerDE->CreateString(buf);

	buf[0] = '\0';
	pServerDE->GetPropString("DeathTriggerMessage", buf, MAX_CS_FILENAME_LEN);
	if (buf[0]) m_hstrDeathTriggerMessage = pServerDE->CreateString(buf);

	buf[0] = '\0';
	pServerDE->GetPropString("SpawnObject", buf, MAX_CS_FILENAME_LEN);
	if (buf[0]) m_hstrSpawnObject = pServerDE->CreateString(buf);

	pServerDE->GetPropVector("SpawnObjectVel", &m_vSpawnObjectVel);

	pServerDE->GetPropBool("TriggerDestroyOnly", &m_bTriggerOnly);


	// Create empty message strings if there is are trigger targets & no messages
	if (m_hstrDamageTriggerTarget && !m_hstrDamageTriggerMessage)
		m_hstrDamageTriggerMessage = pServerDE->CreateString("");

	if (m_hstrDeathTriggerTarget && !m_hstrDeathTriggerMessage)
		m_hstrDeathTriggerMessage = pServerDE->CreateString("");

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


	return DTRUE;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::Init
//
//	PURPOSE:	Initialize object
//
// ----------------------------------------------------------------------- //

DBOOL CDestructable::Init(HOBJECT hObject, CInventoryMgr* pInv, CAnim_Sound* pAnimSound)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!hObject || !pServerDE) return DFALSE;

	m_hObject = hObject;

	// insert it into the list
	if (!m_Link.m_pData)
	{
		dl_Insert( &m_DestructableHead, &m_Link );
		m_Link.m_pData = ( void * )this;
		m_dwNumDestructables++;
	}

	m_pInventoryMgr = pInv;
	m_pAnim_Sound = pAnimSound;

	return DTRUE;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::CalculateResistance
//
//	PURPOSE:	Handle damage message
// 
// ----------------------------------------------------------------------- //

void CDestructable::CalculateResistance(DBYTE nResistValue)
{
	if (nResistValue == 1)
		m_fResistance = 1.20f;
	else if (nResistValue == 2)
		m_fResistance = 1.10f;
	else if (nResistValue == 3)
		m_fResistance = 1.0f;
	else if (nResistValue == 4)
		m_fResistance = 0.9f;
	else if (nResistValue == 5)
		m_fResistance = 0.8f;
	else if (nResistValue >= 6)
		m_fResistance = 0.7f;
}
	
	
// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::SetMass
//
//	PURPOSE:	Set the blocking priority for this object
//
// ----------------------------------------------------------------------- //

void CDestructable::SetMass(DFLOAT fMass)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE || !m_hObject) return;

	m_fMass = fMass;

	pServerDE->SetForceIgnoreLimit(m_hObject, MIN_FORCE);

	// Set the friction based on the mass of the object...

	pServerDE->SetObjectMass(m_hObject, m_fMass);

	CLIPLOWHIGH(fMass, 0, 500.0f);
	DFLOAT fFricCoeff = MIN_FRICTION + (m_fMass * (MAX_FRICTION - MIN_FRICTION)) / 500.0f;
	pServerDE->SetFrictionCoefficient(m_hObject, fFricCoeff);
//	pServerDE->SetFrictionCoefficient(m_hObject, 10.0f);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::HandleDamage
//
//	PURPOSE:	Handle damage message
// 
// ----------------------------------------------------------------------- //

void CDestructable::HandleDamage(HOBJECT hSender, HMESSAGEREAD hRead)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE) return;

	DVector vDir,vPos;

	pServerDE->ReadFromMessageVector(hRead, &vDir);
	DFLOAT fDamage = pServerDE->ReadFromMessageFloat(hRead);
	DBYTE nDamageType	= pServerDE->ReadFromMessageByte(hRead);
	HOBJECT hWhoHit = pServerDE->ReadFromMessageObject(hRead);
	pServerDE->ReadFromMessageVector(hRead, &vPos);

//	char buf[50];
	DFLOAT fOldHitPoints = m_fHitPoints;
	fDamage = fDamage * m_fResistance;

	// Just return if we can't take damage
	if (m_bGodMode || (m_bTriggerOnly && nDamageType != DAMAGE_TYPE_DEATH) || fDamage < 0)
	{
		return;
	}

	if (!IsPlayerToPlayerDamageOk(hSender, hWhoHit))
	{
		return;
	}

	// If instant death, don't bother calculating stuff.. 
	if( m_bDestructable && nDamageType == DAMAGE_TYPE_DEATH)
	{
		m_fArmorPoints = 0;
		m_fHitPoints = 0;
		m_fDeathHitPoints = 0;
		m_fLastDamagePercent = 100.0f;
		m_fLastDamageAmount = (DFLOAT)m_fMaxHitPoints;

		nDamageType &= 0x0f;	// Mask off the damage type flags
		m_nLastDamageType = nDamageType;
	}
	else
	{
		// Special pre-damage base character modifiers
		if (IsAICharacter(m_hObject))
		{
			m_nNodeHit = CalculateHitLimb(vDir,vPos,fDamage);

			if(m_nNodeHit == -1 && !(nDamageType & DAMAGE_TYPE_NORMAL))
				m_nNodeHit = SetProperNode(pServerDE->IntRandom(0,NUM_ALL_NODES - 3));
			else if(m_nNodeHit >= 0)
				m_nNodeHit = SetProperNode(m_nNodeHit);
			else
				return;

⌨️ 快捷键说明

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