📄 destructable.cpp
字号:
//----------------------------------------------------------
//
// 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 + -