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