예제 #1
0
DBOOL CDestructable::Heal(DFLOAT fAmount)
{
	// Sanity checks...

	if (m_fHitPoints >= m_fMaxHitPoints)
		return DFALSE;


	// Check if this is a humiliated player in a multiplayer game...

	if (g_pBloodServerShell->IsMultiplayerGame())
	{
		if (IsPlayer(m_hObject))
		{
			CPlayerObj* pPlayer = (CPlayerObj*)g_pServerDE->HandleToObject(m_hObject);
			if (pPlayer && pPlayer->IsInSlowDeath())
			{
				return(DFALSE);
			}
		}
	}


	// Heal...

	m_bDead = DFALSE;

	m_fHitPoints += fAmount;
	if(m_fHitPoints > m_fMaxHitPoints)
		m_fHitPoints = m_fMaxHitPoints;
	m_fDeathHitPoints = m_fHitPoints;


	// All done...

	return DTRUE;
}
예제 #2
0
void CDestructable::HandleDamage(HOBJECT hSender, HMESSAGEREAD hRead)
{
	CServerDE* pServerDE = BaseClass::GetServerDE();
	if (!pServerDE) return;

	DVector vDir,vPos;

	pServerDE->ReadFromMessageVector(hRead, &vDir);
	DFLOAT fDamage = pServerDE->ReadFromMessageFloat(hRead);
	DBYTE nDamageType	= pServerDE->ReadFromMessageByte(hRead);
	HOBJECT hWhoHit = pServerDE->ReadFromMessageObject(hRead);
	pServerDE->ReadFromMessageVector(hRead, &vPos);

//	char buf[50];
	DFLOAT fOldHitPoints = m_fHitPoints;
	fDamage = fDamage * m_fResistance;

	// Just return if we can't take damage
	if (m_bGodMode || (m_bTriggerOnly && nDamageType != DAMAGE_TYPE_DEATH) || fDamage < 0)
	{
		return;
	}

	if (!IsPlayerToPlayerDamageOk(hSender, hWhoHit))
	{
		return;
	}

	// If instant death, don't bother calculating stuff.. 
	if( m_bDestructable && nDamageType == DAMAGE_TYPE_DEATH)
	{
		m_fArmorPoints = 0;
		m_fHitPoints = 0;
		m_fDeathHitPoints = 0;
		m_fLastDamagePercent = 100.0f;
		m_fLastDamageAmount = (DFLOAT)m_fMaxHitPoints;

		nDamageType &= 0x0f;	// Mask off the damage type flags
		m_nLastDamageType = nDamageType;
	}
	else
	{
		// Special pre-damage base character modifiers
		if (IsAICharacter(m_hObject))
		{
			m_nNodeHit = CalculateHitLimb(vDir,vPos,fDamage);

			if(m_nNodeHit == -1 && !(nDamageType & DAMAGE_TYPE_NORMAL))
				m_nNodeHit = SetProperNode(pServerDE->IntRandom(0,NUM_ALL_NODES - 3));
			else if(m_nNodeHit >= 0)
				m_nNodeHit = SetProperNode(m_nNodeHit);
			else
				return;

			//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);
			}
		}
	}
}