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

📄 viewweapon.cpp

📁 Blood 2全套源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	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 + -