void CProjectileFX::Detonate(CollisionInfo* pInfo) { if (!m_pClientDE || m_bDetonated) return; m_bDetonated = LTTRUE; SurfaceType eType = ST_UNKNOWN; LTVector vPos; g_pLTClient->GetObjectPos(m_hServerObject, &vPos); // Determine the normal of the surface we are impacting on... LTVector vNormal; VEC_SET(vNormal, 0.0f, 1.0f, 0.0f); if (pInfo) { if (pInfo->m_hObject) { eType = GetSurfaceType(pInfo->m_hObject); } else if (pInfo->m_hPoly != INVALID_HPOLY) { eType = GetSurfaceType(pInfo->m_hPoly); VEC_COPY(vNormal, pInfo->m_Plane.m_Normal); LTRotation rRot(vNormal, LTVector(0.0f, 1.0f, 0.0f)); m_pClientDE->SetObjectRotation(m_hServerObject, &rRot); // Calculate where we really hit the plane... LTVector vVel, vP0, vP1; g_pPhysicsLT->GetVelocity(m_hServerObject, &vVel); VEC_COPY(vP1, vPos); VEC_MULSCALAR(vVel, vVel, g_pGameClientShell->GetFrameTime()); VEC_SUB(vP0, vP1, vVel); LTFLOAT fDot1 = VEC_DOT(pInfo->m_Plane.m_Normal, vP0) - pInfo->m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT(pInfo->m_Plane.m_Normal, vP1) - pInfo->m_Plane.m_Dist; if (fDot1 < 0.0f && fDot2 < 0.0f || fDot1 > 0.0f && fDot2 > 0.0f) { VEC_COPY(vPos, vP1); } else { LTFLOAT fPercent = -fDot1 / (fDot2 - fDot1); VEC_LERP(vPos, vP0, vP1, fPercent); } } } else { // Since pInfo was null, this means the projectile's lifetime was up, // so we just blow-up in the air. eType = ST_AIR; } HOBJECT hObj = !!pInfo ? pInfo->m_hObject : LTNULL; ::AddLocalImpactFX(hObj, m_vFirePos, vPos, vNormal, eType, m_vPath, m_nWeaponId, m_nAmmoId, 0); m_bWantRemove = LTTRUE; }
void Prop::HandleAttachmentTouch( HOBJECT hToucher ) { if( !hToucher || !m_bAttachmentShotOff ) return; // Don't touch the owner... if( hToucher == m_hAttachmentOwner ) return; // Or any non-solid objects... uint32 dwToucherFlags; g_pCommonLT->GetObjectFlags( hToucher, OFT_Flags, dwToucherFlags ); if( !(dwToucherFlags & FLAG_SOLID) ) return; CollisionInfo info; g_pLTServer->GetLastCollision( &info ); LTVector vVel; g_pPhysicsLT->GetVelocity( m_hObject, &vVel ); // Calculate where we really hit the world... if( IsMainWorld( hToucher )) { LTVector vPos, vCurVel, vP0, vP1; g_pLTServer->GetObjectPos( m_hObject, &vPos ); vP1 = vPos; vCurVel = vVel * g_pLTServer->GetFrameTime(); vP0 = vP1 - vCurVel; vP1 += vCurVel; LTFLOAT fDot1 = VEC_DOT( info.m_Plane.m_Normal, vP0 ) - info.m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT( info.m_Plane.m_Normal, 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); VEC_LERP( vPos, vP0, vP1, fPercent); } // Set our new "real" pos... g_pLTServer->SetObjectPos( m_hObject, &vPos ); } // If we're on the ground (or an object), stop movement... CollisionInfo standingInfo; g_pLTServer->GetStandingOn( m_hObject, &standingInfo ); CollisionInfo* pInfo = standingInfo.m_hObject ? &standingInfo : &info; if( pInfo->m_hObject ) { // Don't stop on walls... if( pInfo->m_Plane.m_Normal.y > 0.75f ) { vVel.Init(); // Turn off gravity, solid, and touch notify.... uint32 dwFlags = FLAG_POINTCOLLIDE | FLAG_NOSLIDING | FLAG_TOUCH_NOTIFY | FLAG_GRAVITY; g_pCommonLT->SetObjectFlags( m_hObject, OFT_Flags, 0, dwFlags ); // Rotate to rest... if( m_bRotating ) { LTRotation rRot( 0.0f, m_fYaw, 0.0f ); g_pLTServer->SetObjectRotation( m_hObject, &rRot ); m_bRotating = false; StartFade( s_vtAttachmentFadeDuration.GetFloat(), s_vtAttachmentFadeDelay.GetFloat() ); } } } // Remove the stoping velocity... vVel = -info.m_vStopVel; g_pPhysicsLT->SetVelocity( m_hObject, &vVel ); }
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(); }
void CSpear::HandleImpact(HOBJECT hObj) { if (!g_vtSpearStickPercentage.IsInitted()) { g_vtSpearStickPercentage.Init(g_pLTServer, "SpearStickPercent", LTNULL, 0.9f); } if (!m_pAmmoData || !m_pAmmoData->pProjectileFX) { CProjectile::HandleImpact(hObj); return; } CollisionInfo info; g_pLTServer->GetLastCollision(&info); LTVector vPos, vVel, vCurVel, vP0, vP1; g_pLTServer->GetObjectPos(m_hObject, &vPos); LTRotation rRot; g_pLTServer->GetObjectRotation(m_hObject, &rRot); // Should we break the spear? enum SpearAction { eSpearActionBreak, eSpearActionStickWorld, eSpearActionStickAI, eSpearActionStickPlayer, eSpearActionStickBody }; SpearAction eSpearAction = eSpearActionBreak; // Randomly break even if we could sometimes stick... if (GetRandom(0.0, 1.0f) > g_vtSpearStickPercentage.GetFloat()) { eSpearAction = eSpearActionBreak; } else if (IsMainWorld(hObj)) { // Calculate where we really hit the world... g_pLTServer->GetVelocity(m_hObject, &vVel); vP1 = vPos; vCurVel = vVel * g_pLTServer->GetFrameTime(); vP0 = vP1 - vCurVel; vP1 += vCurVel; LTFLOAT fDot1 = VEC_DOT(info.m_Plane.m_Normal, vP0) - info.m_Plane.m_Dist; LTFLOAT fDot2 = VEC_DOT(info.m_Plane.m_Normal, 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); VEC_LERP(vPos, vP0, vP1, fPercent); } // Set our new "real" pos... g_pLTServer->SetObjectPos(m_hObject, &vPos); eSpearAction = eSpearActionStickWorld; } else if (IsMoveable(hObj)) { if (IsAI(hObj)) { // Attach to a AI eSpearAction = eSpearActionStickAI; } else if (IsPlayer(hObj)) { // Attach to a Player eSpearAction = eSpearActionStickPlayer; } else if (IsBody(hObj)) { // Attach to a body eSpearAction = eSpearActionStickBody; } else { // Could probably come up with a way to attach to moveable // non-character objects (like doors), but it is much easier // to just break it ;)... eSpearAction = eSpearActionBreak; } } // If the surface is too hard, the spear will just break when // it hits it... SurfaceType eSurf = GetSurfaceType(info); SURFACE* pSurf = g_pSurfaceMgr->GetSurface(eSurf); if ((eSpearActionBreak == eSpearAction) || ((eSpearActionStickWorld == eSpearAction) && pSurf && pSurf->fHardness > 0.5)) { // Create spear debris... DEBRIS* pDebris = g_pDebrisMgr->GetDebris(m_pAmmoData->szName); if (pDebris) { vVel.Norm(); LTVector vNegVel = -vVel; CreatePropDebris(vPos, vNegVel, pDebris->nId); } CProjectile::HandleImpact(hObj); return; } // Create the Spear powerup... char szSpawn[512]; sprintf(szSpawn, "AmmoBox AmmoType1 %s;AmmoCount1 1;Filename %s;Skin %s", m_pAmmoData->szName, m_pAmmoData->pProjectileFX->szModel, m_pAmmoData->pProjectileFX->szSkin); LTVector vScale = m_pAmmoData->pProjectileFX->vModelScale; // Make sure the spear sticks out a little ways... vVel.Norm(); vPos -= (vVel * vScale.z/2.0f); if (eSpearActionStickWorld == eSpearAction) { g_pLTServer->AlignRotation(&rRot, &vVel, LTNULL); } BaseClass* pClass = SpawnObject(szSpawn, LTVector(-10000,-10000,-10000), rRot); if (pClass) { g_pLTServer->ScaleObject(pClass->m_hObject, &vScale); LTVector vDims; g_pLTServer->GetObjectDims(pClass->m_hObject, &vDims); vDims.x *= vScale.x; vDims.y *= vScale.y; vDims.z *= vScale.z; g_pLTServer->SetObjectDims(pClass->m_hObject, &vDims); // We don't want other projectiles to impact on us... //uint32 dwUsrFlags = g_pLTServer->GetObjectUserFlags(pClass->m_hObject); //dwUsrFlags |= USRFLG_IGNORE_PROJECTILES; //g_pLTServer->SetObjectUserFlags(pClass->m_hObject, dwUsrFlags); if ( eSpearActionStickAI == eSpearAction || eSpearActionStickPlayer == eSpearAction ) { g_pLTServer->SetObjectUserFlags(pClass->m_hObject, g_pLTServer->GetObjectUserFlags(pClass->m_hObject) & ~USRFLG_GLOW); g_pLTServer->SetObjectFlags(pClass->m_hObject, g_pLTServer->GetObjectFlags(pClass->m_hObject) & ~FLAG_TOUCH_NOTIFY); if ( eSpearActionStickPlayer == eSpearAction ) { g_pLTServer->SetObjectUserFlags(pClass->m_hObject, g_pLTServer->GetObjectUserFlags(pClass->m_hObject) | USRFLG_ATTACH_HIDE1SHOW3); } // Attach it to the character CCharacter* pCharacter = (CCharacter*)g_pLTServer->HandleToObject(hObj); pCharacter->AddSpear(pClass->m_hObject, pCharacter->GetModelNodeLastHit(), rRot); } else if ( eSpearActionStickBody == eSpearAction ) { g_pLTServer->SetObjectUserFlags(pClass->m_hObject, g_pLTServer->GetObjectUserFlags(pClass->m_hObject) & ~USRFLG_GLOW); g_pLTServer->SetObjectFlags(pClass->m_hObject, g_pLTServer->GetObjectFlags(pClass->m_hObject) & ~FLAG_TOUCH_NOTIFY); // Attach it to the body Body* pBody = (Body*)g_pLTServer->HandleToObject(hObj); pBody->AddSpear(pClass->m_hObject, rRot); } else // ( eSpearActionStickWorld == eSpearAction ) { // Move it to the right position in the world g_pLTServer->SetObjectPos(pClass->m_hObject, &vPos); } } CProjectile::HandleImpact(hObj); }