void CProjectile::Explode() { if (!g_pServerDE) return; DVector vPos; g_pServerDE->GetObjectPos(m_hObject, &vPos); AddImpact(vPos, vPos, m_hHitObject); if(m_nRadius) { DamageObjectsWithinRadius(); } else if (m_hHitObject) { // Send damage message to object... DamageObject(m_hFiredFrom, this, m_hHitObject, m_fDamage, m_vDir, vPos, m_nDamageType); } if (m_hHitObject) { g_pServerDE->BreakInterObjectLink(m_hObject, m_hHitObject); m_hHitObject = DFALSE; } }
LTBOOL CProjectile::TestInsideObject(HOBJECT hTestObj, AmmoType eAmmoType) { if (!hTestObj) return LTFALSE; // TO DO??? // NOTE: This code may need to be updated to use test the dims // of the CharacterHitBox instead of the dims of the object... // TO DO??? // See if we are inside the test object... LTVector vTestPos, vTestDims; g_pLTServer->GetObjectPos(hTestObj, &vTestPos); g_pLTServer->GetObjectDims(hTestObj, &vTestDims); if (m_vFirePos.x < vTestPos.x - vTestDims.x || m_vFirePos.x > vTestPos.x + vTestDims.x || m_vFirePos.y < vTestPos.y - vTestDims.y || m_vFirePos.y > vTestPos.y + vTestDims.y || m_vFirePos.z < vTestPos.z - vTestDims.z || m_vFirePos.z > vTestPos.z + vTestDims.z) { return LTFALSE; } // We're inside the object, so we automatically hit the object... if (eAmmoType == PROJECTILE) { Detonate(hTestObj); } else { if (eAmmoType == VECTOR) { if (IsCharacter(hTestObj)) { CCharacter *pChar = (CCharacter*) g_pLTServer->HandleToObject(hTestObj); if (!pChar) return LTFALSE; ModelNode eModelNode = g_pModelButeMgr->GetSkeletonDefaultHitNode(pChar->GetModelSkeleton()); pChar->SetModelNodeLastHit(eModelNode); m_fInstDamage *= pChar->ComputeDamageModifier(eModelNode); } ImpactDamageObject(m_hFiredFrom, hTestObj); } LTVector vNormal(0, 1, 0); AddImpact(hTestObj, m_vFlashPos, vTestPos, vNormal, GetSurfaceType(hTestObj)); } RemoveObject(); return LTTRUE; }
void CProjectile::Detonate(HOBJECT hObj) { if (m_bDetonated) return; // Make sure we don't detonate if a cinematic is playing (i.e., // make sure the user doesn't disrupt the cinematic)... if (Camera::IsActive()) { RemoveObject(); return; } m_bDetonated = LTTRUE; SurfaceType eType = ST_UNKNOWN; LTVector vPos; g_pLTServer->GetObjectPos(m_hObject, &vPos); // Determine the normal of the surface we are impacting on... LTVector vNormal(0.0f, 1.0f, 0.0f); if (hObj) { if (IsMainWorld(hObj) || g_pLTServer->GetObjectType(hObj) == OT_WORLDMODEL) { CollisionInfo info; g_pLTServer->GetLastCollision(&info); if (info.m_hPoly) { eType = GetSurfaceType(info.m_hPoly); } LTPlane plane = info.m_Plane; vNormal = plane.m_Normal; // Calculate where we really hit the plane... LTVector vVel, vP0, vP1, vDir; g_pLTServer->GetVelocity(m_hObject, &vVel); vDir = vVel; vDir.Norm(); vP1 = vPos; vVel *= g_pLTServer->GetFrameTime(); vP0 = vP1 - vVel; vP1 += vVel; // Make sure we don't tunnel through an object... IntersectInfo iInfo; IntersectQuery qInfo; qInfo.m_Flags = INTERSECT_HPOLY | INTERSECT_OBJECTS | IGNORE_NONSOLID; qInfo.m_From = vP0; qInfo.m_To = vPos; qInfo.m_FilterFn = SpecificObjectFilterFn; qInfo.m_pUserData = m_hObject; if (g_pLTServer->IntersectSegment(&qInfo, &iInfo)) { vPos = iInfo.m_Point - vDir; eType = GetSurfaceType(iInfo); vNormal = iInfo.m_Plane.m_Normal; } else { //g_pLTServer->CPrint("P0 = %.2f, %.2f, %.2f", VEC_EXPAND(vP0)); //g_pLTServer->CPrint("P1 = %.2f, %.2f, %.2f", VEC_EXPAND(vP1)); //LTVector vDist = vP1 - vP0; //g_pLTServer->CPrint("Distance from P0 to P1: %.2f", vDist.Mag()); LTFLOAT fDot1 = VEC_DOT(vNormal, vP0) - info.m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT(vNormal, vP1) - info.m_Plane.m_Dist; if (fDot1 < 0.0f && fDot2 < 0.0f || fDot1 > 0.0f && fDot2 > 0.0f) { vPos = vP1; } else { LTFLOAT fPercent = -fDot1 / (fDot2 - fDot1); //g_pLTServer->CPrint("Percent: %.2f", fPercent); VEC_LERP(vPos, vP0, vP1, fPercent); } } LTRotation rRot; g_pLTServer->AlignRotation(&rRot, &vNormal, LTNULL); g_pLTServer->SetObjectRotation(m_hObject, &rRot); // g_pLTServer->CPrint("Pos = %.2f, %.2f, %.2f", VEC_EXPAND(vPos)); } } else { // Since hObj was null, this means the projectile's lifetime was up, // so we just blew-up in the air. eType = ST_AIR; } if (eType == ST_UNKNOWN) { eType = GetSurfaceType(hObj); } AddImpact(hObj, m_vFlashPos, vPos, vNormal, eType); // Handle impact damage... if (hObj) { HOBJECT hDamager = m_hFiredFrom ? m_hFiredFrom : m_hObject; ImpactDamageObject(hDamager, hObj); } //g_pLTServer->CPrint("Server end pos (%.2f, %.2f, %.2f)", vPos.x, vPos.y, vPos.z); //g_pLTServer->CPrint("Server fly time %.2f", g_pLTServer->GetTime() - m_fStartTime); // Remove projectile from world... RemoveObject(); }
LTBOOL CProjectile::HandleVectorImpact(IntersectInfo & iInfo, LTVector & vFrom, LTVector & vTo) { // Get the surface type... SurfaceType eSurfType = GetSurfaceType(iInfo); // See if we hit an invisible surface... if (eSurfType == ST_INVISIBLE) { if (!CalcInvisibleImpact(iInfo, eSurfType)) { SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eSurfType); if (!pSurf) return LTTRUE; return UpdateDoVectorValues(*pSurf, 0, iInfo.m_Point, vFrom, vTo); } } // See if we hit an object that should be damaged... LTBOOL bHitWorld = IsMainWorld(iInfo.m_hObject); if (!bHitWorld && eSurfType != ST_LIQUID) { ImpactDamageObject(m_hFiredFrom, iInfo.m_hObject); } // If the fire position is the initial fire position, use the flash // position when building the impact special fx... LTVector vFirePos = (vFrom.Equals(m_vFirePos) ? m_vFlashPos : vFrom); AddImpact(iInfo.m_hObject, vFirePos, iInfo.m_Point, iInfo.m_Plane.m_Normal, eSurfType); // See if we can shoot through the surface... SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eSurfType); if (!pSurf) return LTTRUE; // Done. if (pSurf->bCanShootThrough) { int nMaxThickness = pSurf->nMaxShootThroughThickness; if (nMaxThickness == 0) { // Special case of always being able to shoot through surface... // Calculate new values for next DoVector iteration... return UpdateDoVectorValues(*pSurf, 0, iInfo.m_Point, vFrom, vTo); } // Test if object/wall intersected is thin enough to be shot // through... // Test object case first... if (!bHitWorld && iInfo.m_hObject) { // Test to see if we can shoot through the object... LTVector vDims; g_pLTServer->GetObjectDims(iInfo.m_hObject, &vDims); if (vDims.x*2.0f >= nMaxThickness && vDims.y*2.0f >= nMaxThickness && vDims.z*2.0f >= nMaxThickness) { // Can't shoot through this object... return LTTRUE; } } // Determine if we shot through the wall/object... IntersectInfo iTestInfo; IntersectQuery qTestInfo; qTestInfo.m_From = iInfo.m_Point + (m_vDir * (LTFLOAT)(nMaxThickness + 1)); qTestInfo.m_To = iInfo.m_Point - m_vDir; qTestInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID | INTERSECT_HPOLY; qTestInfo.m_FilterFn = DoVectorFilterFn; qTestInfo.m_pUserData = m_hFiredFrom; if (g_pLTServer->IntersectSegment(&qTestInfo, &iTestInfo)) { // Calculate new values for next DoVector iteration... LTVector vThickness = iTestInfo.m_Point - iInfo.m_Point; return UpdateDoVectorValues(*pSurf, vThickness.Mag(), iTestInfo.m_Point, vFrom, vTo); } } return LTTRUE; }
void CProjectile::DoVector() { IntersectInfo iInfo; IntersectQuery qInfo; LTVector vTo, vFrom, vOriginalFrom; vFrom = m_vFirePos; vTo = vFrom + (m_vDir * m_fRange); qInfo.m_Flags = INTERSECT_OBJECTS | IGNORE_NONSOLID | INTERSECT_HPOLY; LTBOOL bHitSomething = LTFALSE; LTBOOL bDone = LTFALSE; int nLoopCount = 0; // No infinite loops thanks. HOBJECT hLastHitbox = LTNULL; while (!bDone) { qInfo.m_PolyFilterFn = DoVectorPolyFilterFn; qInfo.m_FilterFn = DoVectorFilterFn; qInfo.m_pUserData = m_hFiredFrom; qInfo.m_From = vFrom; qInfo.m_To = vTo; if (g_pLTServer->IntersectSegment(&qInfo, &iInfo)) { HCLASS hClass = g_pLTServer->GetObjectClass(iInfo.m_hObject); if ( iInfo.m_hObject == hLastHitbox ) { _ASSERT(LTFALSE); g_pLTServer->CPrint("ERROR: vector intersected character hitbox twice"); bDone = LTTRUE; continue; } if (IsCharacterHitBox(iInfo.m_hObject)) { hLastHitbox = iInfo.m_hObject; vOriginalFrom = vFrom; if (HandlePotentialHitBoxImpact(iInfo, vFrom)) { HandleVectorImpact(iInfo, vOriginalFrom, vTo); return; } } else { if (HandleVectorImpact(iInfo, vFrom, vTo)) { return; } } } else // Didn't hit anything... { bDone = LTTRUE; } // Melee weapons can't shoot through objects... if (m_pAmmoData->eInstDamageType == DT_MELEE) { bDone = LTTRUE; } // Make sure we don't loop forever... if (++nLoopCount > MAX_VECTOR_LOOP) { g_pLTServer->CPrint("ERROR in CProjectile::DoVector() - Infinite loop encountered!!!"); bDone = LTTRUE; } } // Didn't hit anything so just impact at the end pos... LTVector vUp(0.0f, 1.0f, 0.0f); AddImpact(LTNULL, m_vFlashPos, vTo, vUp, ST_SKY); // Okay, we're all done now...bye, bye... RemoveObject(); }