📄 viewweapon.cpp
字号:
DDWORD dwFlags = m_pClientDE->GetObjectFlags(m_hObject);
m_pClientDE->SetObjectFlags(m_hObject, (dwFlags | FLAG_VISIBLE));
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::SendFireMsg
//
// PURPOSE: Send fire message to server
//
// ----------------------------------------------------------------------- //
void CViewWeapon::SendFireMsg(DVector* pvPos, DVector* pvFire, DBYTE byRandomSeed, DBOOL bAltFire)
{
if (!m_pClientDE || !m_hObject) return;
// Make sure we always ignore the fire sound...
m_nIgnoreFX = 0;
// Put alt fire value in top bit...
DBYTE byFlags = 0;
if (bAltFire)
byFlags |= 0x01;
if (m_bLeftHand)
byFlags |= 0x02;
// Send Fire message to server...
HMESSAGEWRITE hWrite = m_pClientDE->StartMessage(CMSG_WEAPON_FIRE);
m_pClientDE->WriteToMessageVector(hWrite, pvPos);
m_pClientDE->WriteToMessageVector(hWrite, pvFire);
m_pClientDE->WriteToMessageByte(hWrite, byRandomSeed);
m_pClientDE->WriteToMessageByte(hWrite, (DBYTE)m_nType);
if(!FireMsgSpecialData(hWrite, byFlags))
m_pClientDE->WriteToMessageByte(hWrite, byFlags);
m_pClientDE->EndMessage2(hWrite, MESSAGE_NAGGLEFAST|MESSAGE_GUARANTEED);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::IsIdle()
//
// PURPOSE: Terminates this weapon
//
// ----------------------------------------------------------------------- //
DBOOL CViewWeapon::IsChanging()
{
if((m_eState == WS_DRAW) || (m_eState == WS_HOLSTER))
return DTRUE;
else
return DFALSE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::Draw()
//
// PURPOSE: draws the weapon, sets filenames
//
// ----------------------------------------------------------------------- //
void CViewWeapon::Draw()
{
m_eState = WS_DRAW;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::CheckAmmo()
//
// PURPOSE: returns amount of ammo available to this weapon
//
// ----------------------------------------------------------------------- //
DFLOAT CViewWeapon::CheckAmmo(DBOOL bAltFire)
{
CBloodClientShell *pShell = (CBloodClientShell*)g_pClientDE->GetClientShell();
if (!pShell) return 0;
// If the No Ammo is required for the Weapon then return 1
if (GetAmmoType(bAltFire) == AMMO_NONE)
{
return 1.0f;
}
if (bAltFire)
return (DFLOAT)pShell->GetAltAmmo();
else
return (DFLOAT)pShell->GetAmmo();
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::PlayFireSound()
//
// PURPOSE: Plays the firing sound
//
// ----------------------------------------------------------------------- //
HSOUNDDE CViewWeapon::PlayFireSound(DBOOL bAltFire)
{
HSOUNDDE hSound = DNULL;
/* TODO
char *sound;
DBOOL bLoop = DFALSE;
if (bAltFire)
{
sound = m_szAltFireSound;
}
else
{
sound = m_szFireSound;
}
if (sound && _mbstrlen(sound) > 0)
{
DFLOAT Radius = 2000.0f;
SoundType sndtype = IsOwnerAPlayer() ? SOUNDTYPE_PLAYER : SOUNDTYPE_AI;
hSound = PlaySoundFromObject(m_hOwner, sound, Radius, sndtype, SOUNDPRIORITY_HIGH, bLoop, DTRUE, DTRUE);
SendSoundTrigger(m_hOwner, SOUND_GUNFIRE, m_vPosition, Radius);
}
int soundToKill = 0;
if (hSound)
{
// See if there is an available sound slot, if not, kill the sound with the least time remaining.
int nIndex = -1;
for (int i=0; i < MAX_FIRE_SOUNDS; i++)
{
if (!m_hCurFireSounds[i])
{
nIndex = i;
break; // A match!
}
else if (nIndex == -1 || m_fCurFireSoundsEndTime[i] < m_fCurFireSoundsEndTime[nIndex])
{
nIndex = i;
}
}
if (nIndex != -1) // This should ALWAYS be the case.
{
DFLOAT fTime;
m_pClientDE->GetSoundDuration(hSound, &fTime);
fTime += m_pClientDE->GetTime();
if (m_hCurFireSounds[nIndex])
m_pClientDE->KillSound(m_hCurFireSounds[nIndex]);
m_hCurFireSounds[nIndex] = hSound;
m_fCurFireSoundsEndTime[nIndex] = fTime;
}
else
{
m_pClientDE->KillSound(hSound);
hSound = DNULL;
}
}
*/
return hSound;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::PlayEmptyWeaponSound()
//
// PURPOSE: Plays the firing sound
//
// ----------------------------------------------------------------------- //
HSOUNDDE CViewWeapon::PlayEmptyWeaponSound(DBOOL bAltFire)
{
HSOUNDDE hSound = DNULL;
/*
char *sound;
if (bAltFire)
sound = m_szAltEmptyWeaponSound;
else
sound = m_szEmptyWeaponSound;
// if (pWeap->m_nAmmo > 0) sound = m_FireSound;
if (_mbstrlen(sound) > 0)
{
DFLOAT Radius = 800.0f;
SoundType sndtype = IsOwnerAPlayer() ? SOUNDTYPE_PLAYER : SOUNDTYPE_AI;
hSound = PlaySoundFromObject(m_hOwner, sound, Radius, sndtype, SOUNDPRIORITY_HIGH);
}
*/
return hSound;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::FireVector()
//
// PURPOSE: Fires a vector for vector weapons
//
// ----------------------------------------------------------------------- //
DBOOL CViewWeapon::FireVector(DVector *vFire, DFLOAT dist, DBOOL bTracer)
{
if (!m_pClientDE) return DFALSE;
IntersectQuery iq;
IntersectInfo ii;
DVector vFrom, vTo, vDist;
DDWORD nFX = 0;
DDWORD nExtras = 0;
WeaponFXExtras ext;
int nNode = 999;
if(bTracer) nFX |= WFX_TRACER;
// Setup the origin and destination points
VEC_COPY(vFrom, m_vPosition);
VEC_MULSCALAR(vDist, *vFire, dist)
VEC_ADD(vTo, m_vPosition, vDist);
// Set the intersection query values
iq.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID | INTERSECT_HPOLY;
iq.m_FilterFn = DNULL;
iq.m_pUserData = DNULL;
SurfaceType eType = SURFTYPE_UNKNOWN;
VEC_COPY(iq.m_From, vFrom);
VEC_COPY(iq.m_To, vTo);
return DTRUE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::FireProjectile()
//
// PURPOSE: Fires a projectile
//
// ----------------------------------------------------------------------- //
DBOOL CViewWeapon::FireProjectile(DVector *vFire, DFLOAT dist, DBOOL bAltFire)
{
if (!m_pClientDE)
return DFALSE;
return DFALSE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::Fire()
//
// PURPOSE: Fires the weapon
//
// ----------------------------------------------------------------------- //
DDWORD CViewWeapon::Fire()
{
if (!m_pClientDE) return 0;
//***** General variable declarations *****//
DFLOAT fReloadTime;
DBYTE nFiredType = 0;
DFLOAT cTime = m_pClientDE->GetTime();
DFLOAT range;
Spread *spread;
DDWORD dwShotsPerFire;
D_WORD nAmmoUse;
DBOOL bHitPlayerObj = DFALSE;
CBloodClientShell *pShell = (CBloodClientShell*)g_pClientDE->GetClientShell();
if( !pShell )
return 0;
// Can't fire while binocs active.
if( pShell->BinocularsActive( ))
return 0;
// Calculate a random seed...(srand uses this value so it can't be 1, since
// that has a special meaning for srand)
g_byRandomWeaponSeed = GetRandom(2, 255);
srand(g_byRandomWeaponSeed);
// Reload time depends on current barrel or alt fire
if(m_bLastFireAlt) fReloadTime = m_fAltReloadTime;
else fReloadTime = m_fReloadTime;
// See if any reload time modifiers are in effect
fReloadTime *= 1; // TODO m_pInventoryMgr->GetFireRateMultiplier();
// Set up varaible for primary or alternate firing states
DBOOL bAltFire = (m_eState == WS_ALT_FIRING);
if(!bAltFire)
{
dwShotsPerFire = m_dwShotsPerFire;
spread = &m_Spread;
range = m_fRange;
m_fDamage = GetRandom(m_fMinDamage, m_fMaxDamage);
nAmmoUse = m_nAmmoUse;
}
else
{
dwShotsPerFire = m_dwAltShotsPerFire;
spread = &m_AltSpread;
range = m_fAltRange;
m_fDamage = GetRandom(m_fMinAltDamage, m_fMaxAltDamage);
nAmmoUse = m_nAltAmmoUse;
}
// Only fire ammo if we have the ammo
DFLOAT fAmmoCount = CheckAmmo(bAltFire);
if (fAmmoCount >= nAmmoUse)
{
switch(GetAmmoType(bAltFire))
{
// Shells only use 1 shell per fire, no matter how many vectors
case AMMO_SHELL:
fAmmoCount -= (DFLOAT)nAmmoUse;
break;
// default is 1 bullet per vector
default:
if ((DFLOAT)(dwShotsPerFire * nAmmoUse) > fAmmoCount)
dwShotsPerFire = (int)fAmmoCount / nAmmoUse;
fAmmoCount -= (DFLOAT)(dwShotsPerFire * nAmmoUse);
break;
}
}
else
dwShotsPerFire = 0;
//***** If no shots are available, play empty sound and exit the function *****//
if(dwShotsPerFire <= 0)
{
PlayEmptyWeaponSound(bAltFire);
return 0; // Don't fire if we don't have ammo
}
PlayFireSound(bAltFire);
DVector shellDir;
FireSpread(spread, dwShotsPerFire, range, bAltFire, &shellDir);
m_fLastShotTime = cTime;
if(m_eState == WS_ALT_FIRING)
{
m_bLastFireAlt = DTRUE;
nFiredType = 2;
}
else
{
m_bLastFireAlt = DFALSE;
nFiredType = 1;
}
// Reset the shell eject flag for the next fire..
if(m_nAmmoType == AMMO_BULLET || m_nAmmoType == AMMO_SHELL)
m_bEjectShell = DTRUE;
else
m_bEjectShell = DFALSE;
m_nFiredType = nFiredType;
if (((m_nFiredType == 1) && m_hFlashSprite) || ((m_nFiredType == 2) && m_hAltFlashSprite))
{
m_nFlashVisible = (DBYTE)m_nFiredType;
m_fFlashStartTime = m_pClientDE->GetTime();
}
return nFiredType;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::FireSpread()
//
// PURPOSE: Fires the weapon
//
// ----------------------------------------------------------------------- //
void CViewWeapon::FireSpread(Spread *spread, DDWORD shots, DFLOAT range, DBOOL bAltFire, DVector *rDir)
{
if (!m_pClientDE) return;
DVector vTmp;
DVector vU, vR, vF;
m_pClientDE->GetRotationVectors(&m_rRotation, &vU, &vR, &vF);
// Check to see if the player is standing too close to something, and we need
// to move the firing position back in order to hit it
if(FiringTooClose(&vF, 60.0f, &vTmp))
{ VEC_COPY(m_vPosition, vTmp); }
// Send the fire message to the client..
SendFireMsg(&m_vPosition, &vF, g_byRandomWeaponSeed, bAltFire);
VEC_COPY(*rDir, vR);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::FiringTooClose
//
// PURPOSE: Trick to improve accuracy and keep the effect at the weapon end
//
// ----------------------------------------------------------------------- //
DBOOL CViewWeapon::FiringTooClose(DVector *vFire, DFLOAT fDist, DVector *vNewPos)
{
//***** Make sure the server and inventory systems are valid *****//
if (!m_pClientDE || !m_hObject) return DFALSE;
CBloodClientShell *pShell = (CBloodClientShell*)g_pClientDE->GetClientShell();
DFLOAT fOffset = pShell->GetEyeLevel();
DVector vOffset;
VEC_SET(vOffset, 0.0f, fOffset, 0.0f);
// Setup the vectors for the intersect
m_pClientDE->GetObjectPos(m_pClientDE->GetClientObject(), vNewPos);
VEC_ADD(*vNewPos, *vNewPos, vOffset);
VEC_NORM(*vFire);
VEC_MULSCALAR(*vFire, *vFire, fDist);
IntersectQuery iq;
IntersectInfo ii;
// Set the intersection query values
iq.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID | INTERSECT_HPOLY;
// iq.m_FilterFn = LiquidFilterFn;
iq.m_pUserData = DNULL;
VEC_COPY(iq.m_From, *vNewPos);
VEC_ADD(iq.m_To, iq.m_From, *vFire);
VEC_NORM(*vFire);
if(m_pClientDE->IntersectSegment(&iq, &ii))
return DTRUE;
return DFALSE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::SetFirePosRot
//
// PURPOSE: Update the firing state of the gun, keep track of muzzle
// position & rotation (used by AIs)
//
// ----------------------------------------------------------------------- //
void CViewWeapon::SetFirePosRot(DVector *firedPos, DRotation *rotP, DBOOL bAltFire)
{
VEC_COPY(m_vPosition, *firedPos);
ROT_COPY(m_rRotation, *rotP);
m_eState = bAltFire ? WS_ALT_FIRING : WS_FIRING;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CViewWeapon::UpdateFiringState
//
// PURPOSE: Update the firing state of the gun, keep track of muzzle
// position & rotation (used by player objects)
//
// ----------------------------------------------------------------------- //
void CViewWeapon::UpdateFiringState(DVector *firedPos, DRotation *rotP, DBOOL bFiring, DBOOL bAltFiring)
{
if (!m_pClientDE) return;
VEC_COPY(m_vPosition, *firedPos);
ROT_COPY(m_rRotation, *rotP);
DFLOAT fTime = m_pClientDE->GetTime();
DBOOL bAltFire = DFALSE;
switch (m_eState)
{
case WS_IDLE:
{
if(!PlayAnimation(m_nIdleAnim))
{
PlayAnimation(m_nRestAnim);
m_eState = WS_REST;
m_fIdleStartTime = fTime;
m_fIdleDelay = GetRandom(m_fMinIdleDelay, m_fMaxIdleDelay);
m_pClientDE->SetModelLooping(m_hObject, m_bLoopStatic);
}
}
case WS_REST:
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -