📄 gibfx.cpp
字号:
// ----------------------------------------------------------------------- //
//
// MODULE : GibFX.cpp
//
// PURPOSE : Gib special FX - Implementation
//
// CREATED : 8/3/98
//
// ----------------------------------------------------------------------- //
#include "gibfx.h"
#include "cpp_client_de.h"
#include "dlink.h"
#include "BloodClientShell.h"
#include "ClientUtilities.h"
#include "bloodsplatfx.h"
#include "ParticleExplosionFX.h"
#include "SoundTypes.h"
#define GIBS_FLESH 8
#define GIBS_WOOD 4
#define GIBS_GLASS 3
#define GIBS_METAL 5
#define GIBS_PLASTIC 5
#define GIBS_STONE 9
#define GIBS_TERRAIN 5
#define SOUNDS_FLESH 5
#define SOUNDS_WOOD 5
#define SOUNDS_GLASS 5
#define SOUNDS_METAL 5
#define SOUNDS_PLASTIC 5
#define SOUNDS_STONE 5
#define SOUNDS_TERRAIN 5
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGibFX::Init
//
// PURPOSE: Create the gib
//
// ----------------------------------------------------------------------- //
DBOOL CGibFX::Init(SFXCREATESTRUCT* psfxCreateStruct)
{
if (!psfxCreateStruct) return DFALSE;
CSpecialFX::Init(psfxCreateStruct);
GIBCREATESTRUCT* pGib = (GIBCREATESTRUCT*)psfxCreateStruct;
VEC_COPY( m_vPos, pGib->m_Pos);
VEC_COPY( m_vDir, pGib->m_Dir);
VEC_COPY( m_vDims, pGib->m_Dims);
m_dwFlags = pGib->m_dwFlags;
m_fScale = pGib->m_fScale;
m_nBounceCount = 1;
DFLOAT fVel = VEC_MAG(m_vDir);
VEC_MULSCALAR(m_vDims, m_vDims, 0.8f);
if (m_vDims.x)
m_vPos.x += GetRandom(-m_vDims.x, m_vDims.x);
if (m_vDims.z)
m_vPos.z += GetRandom(-m_vDims.z, m_vDims.z);
m_nType = (m_dwFlags & TYPE_MASK) * 10;
VEC_NORM(m_vDir);
// Don't blow glass straight up quite so much
if (m_nType == SURFTYPE_GLASS)
{
VEC_SET(m_vMinVel, -fVel, 0, -fVel)
VEC_SET(m_vMaxVel, fVel, fVel*2, fVel)
if (m_vDims.y)
m_vPos.y += GetRandom(-m_vDims.y, m_vDims.y);
}
else
{
VEC_SET(m_vMinVel, -fVel, 0, -fVel)
VEC_SET(m_vMaxVel, fVel, fVel*4, fVel)
if (m_vDims.y)
m_vPos.y += GetRandom(-m_vDims.y/2, m_vDims.y);
}
m_fPitchVel = GetRandom(-MATH_CIRCLE, MATH_CIRCLE);
m_fYawVel = GetRandom(-MATH_CIRCLE, MATH_CIRCLE);
if (m_dwFlags & TYPEFLAG_CUSTOM)
{
m_hstrModel = pGib->m_hstrModel;
m_hstrSkin = pGib->m_hstrSkin;
m_hstrSound = pGib->m_hstrSound;
}
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGibFX::Term
//
// PURPOSE: Term
//
// ----------------------------------------------------------------------- //
DBOOL CGibFX::Term()
{
m_bFade = DTRUE;
return DFALSE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGibFX::CreateObject
//
// PURPOSE: Create object associated with the mark
//
// ----------------------------------------------------------------------- //
DBOOL CGibFX::CreateObject(CClientDE *pClientDE)
{
if (!CSpecialFX::CreateObject(pClientDE)) return DFALSE;
CBloodClientShell *pShell = (CBloodClientShell*)g_pClientDE->GetClientShell();
if (!pShell) return DFALSE;
CSFXMgr* psfxMgr = pShell->GetSFXMgr();
if (!psfxMgr) return DFALSE;
m_pClientDE->AlignRotation(&m_Rotation, &m_vDir, DNULL);
// Determine the filenames to use
int index;
DBOOL bRandomizeScale = DFALSE;
moveObj.m_PhysicsFlags = MO_HALFGRAVITY;
ObjectCreateStruct createStruct;
INIT_OBJECTCREATESTRUCT(createStruct);
createStruct.m_ObjectType = OT_MODEL;
char szSound[MAX_CS_FILENAME_LEN+1];
char szFilename[MAX_CS_FILENAME_LEN+1];
_mbscpy((unsigned char*)szFilename, (const unsigned char*)"");
// Determine the file to use
if (!(m_dwFlags & TYPEFLAG_CUSTOM))
{
switch (m_nType)
{
case SURFTYPE_FLESH:
{
index = GetRandom(1, NRES(GIBS_FLESH));
sprintf(szFilename, "flesh\\gib%d", index);
bRandomizeScale = DTRUE;
m_nBounceCount = (GetRandom(0, 4) == 4) ? 1 : 0; // Stick the wall 20% of the time
moveObj.m_PhysicsFlags |= MO_STICKY;
index = GetRandom(1, NRES(SOUNDS_FLESH));
sprintf(szSound, "sounds\\gibs\\flesh\\gib_impact%d.wav", index);
}
break;
case SURFTYPE_GLASS:
{
index = GetRandom(1, NRES(GIBS_GLASS));
sprintf(szFilename, "glass\\gib%d", index);
bRandomizeScale = DTRUE;
m_nBounceCount = 1;
index = GetRandom(1, NRES(SOUNDS_GLASS));
sprintf(szSound, "sounds\\gibs\\glass\\gib_impact%d.wav", index);
}
break;
case SURFTYPE_WOOD:
{
index = GetRandom(1, NRES(GIBS_WOOD));
sprintf(szFilename, "wood\\gib%d", index);
bRandomizeScale = DFALSE;
m_nBounceCount = 1;
index = GetRandom(1, NRES(SOUNDS_WOOD));
sprintf(szSound, "sounds\\gibs\\wood\\gib_impact%d.wav", index);
}
break;
case SURFTYPE_STONE:
{
index = GetRandom(1, NRES(GIBS_STONE));
sprintf(szFilename, "stone\\gib%d", index);
bRandomizeScale = DTRUE;
m_nBounceCount = 2;
index = GetRandom(1, NRES(SOUNDS_STONE));
sprintf(szSound, "sounds\\gibs\\stone\\gib_impact%d.wav", index);
}
break;
case SURFTYPE_PLASTIC:
{
index = GetRandom(1, NRES(GIBS_PLASTIC));
sprintf(szFilename, "plastic\\gib%d", index);
bRandomizeScale = DTRUE;
m_nBounceCount = 2;
index = GetRandom(1, NRES(SOUNDS_PLASTIC));
sprintf(szSound, "sounds\\gibs\\plastic\\gib_impact%d.wav", index);
}
break;
case SURFTYPE_TERRAIN:
{
index = GetRandom(1, NRES(GIBS_TERRAIN));
sprintf(szFilename, "terrain\\gib%d", index);
bRandomizeScale = DTRUE;
m_nBounceCount = 2;
index = GetRandom(1, NRES(SOUNDS_TERRAIN));
sprintf(szSound, "sounds\\gibs\\terrain\\gib_impact%d.wav", index);
}
break;
case SURFTYPE_METAL:
default:
{
index = GetRandom(1, NRES(GIBS_METAL));
sprintf(szFilename, "metal\\gib%d", index);
bRandomizeScale = DFALSE;
m_nBounceCount = 1;
index = GetRandom(1, NRES(SOUNDS_METAL));
sprintf(szSound, "sounds\\gibs\\metal\\gib_impact%d.wav", index);
}
break;
}
if (!szFilename)
return DFALSE;
if (bRandomizeScale)
{
if (m_nType == SURFTYPE_FLESH)
{
VEC_SET(createStruct.m_Scale, GetRandom(0.8f, 1.35f), GetRandom(0.8f, 1.35f), GetRandom(0.8f, 1.35f));
}
else
{
VEC_SET(createStruct.m_Scale, GetRandom(0.5f, 1.25f), GetRandom(0.5f, 1.25f), GetRandom(0.5f, 1.25f));
}
}
VEC_MULSCALAR(createStruct.m_Scale, createStruct.m_Scale, m_fScale);
if (_mbstrlen(szSound) && !m_hstrSound)
{
m_hstrSound = m_pClientDE->CreateString(szSound);
}
}
// Custom or normal?
if (m_hstrModel)
_mbscpy((unsigned char*)createStruct.m_Filename, (const unsigned char*)m_pClientDE->GetStringData(m_hstrModel));
else
sprintf(createStruct.m_Filename, "models\\gibs\\%s.abc", szFilename);
if (m_hstrSkin)
_mbscpy((unsigned char*)createStruct.m_SkinName, (const unsigned char*)m_pClientDE->GetStringData(m_hstrSkin));
else
sprintf(createStruct.m_SkinName, "skins\\gibs\\%s.dtx", szFilename);
createStruct.m_Flags = FLAG_VISIBLE;
VEC_COPY(createStruct.m_Pos, m_vPos);
m_hObject = pClientDE->CreateObject(&createStruct);
// Make glass transparent
if (m_nType == SURFTYPE_GLASS)
m_pClientDE->SetObjectColor(m_hObject, 0.0f, 0.0f, 0.0f, 0.4f);
if(m_dwFlags & TRAIL_BLOOD)
{
m_bBlood = DTRUE;
}
else if(m_dwFlags & TRAIL_SMOKE)
{
m_bSmoke = DTRUE;
}
//initialize velocity
DVector vVelMin, vVelMax, vTemp, vU, vR, vF;
VEC_SET(vVelMin, 1.0f, 1.0f, 1.0f);
VEC_SET(vVelMax, 1.0f, 1.0f, 1.0f);
m_pClientDE->GetRotationVectors(&m_Rotation, &vU, &vR, &vF);
if (vF.y <= -0.95f || vF.y >= 0.95f)
{
vF.y = vF.y > 0.0f ? 1.0f : -1.0f;
VEC_SET(vR, 1.0f, 0.0f, 0.0f);
VEC_SET(vU, 0.0f, 0.0f, 1.0f);
}
else if (vF.x <= -0.95f || vF.x >= 0.95f)
{
vF.x = vF.x > 0.0f ? 1.0f : -1.0f;
VEC_SET(vR, 0.0f, 1.0f, 0.0f);
VEC_SET(vU, 0.0f, 0.0f, 1.0f);
}
else if (vF.z <= -0.95f || vF.z >= 0.95f)
{
vF.z = vF.z > 0.0f ? 1.0f : -1.0f;
VEC_SET(vR, 1.0f, 0.0f, 0.0f);
VEC_SET(vU, 0.0f, 1.0f, 0.0f);
}
VEC_MULSCALAR(vVelMin, vF, m_vMinVel.y);
VEC_MULSCALAR(vVelMax, vF, m_vMaxVel.y);
VEC_MULSCALAR(vTemp, vR, m_vMinVel.x);
VEC_ADD(vVelMin, vVelMin, vTemp);
VEC_MULSCALAR(vTemp, vR, m_vMaxVel.x);
VEC_ADD(vVelMax, vVelMax, vTemp);
VEC_MULSCALAR(vTemp, vU, m_vMinVel.z);
VEC_ADD(vVelMin, vVelMin, vTemp);
VEC_MULSCALAR(vTemp, vU, m_vMaxVel.z);
VEC_ADD(vVelMax, vVelMax, vTemp);
DVector vStartVel;
VEC_SET(vStartVel, GetRandom(vVelMin.x, vVelMax.x),
GetRandom(vVelMin.y, vVelMax.y),
GetRandom(vVelMin.z, vVelMax.z));
InitMovingObject(&moveObj, &m_vPos, &vStartVel);
if (m_bBlood)
CreateBloodSpurt(&vStartVel);
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGibFX::Update
//
// PURPOSE: Update the mark
//
// ----------------------------------------------------------------------- //
DBOOL CGibFX::Update()
{
if(!m_hObject || !m_pClientDE) return DFALSE;
//fade the object out of existence
if(m_bFade)
{
if(m_fScaleCount >= 150.0f)
return DFALSE;
DFLOAT fAlpha = 0.0f;
DVector vColor;
m_pClientDE->GetObjectColor(m_hObject,&vColor.x, &vColor.y, &vColor.z, &fAlpha);
m_pClientDE->SetObjectColor(m_hObject,vColor.x,vColor.y,vColor.z,1.0f - (m_fScaleCount/150.0f));
m_fScaleCount++;
return DTRUE;
}
DBOOL bBounced = DFALSE;
ClientIntersectInfo info;
if(moveObj.m_PhysicsFlags & MO_RESTING)
{
return DTRUE;
}
else if(bBounced = UpdateMovement(&moveObj, &info))
{
PlaySoundFromPos(&moveObj.m_Pos, m_pClientDE->GetStringData(m_hstrSound), 750.0f,SOUNDPRIORITY_MISC_LOW);
if (m_bBlood)
CreateBloodSplat(&moveObj.m_Pos, &info);
// Don't count bounces off the ceiling
if (info.m_Plane.m_Normal.y > 0)
{
if (m_nBounceCount <= 0)
{
moveObj.m_PhysicsFlags |= MO_RESTING;
}
m_nBounceCount--;
}
else
{
moveObj.m_PhysicsFlags &= ~MO_RESTING;
}
m_pClientDE->SetObjectPos(m_hObject, &(moveObj.m_Pos));
// Adjust due to the bounce...
m_fPitchVel = GetRandom(-MATH_CIRCLE, MATH_CIRCLE);
m_fYawVel = GetRandom(-MATH_CIRCLE, MATH_CIRCLE);
}
else
{
//rotate the object
if (m_fPitchVel != 0 || m_fYawVel != 0)
{
DFLOAT fDeltaTime = m_pClientDE->GetFrameTime();
m_fPitch += m_fPitchVel * fDeltaTime;
m_fYaw += m_fYawVel * fDeltaTime;
DRotation rRot;
m_pClientDE->SetupEuler(&rRot, m_fPitch, m_fYaw, 0.0f);
m_pClientDE->SetObjectRotation(m_hObject, &rRot);
}
m_pClientDE->SetObjectPos(m_hObject, &(moveObj.m_Pos));
if(m_bBlood)
{
}
}
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGibFX::UpdateMovement
//
// PURPOSE: Update position
//
// ----------------------------------------------------------------------- //
DBOOL CGibFX::UpdateMovement(MovingObject* pObject, ClientIntersectInfo* pInfo)
{
if (!m_pClientDE || !pObject || pObject->m_PhysicsFlags & MO_RESTING) return DFALSE;
DBOOL bRet = DFALSE;
DVector vNewPos;
if (UpdateMovingObject(DNULL, pObject, &vNewPos))
{
// SurfaceType eType = SURFTYPE_UNKNOWN;
// bRet = BounceMovingObject(DNULL, pObject, &vNewPos, pInfo, &eType);
bRet = BounceMovingObject(DNULL, pObject, &vNewPos, pInfo);
VEC_COPY(pObject->m_LastPos, pObject->m_Pos);
VEC_COPY(pObject->m_Pos, vNewPos);
if (m_pClientDE->GetPointStatus(&vNewPos) != DE_INSIDE)
{
pObject->m_PhysicsFlags |= MO_RESTING;
}
}
return bRet;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGibFX::UpdateMovement
//
// PURPOSE: Update position
//
// ----------------------------------------------------------------------- //
DBOOL CGibFX::CreateBloodSpurt(DVector *pvDir)
{
CBloodClientShell *pShell = (CBloodClientShell*)g_pClientDE->GetClientShell();
if (!pShell) return DFALSE;
CSFXMgr* psfxMgr = pShell->GetSFXMgr();
if (!psfxMgr) return DFALSE;
char* szBlood[4] = { "spritetextures\\particles\\blooddrop_1.dtx",
"spritetextures\\particles\\blooddrop_2.dtx",
"spritetextures\\particles\\blooddrop_3.dtx",
"spritetextures\\particles\\blooddrop_4.dtx"};
PESCREATESTRUCT pe;
VEC_MULSCALAR(pe.vMinVel, *pvDir, 0.6f);
VEC_MULSCALAR(pe.vMaxVel, *pvDir, 0.6f);
VEC_COPY(pe.vPos, m_vPos);
// ROT_COPY(pe.rSurfaceRot, m_rRotation);
VEC_SET(pe.vColor1, 128.0f, 128.0f, 128.0f);
VEC_SET(pe.vColor2, 128.0f, 128.0f, 128.0f);
VEC_SET(pe.vMinDriftOffset, 0.0f, -10.0f, 0.0f);
VEC_SET(pe.vMaxDriftOffset, 0.0f, -5.0f, 0.0f);
pe.bSmall = DFALSE;
pe.fLifeTime = 2.0f;
pe.fFadeTime = 0.5f;
pe.fOffsetTime = 0.0f;
pe.fRadius = 200.0f;
pe.fGravity = -100.0f;
pe.nNumPerPuff = 2;
pe.nNumEmitters = 1; //GetRandom(1,4);
pe.nEmitterFlags = MO_HALFGRAVITY;
pe.bIgnoreWind = DTRUE;
pe.pFilename = szBlood[GetRandom(0,2)];
pe.nSurfaceType = SURFTYPE_FLESH;
pe.nNumSteps = 6;
pe.bBounce = DFALSE;
CSpecialFX* pFX = psfxMgr->CreateSFX(SFX_PARTICLEEXPLOSION_ID, &pe, DFALSE, this);
if (pFX)
{
CBaseParticleSystemFX* pBasePS = (CBaseParticleSystemFX*)pFX;
pBasePS->m_bSetSoftwareColor = DFALSE;
pFX->Update();
m_pClientDE->SetSoftwarePSColor(pFX->GetObject(), 1.0f, 0.0f, 0.0f);
}
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CGibFX::CreateBloodSplat
//
// PURPOSE: Create a blood splat
//
// ----------------------------------------------------------------------- //
void CGibFX::CreateBloodSplat(DVector *pvPos, ClientIntersectInfo *pInfo)
{
CBloodClientShell *pShell = (CBloodClientShell*)g_pClientDE->GetClientShell();
if (!pShell) return;
CSFXMgr* psfxMgr = pShell->GetSFXMgr();
if (!psfxMgr) return;
BSCREATESTRUCT splat;
char* pSplatSprite = DNULL;
switch(GetRandom(1,3))
{
case 1: pSplatSprite = "sprites\\blood1.spr"; break;
case 2: pSplatSprite = "sprites\\blood2.spr"; break;
case 3: pSplatSprite = "sprites\\blood3.spr"; break;
default: pSplatSprite = "sprites\\blood1.spr"; break;
}
VEC_COPY(splat.m_Pos, *pvPos);
m_pClientDE->AlignRotation(&splat.m_Rotation, &pInfo->m_Plane.m_Normal, &pInfo->m_Plane.m_Normal);
splat.m_fScale = 0.14f + GetRandom(-0.1f,0.1f);
splat.m_hstrSprite = m_pClientDE->CreateString(pSplatSprite);
if(pInfo->m_Plane.m_Normal.y >= 0.5f)
splat.m_fGrowScale = 0.01f;
psfxMgr->CreateSFX(SFX_BLOODSPLAT_ID, &splat, DFALSE, this);
g_pClientDE->FreeString( splat.m_hstrSprite );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -