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

📄 destructable.cpp

📁 Blood 2全套源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
			//Compute one side got hit for recoils
			DVector vU, vR, vF, vTmpDir;
			DRotation rRot;
			pServerDE->GetObjectRotation(m_hObject, &rRot);
			pServerDE->GetRotationVectors(&rRot, &vU, &vR, &vF);

			VEC_COPY(vTmpDir, vDir);

			VEC_MULSCALAR(vTmpDir,vTmpDir,-1.0f);
			DFLOAT fAmount = (DFLOAT) atan2(vTmpDir.x, vTmpDir.z);    
			DFLOAT fAmount2 = (DFLOAT) atan2(vF.x, vF.z);

			if(fAmount < 0.0f)
				fAmount = (MATH_PI*2) + fAmount;
			if(fAmount2 < 0.0f)
				fAmount2 = (MATH_PI*2) + fAmount2;

			DFLOAT fAngle = fAmount2 - fAmount;

			if(fAngle <= MATH_PI/2 || fAngle >= 3*MATH_PI/2)	//Hit the front
			{
				m_nSideHit = 0;
			}
			else //Hit the back
			{
				m_nSideHit = 6;	
			}

			if (m_hLastDamager)
				pServerDE->BreakInterObjectLink(m_hObject, m_hLastDamager);

			m_hLastDamager = hWhoHit;

			if(m_hLastDamager)
				pServerDE->CreateInterObjectLink(m_hObject, m_hLastDamager);

			if(m_nNodeHit == NODE_NECK)
			{
				AI_Mgr* pAI = (AI_Mgr*)pServerDE->HandleToObject(m_hObject);

				if(pAI->m_bCabal || pServerDE->IsKindOf(pServerDE->GetObjectClass(m_hObject), pServerDE->GetClass("SoulDrudge")))
					m_fHitPoints = 0;
				
				fDamage *= 1.5f;
			}
			else if(m_nNodeHit == NODE_TORSO)
			{
				fDamage *= 1.0f;
			}
			else
			{
				fDamage *= 0.5f;
			}
		}

		if (IsBaseCharacter(m_hObject))
		{
			CBaseCharacter *pOwner = (CBaseCharacter*)pServerDE->HandleToObject(m_hObject);

//			if (pOwner->IsItemActive(SPELL_STONE))
//				return;

			// If Nigh-invulnerability powerup in effect..
			if (m_bNighInvulnerable)
				fDamage = fDamage * 0.05f;

			// Shield absorbs the damage as Focus ammo use
/*			if (nDamageType != DAMAGE_TYPE_DEATH && pOwner->IsItemActive(SPELL_SHIELD))
			{
				DFLOAT fFocusAmmo = pOwner->GetInventoryMgr()->GetAmmoCount(AMMO_FOCUS);
		
				fFocusAmmo -= fDamage;

				if (fFocusAmmo < 0.0f)
				{
					fDamage = -fFocusAmmo;
					fFocusAmmo = 0.0f;
				}
				else
				{
					fDamage = 0.0f;
				}

				pOwner->GetInventoryMgr()->SetAmmoCount(AMMO_FOCUS, fFocusAmmo);
			}
*/
			// Reflection reflects damage back to the sender, and absorbs 
			// twice the damage in focus ammo
/*			if (pOwner->IsItemActive(SPELL_REFLECTION) && !(nDamageType & DAMAGE_FLAG_AREAEFFECT))
			{
				DFLOAT fFocusAmmo = pOwner->GetInventoryMgr()->GetAmmoCount(AMMO_FOCUS);
		
				fFocusAmmo -= fDamage * 2.0f;

				if (fFocusAmmo < 0.0f)
				{
					fDamage = -fFocusAmmo / 2.0f;
					fFocusAmmo = 0.0f;
				}
				else
				{
					fDamage = 0.0f;
				}

				pOwner->GetInventoryMgr()->SetAmmoCount(AMMO_FOCUS, fFocusAmmo);
			}
*/
		}

		// If single player, don't let the player apply damage to himself.
		if (m_bApplyDamagePhysics && !(g_pBloodServerShell->GetGameType() == GAMETYPE_SINGLE && (m_hObject == hWhoHit) && IsPlayer(m_hObject)))
			ApplyDamagePhysics(fDamage, &vDir);
		
		// Can't damage if already dead...

		if( m_bDestructable && m_bDead )
			return;

		if( m_bDestructable && m_fArmorPoints > 0.0 && nDamageType != DAMAGE_TYPE_SUFFOCATE )
		{
			DFLOAT fAbsorb = 0.0f;

			if (m_fArmorPoints <= 25.0f)
				fAbsorb = fDamage * 0.3f;
			else if (m_fArmorPoints <= 50.0f)
				fAbsorb = fDamage * 0.5f;
			else if (m_fArmorPoints <= 100.0f)
				fAbsorb = fDamage * 0.7f;
			else if (m_fArmorPoints <= 150.0f)
				fAbsorb = fDamage * 0.8f;
			else 
				fAbsorb = fDamage * 0.9f;

			if (!m_bGodMode)
			{
				m_fArmorPoints -= fAbsorb;
				if (m_fArmorPoints < 0.0f) 
				{
					fAbsorb += m_fArmorPoints;
					m_fArmorPoints = 0.0f;
				}
        
				fDamage -= fAbsorb;
       		}
		}

		if (fDamage < 0.0f) fDamage = 0.0f;	// just to be sure :)

		// Save damage type so entity will know how to react
		nDamageType &= 0x0f;	// Mask off the damage type flags
		if (fDamage) m_nLastDamageType = nDamageType;

		if( m_bDestructable )
		{
			m_fHitPoints -= fDamage;
			m_fDeathHitPoints -= fDamage;
		}
	}
	// 01/13/98  How much damage was done (percentage of max hit points)
	m_fLastDamagePercent += (DFLOAT)fDamage/(DFLOAT)GetMaxHitPoints();
	m_fLastDamageAmount += fDamage;
	VEC_COPY(m_vLastDamageDirection, vDir);

	// Set pSender if sender is a player
	CPlayerObj* pSender = DNULL;

	if( m_bDestructable )
	{
		if(hWhoHit)
			if(pServerDE->IsKindOf(pServerDE->GetObjectClass(hWhoHit), pServerDE->GetClass("CPlayerObj")))
				pSender = (CPlayerObj*)pServerDE->HandleToObject(hWhoHit);

		// If it was hurt with a leech weapon, then add the damage done back to playerobj
		if(pSender && pServerDE->IsKindOf(pServerDE->GetObjectClass(m_hObject), pServerDE->GetClass("CBaseCharacter")))
		{
			if(nDamageType == DAMAGE_TYPE_LEECH)
			{
				if (!pSender->IsDead() && !pSender->IsInSlowDeath())
				{
					pSender->GetDestructable()->Heal(fDamage / 10.0f);
				}
			}
		}
	}

//	m_fHitPoints = 1;
	if( m_bDestructable && m_fHitPoints <= 0 )
	{
		m_bDead = DTRUE;
		m_fHitPoints = 0;
		HandleDestruction();

		m_hWhoKilledMeLast = hWhoHit;

        // If its a PlayerObj then Increase the Kills 
/*		if(pSender && pServerDE->IsKindOf(pServerDE->GetObjectClass(m_hObject), pServerDE->GetClass("CBaseCharacter"))) 
		{
            // If it was killed with a melee weapon, then add the damage done back to playerobj
        	if(nDamageType == DAMAGE_TYPE_LEECH)
            {
				pSender->GetDestructable()->Heal(fDamage / 5.0f);
				pSender->AddMeleeKill();

				DFLOAT fIncrease = 0.0f;
				int nKills = pSender->GetMeleeKills();
        
				if (nKills > 0)
				{
                    // Increase Damage by 5% for every kill
                    fIncrease = (DFLOAT)nKills * .05f;
                    // Max Increase 200%
                    if (fIncrease > 2.0f)   fIncrease = 2.0f;
                }            
                
                // If the Increase is greater than 50% then add back some of the damage to player
                if (fIncrease > 0.5f)
                {
                    // Add back damage to playerobj
                    DFLOAT fAddHits = fDamage * (fIncrease/2.0f);
                    
    				pSender->GetDestructable()->Heal(fAddHits);
                    
                    // Need to Glow the player Sword...
                    // Set Glow on the Melee Weapon
                    
                }
            }
        }*/
	}


	// If this is supposed to send a damage trigger, send it now..

	if( m_bDestructable && m_hstrDamageTriggerTarget && m_hstrDamageTriggerMessage )
	{
		LPBASECLASS pD = pServerDE->HandleToObject(m_hObject);
		SendTriggerMsgToObjects(pD, m_hstrDamageTriggerTarget, m_hstrDamageTriggerMessage);
	}

	// If player did this damage and has soul stealing binding..
	if( m_bDestructable && fOldHitPoints != m_fHitPoints && m_hObject != hWhoHit)
	{
		// Make sure it's a player
		if(pSender) 
		{
			DFLOAT fHeal;
			if (pSender->HasSoulStealingBinding() && (fHeal = (fOldHitPoints - m_fHitPoints) / 10.0f))
			{
				pSender->GetDestructable()->Heal(fHeal);
			}
		}
	}
}


// --------------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::HandleTrigger()
//
//	PURPOSE:	Handler for trigger messages - Handles the KILL trigger
//
// --------------------------------------------------------------------------- //

void CDestructable::HandleTrigger(HOBJECT hSender, HMESSAGEREAD hRead)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE) return;

	HSTRING hMsg = pServerDE->ReadFromMessageHString(hRead);

	char* pMsg = pServerDE->GetStringData(hMsg);
	if (!pMsg || !pMsg[0]) return;

	if (_mbsicmp((const unsigned char*)pMsg, (const unsigned char*)TRIGGER_MSG_KILL) == 0)
	{
		DVector vTmp;
		VEC_INIT(vTmp);
		BaseClass *ffObj = pServerDE->HandleToObject(hSender);
		DamageObject(hSender, ffObj, m_hObject, 1, vTmp, vTmp, DAMAGE_TYPE_DEATH);
	}
	pServerDE->FreeString(hMsg);
}

// ----------------------------------------------------------------------- //
// ROUTINE		: CDestructable::SetProperNode
// DESCRIPTION	: Set the hit node to the parent node of the limb
// RETURN TYPE	: int 
// PARAMS		: int nNode
// ----------------------------------------------------------------------- //

int CDestructable::SetProperNode(int nNode)
{
	switch(nNode)
	{
		case 0:		return NODE_NECK;
		case 1:		return NODE_NECK;
		case 2:		return NODE_TORSO;
		case 3:		return NODE_TORSO;
		case 4:		return NODE_RARM;
		case 5:		return NODE_RARM;
		case 6:		return NODE_RARM;
		case 7:		return NODE_LARM;
		case 8:		return NODE_LARM;
		case 9:		return NODE_LARM;
		case 10:	return NODE_LLEG;
		case 11:	return NODE_LLEG;
		case 12:	return NODE_LLEG;
		case 13:	return NODE_LLEG;
		case 14:	return NODE_RLEG;
		case 15:	return NODE_RLEG;
		case 16:	return NODE_RLEG;
		case 17:	return NODE_RLEG;
		default:	return -1;
	}

	return -1;
}

// ----------------------------------------------------------------------- //
// ROUTINE		: CDestructable::CalculateHitLimb
// DESCRIPTION	: 
// RETURN TYPE	: int
// ----------------------------------------------------------------------- //

int CDestructable::CalculateHitLimb(DVector vDir, DVector vPos, DFLOAT fDamage)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE || !m_hObject || !m_pInventoryMgr || !m_pAnim_Sound) return -1;

	int nNode = -1;
	DFLOAT fNodeDist = 0.0f, fDist = 999.0f, fTemp = 0.0f;
	DVector vShot, vNewShot, vTemp, vObjDims, vNodePos, vZ;
	DFLOAT fX, fY, ft;
	DBOOL bStatus = DFALSE;
	DRotation rRot;

	if(pServerDE->GetModelAnimUserDims(m_hObject, &vObjDims, pServerDE->GetModelAnimation(m_hObject)) == DE_INVALIDPARAMS)
		pServerDE->DebugOut("CalculateHitLimb() fucked up\r\n");

	vTemp.x = (float)fabs(vDir.x);
	vTemp.y = (float)fabs(vDir.y);
	vTemp.z = (float)fabs(vDir.z);

	if(vTemp.x > vTemp.y && vTemp.x > vTemp.z)
	{
		fTemp = vObjDims.x / vTemp.x;
	}
	else if(vTemp.y > vTemp.x  && vTemp.y > vTemp.z)
	{
		fTemp = vObjDims.y / vTemp.y;
	}
	else if(vTemp.z > vTemp.x  && vTemp.z > vTemp.y)
	{
		fTemp = vObjDims.z / vTemp.z;
	}

	VEC_MULSCALAR(vNewShot,vDir,fTemp);
	VEC_ADD(vShot,vPos,vNewShot);

	DVector vC;
	VEC_SUB(vC,vShot,vPos);

	fX = 1 / VEC_DOT(vC,vC);
	fY = fX * -(VEC_DOT(vC,vPos));
	
	for(int i = 0; i < NUM_STD_NODES; i++)
	{
		pServerDE->GetModelNodeHideStatus(m_hObject, szNodes[i], &bStatus);

		if(!bStatus)
		{
			DBOOL bRet = pServerDE->GetModelNodeTransform(m_hObject, szNodes[i], &vNodePos, &rRot);

			ft = VEC_DOT(vC,vNodePos) * fX + fY;

			if(ft >= 0.0f && ft <= 1.0f)
			{
				VEC_ADDSCALED(vZ,vPos,vC, ft);

				fNodeDist = VEC_DIST(vNodePos, vZ);

				if(fNodeDist < fDist && fNodeDist <= m_pAnim_Sound->m_fHitSpheres[i])
				{
					fDist = fNodeDist;
					nNode = i;
				}
			}
		}
	}
/*
	//Do we leave a pass through mark behind us?	
	if(nNode != -1)
	{
		CWeapon *pW = m_pInventoryMgr->GetCurrentWeapon();

		if(pW)
		{
			VEC_MULSCALAR(vTemp,vDir,-1.0f);
			// TODO: combine sparks with weaponFX GK 8/27
//			pW->AddSparks(vPos, vTemp, fDamage * 2.0f, m_hObject, SURFTYPE_FLESH);	
//			pW->AddBloodSpurt(vPos, vTemp, fDamage * 2.0f, m_hObject, SURFTYPE_FLESH);	

//			Took this out - more efficient to send one message. GK 8/27
//			vTemp.x *= -1.0f;
//			vTemp.z *= -1.0f;
//			pW->AddBloodSpurt(vPos, vTemp, fDamage * 2.0f, m_hObject, SURFTYPE_FLESH);	

			IntersectQuery	iq;
			IntersectInfo	ii;

			// Set the intersection query values
			iq.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID;
			iq.m_FilterFn = DNULL;
			iq.m_pUserData = DNULL;

			VEC_COPY(iq.m_From, vPos);
			VEC_ADDSCALED(iq.m_To, vPos, vDir, 75.0f);

			// Apply a blood splat to the wall
			if(pServerDE->IntersectSegment(&iq, &ii) && (ii.m_hObject == pServerDE->GetWorldObject()))
			{
//				pW->AddImpact(WFX_BLOODSPLAT, ii.m_Point, vDir, ii.m_Plane.m_Normal, fDamage * 2.0f, 
//							  ii.m_hObject, SURFTYPE_FLESH);
//				pW->AddSparks(ii.m_Point, ii.m_Plane.m_Normal, fDamage * 2.0f, ii.m_hObject, SURFTYPE_FLESH);	
			}
		}
	}
*/
	return nNode;
}

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	CDestructable::ApplyDamagePhysics
//
//	PURPOSE:	Applies physics when hit
//
// ----------------------------------------------------------------------- //

void CDestructable::ApplyDamagePhysics(DFLOAT fDamage, DVector *pvDir)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE || !m_hObject || !pvDir) return;

	// Don't apply damage physics if the object is a trapped character (Andy 2/22/99)
	if(IsBaseCharacter(m_hObject))
	{
		CBaseCharacter *pObj = (CBaseCharacter*)pServerDE->HandleToObject(m_hObject);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -