📄 weapon.cpp
字号:
//----------------------------------------------------------
//
// MODULE : Weapon.cpp
//
// PURPOSE : General purpose weapon parent
//
// CREATED : 9/20/97
//
//----------------------------------------------------------
// Includes....
#include <stdio.h>
#include "InventoryMgr.h"
#include "BaseCharacter.h"
#include "generic_msg_de.h"
#include "GameProjectiles.h"
#include "PlayerObj.h"
#include "SFXMsgIds.h"
#include "ViewWeaponModel.h"
#include "ClientSparksSFX.h"
#include "ClientMarkSFX.h"
#include "Impacts.h"
//#include "ShellCasing.h"
#include "ObjectUtilities.h"
#include "VolumeBrushTypes.h"
#include "ClientSplashSFX.h"
#include "ClientExplosionSFX.h"
#include "corpse.h"
#include "ai_mgr.h"
#include "DestructableBrush.h"
#include "WeaponDefs.h"
#include "Door.h"
#include "BloodServerShell.h"
void BPrint(char*);
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::CWeapon()
//
// PURPOSE: constructor
//
// ----------------------------------------------------------------------- //
CWeapon::CWeapon(DBYTE dbWeapType)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
m_hOwner = DNULL;
m_hClient = DNULL;
m_pInventoryMgr = DNULL;
m_bInitialized = DFALSE;
m_bClientNotified = DFALSE;
m_nType = dbWeapType;
m_eState = WS_HOLSTERED;
m_pViewModel = DNULL;
WeaponData *wd = &g_WeaponDefaults[m_nType-1];
m_nFireType = wd->m_nFireType;
m_pViewModelFilename = wd->m_szViewModelFilename;
m_pLeftViewModelFilename = wd->m_szLeftViewModelFilename;
m_pViewModelSkinname = wd->m_szViewModelSkin;
m_pHandModelFilename = wd->m_szHandModelFilename;
m_pHandModelSkinname = wd->m_szHandModelSkin;
m_nAmmoType = wd->m_nAmmoType;
m_nAmmoUse = wd->m_nAmmoUse;
m_nAltAmmoUse = wd->m_nAltAmmoUse;
m_fDamage = 0;
m_fMinDamage = wd->m_fMinDamage;
m_fMaxDamage = wd->m_fMaxDamage;
m_fMinAltDamage = wd->m_fMinAltDamage;
m_fMaxAltDamage = wd->m_fMaxAltDamage;
m_fReloadTime = wd->m_fReloadTime;
m_fAltReloadTime = wd->m_fAltReloadTime;
m_Spread = wd->m_Spread;
m_AltSpread = wd->m_AltSpread;
m_fProjVelocity = wd->m_fProjVelocity;
m_fAltProjVelocity = wd->m_fAltProjVelocity;
m_fRange = wd->m_fRange;
m_fAltRange = wd->m_fAltRange;
m_dwShotsPerFire = wd->m_dwShotsPerFire;
m_dwAltShotsPerFire = wd->m_dwAltShotsPerFire;
m_dwStrengthReq = wd->m_dwStrengthReq;
m_dwTwoHandStrengthReq = wd->m_dwTwoHandStrengthReq;
m_bDualHanded = (m_dwTwoHandStrengthReq > 0);
m_nDamageRadius = wd->m_nDamageRadius;
m_nAltDamageRadius = wd->m_nAltDamageRadius;
m_bAltFireZoom = wd->m_bAltFireZoom;
m_bSemiAuto = wd->m_bSemiAuto;
m_szFireSound = wd->m_szFireSound;
m_szAltFireSound = wd->m_szAltFireSound;
m_szEmptyWeaponSound = wd->m_szEmptyWeaponSound;
m_szAltEmptyWeaponSound = wd->m_szAltEmptyWeaponSound;
m_szProjectileClass = wd->m_szProjectileClass;
m_szAltProjectileClass = wd->m_szAltProjectileClass;
m_szWeaponName = wd->m_szWeaponName;
m_nWeaponNameID = wd->m_nWeaponNameID;
m_szFlashSprite = wd->m_szFlashSprite;
m_szAltFlashSprite = wd->m_szAltFlashSprite;
m_fFlashDuration = wd->m_fFlashDuration;
m_fFlashScale = wd->m_fFlashScale;
VEC_COPY(m_vHandModelOffset, wd->m_vHandModelOffset)
VEC_COPY(m_vViewModelOffset, wd->m_vViewModelOffset)
VEC_COPY(m_vMuzzleOffset, wd->m_vMuzzleOffset)
VEC_COPY(m_vRecoil, wd->m_vRecoil)
VEC_COPY(m_vFlash, wd->m_vFlash)
m_fEjectInterval = wd->m_fEjectInterval;
m_fViewKick = wd->m_fViewKick; // Amount to adjust view when firing.
m_bCumulativeKick = wd->m_bCumulativeKick; // Kick is Cumulative
m_bLoopAnim = wd->m_bLoopAnim;
m_bAltLoopAnim = wd->m_bAltLoopAnim;
m_bLoopStatic = DFALSE;
m_fLastShotTime = 0;
m_fFireTime = 0;
m_bLastFireAlt = DFALSE;
if (m_nAmmoType == AMMO_BULLET || m_nAmmoType == AMMO_SHELL)
{
m_bEjectShell = DTRUE;
}
else
{
m_bEjectShell = DFALSE;
}
m_fIdleStartTime = 0.0f;
m_fIdleDelay = 0.0f;
m_fMinIdleDelay = 20.0f;
m_fMaxIdleDelay = 60.0f;
// Create a muzzle flash
m_hFlash = DNULL;
m_pViewModel = DNULL;
m_pHandModel = DNULL;
m_hHandAttachment = DNULL;
m_bFlashShowing = DFALSE;
m_nRestAnim = INVALID_ANI;
m_nIdleAnim = INVALID_ANI;
m_nDrawAnim = INVALID_ANI;
m_nDrawDuelAnim = INVALID_ANI;
m_nHolsterAnim = INVALID_ANI;
m_nHolsterDuelAnim = INVALID_ANI;
m_nStartFireAnim = INVALID_ANI;
m_nFireAnim = INVALID_ANI;
m_nStopFireAnim = INVALID_ANI;
m_nStartAltFireAnim = INVALID_ANI;
m_nAltFireAnim = INVALID_ANI;
m_nStopAltFireAnim = INVALID_ANI;
m_nDamageType = DAMAGE_TYPE_NORMAL;
for (int i=0; i < MAX_FIRE_SOUNDS; i++)
{
m_hCurFireSounds[i] = DNULL;
m_fCurFireSoundsEndTime[i] = 0.0f;
}
m_nUpdateWait = 10;
m_nFlags = DNULL;
m_szPic = DNULL;
m_szPicH = DNULL;
m_bAccuracyCheck = DTRUE;
m_bMultiDamageBoost = DFALSE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::~CWeapon()
//
// PURPOSE: destructor
//
// ----------------------------------------------------------------------- //
CWeapon::~CWeapon()
{
Term();
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::Init()
//
// PURPOSE: Initializes the weapon
//
// ----------------------------------------------------------------------- //
void CWeapon::Init(HOBJECT hOwner, CInventoryMgr* pInventoryMgr, DBOOL bLeftHand, HOBJECT hMuzzleFlash)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!hOwner || !pInventoryMgr) return;
m_hOwner = hOwner;
m_pInventoryMgr = pInventoryMgr;
m_bLeftHand = bLeftHand;
if (m_bLeftHand)
{
m_vViewModelOffset.x = -m_vViewModelOffset.x;
m_vFlash.x = -m_vFlash.x;
m_vMuzzleOffset.x = -m_vMuzzleOffset.x;
}
m_hFlash = hMuzzleFlash;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::SetClient()
//
// PURPOSE: Sets the client for the weapon, and initializes a player view model.
//
// ----------------------------------------------------------------------- //
void CWeapon::SetClient(HCLIENT hClient, CViewWeaponModel *pViewModel)
{
m_hClient = hClient;
// Create the view weapon model if it's a Player object
m_pViewModel = pViewModel;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::Term()
//
// PURPOSE: Terminates this weapon
//
// ----------------------------------------------------------------------- //
void CWeapon::Term()
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (m_hHandAttachment)
{
pServerDE->RemoveAttachment(m_hHandAttachment);
m_hHandAttachment = DNULL;
}
if (m_pHandModel)
{
pServerDE->RemoveObject(m_pHandModel->m_hObject);
m_pHandModel->SetWeaponOwner( NULL );
m_pHandModel = DNULL;
}
if( m_szPic )
{
pServerDE->FreeString( m_szPic );
m_szPic = DNULL;
}
if( m_szPicH )
{
pServerDE->FreeString( m_szPicH );
m_szPicH = DNULL;
}
KillSounds();
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::IsIdle()
//
// PURPOSE: Terminates this weapon
//
// ----------------------------------------------------------------------- //
DBOOL CWeapon::IsChanging()
{
if(IsOwnerAPlayer())
{
if((m_eState == WS_DRAW) || (m_eState == WS_HOLSTER))
return DTRUE;
}
return DFALSE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::Draw()
//
// PURPOSE: draws the weapon, sets filenames
//
// ----------------------------------------------------------------------- //
void CWeapon::Draw()
{
m_eState = WS_DRAW;
SetupMuzzleFlash();
if (m_hClient)
{
SetupViewModel();
}
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::CheckAmmo()
//
// PURPOSE: returns amount of ammo available to this weapon
//
// ----------------------------------------------------------------------- //
DFLOAT CWeapon::CheckAmmo(DBOOL bAltFire)
{
// If the No Ammo is required for the Weapon then return 1
if (GetAmmoType(bAltFire) == AMMO_NONE)
{
return 1.0f;
}
if (m_pInventoryMgr)
return m_pInventoryMgr->GetAmmoCount(GetAmmoType(bAltFire));
else
return 0.0f;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::CheckDamageMultiplier()
//
// PURPOSE: returns the owner's damage multiplier
//
// ----------------------------------------------------------------------- //
DFLOAT CWeapon::GetDamageMultiplier()
{
if (m_pInventoryMgr)
return m_pInventoryMgr->GetDamageMultiplier();
else
return 0.0f;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::ShowHandModel()
//
// PURPOSE: Creates and shows or destroys and hides the hand model.
//
// ----------------------------------------------------------------------- //
void CWeapon::ShowHandModel(DBOOL bShow)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (bShow) // Create it.
{
if (!m_pHandModel)
{
CreateHandModel();
}
}
else // Remove it.
{
if (m_hHandAttachment)
{
pServerDE->RemoveAttachment(m_hHandAttachment);
m_hHandAttachment = DNULL;
}
if (m_pHandModel && m_pHandModel->m_hObject)
{
pServerDE->RemoveObject(m_pHandModel->m_hObject);
m_pHandModel->SetWeaponOwner( NULL );
m_pHandModel = DNULL;
}
}
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::Update()
//
// PURPOSE: Updates this weapon's position
//
// ----------------------------------------------------------------------- //
void CWeapon::Update()
{
CServerDE* pServerDE = BaseClass::GetServerDE();
if (!pServerDE || !m_hOwner) return;
// This flag shows that the weapon has had an update, so it's now ok to
// send the view object to the client.
if (!m_bInitialized)
{
m_bInitialized = DTRUE;
}
// Kill the sound if it's played long enough
for(int i = 0; i < MAX_FIRE_SOUNDS; i++)
{
DBOOL bSoundDone = DFALSE;
if (m_hCurFireSounds[i] && pServerDE->IsSoundDone(m_hCurFireSounds[i], &bSoundDone) == LT_OK && bSoundDone)
{
pServerDE->KillSound(m_hCurFireSounds[i]);
m_hCurFireSounds[i] = DNULL;
}
}
// Update muzzle flash
if (m_bFlashShowing)
{
UpdateMuzzleFlash();
}
// Set color to match the owner (stealth pu..)
if (m_hOwner && m_pHandModel && m_pHandModel->m_hObject)
{
DVector vColor;
DFLOAT fAlpha;
pServerDE->GetObjectColor(m_hOwner, &vColor.x, &vColor.y, &vColor.z, &fAlpha);
pServerDE->SetObjectColor(m_pHandModel->m_hObject, vColor.x, vColor.y, vColor.z, fAlpha);
}
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: CWeapon::PlayFireSound()
//
// PURPOSE: Plays the firing sound
//
// ----------------------------------------------------------------------- //
void CWeapon::PlayFireSound(DBOOL bAltFire)
{
CServerDE* pServerDE = BaseClass::GetServerDE();
HSOUNDDE hSound = DNULL;
char *sound;
DBOOL bLoop = DFALSE;
if (bAltFire)
{
sound = m_szAltFireSound;
}
else
{
sound = m_szFireSound;
}
if (sound && _mbstrlen(sound) > 0)
{
DFLOAT Radius = 2000.0f;
DBYTE sndtype = IsOwnerAPlayer() ? SOUNDPRIORITYBASE_PLAYER : SOUNDPRIORITYBASE_AI;
hSound = PlaySoundFromObject(m_hOwner, sound, Radius, sndtype + SOUNDPRIORITYMOD_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;
pServerDE->GetSoundDuration(hSound, &fTime);
fTime += pServerDE->GetTime();
if (m_hCurFireSounds[nIndex])
pServerDE->KillSound(m_hCurFireSounds[nIndex]);
m_hCurFireSounds[nIndex] = hSound;
m_fCurFireSoundsEndTime[nIndex] = fTime;
}
else
{
pServerDE->KillSound(hSound);
hSound = DNULL;
}
}
}
// ----------------------------------------------------------------------- //
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -