📄 destructable.cpp
字号:
//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 + -