//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFFreezePanel::UpdateCallout( void ) { CTFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer(); if ( !pPlayer ) return; // Abort early if we have no gibs or ragdoll CUtlVector<EHANDLE> *pGibList = pPlayer->GetSpawnedGibs(); IRagdoll *pRagdoll = pPlayer->GetRepresentativeRagdoll(); if ( (!pGibList || pGibList->Count() == 0) && !pRagdoll ) return; if ( m_pFreezePanelBG == NULL ) return; // Precalc the vectors of the freezepanel & statpanel int iX, iY; m_pFreezePanelBG->GetPos( iX, iY ); Vector vecFreezeTL( iX, iY, 0 ); Vector vecFreezeBR( iX + m_pFreezePanelBG->GetWide(), iY + m_pFreezePanelBG->GetTall(), 1 ); CUtlVector<Vector> vecCalloutsTL; CUtlVector<Vector> vecCalloutsBR; Vector vecStatTL(0,0,0); Vector vecStatBR(0,0,1); CTFStatPanel *pStatPanel = GET_HUDELEMENT( CTFStatPanel ); if ( pStatPanel && pStatPanel->IsVisible() ) { pStatPanel->GetPos( iX, iY ); vecStatTL.x = iX; vecStatTL.y = iY; vecStatBR.x = vecStatTL.x + pStatPanel->GetWide(); vecStatBR.y = vecStatTL.y + pStatPanel->GetTall(); } Vector vMins, vMaxs; // Check gibs if ( pGibList && pGibList->Count() ) { int iCount = 0; for ( int i = 0; i < pGibList->Count(); i++ ) { CBaseEntity *pGib = pGibList->Element(i); if ( pGib ) { Vector origin = pGib->GetRenderOrigin(); IPhysicsObject *pPhysicsObject = pGib->VPhysicsGetObject(); if( pPhysicsObject ) { Vector vecMassCenter = pPhysicsObject->GetMassCenterLocalSpace(); pGib->CollisionProp()->CollisionToWorldSpace( vecMassCenter, &origin ); } pGib->GetRenderBounds( vMins, vMaxs ); // Try and add the callout CTFFreezePanelCallout *pCallout = TestAndAddCallout( origin, vMins, vMaxs, &vecCalloutsTL, &vecCalloutsBR, vecFreezeTL, vecFreezeBR, vecStatTL, vecStatBR, &iX, &iY ); if ( pCallout ) { pCallout->UpdateForGib( i, iCount ); iCount++; } } } } else if ( pRagdoll ) { Vector origin = pRagdoll->GetRagdollOrigin(); pRagdoll->GetRagdollBounds( vMins, vMaxs ); // Try and add the callout CTFFreezePanelCallout *pCallout = TestAndAddCallout( origin, vMins, vMaxs, &vecCalloutsTL, &vecCalloutsBR, vecFreezeTL, vecFreezeBR, vecStatTL, vecStatBR, &iX, &iY ); if ( pCallout ) { pCallout->UpdateForRagdoll(); } // even if the callout failed, check that our ragdoll is onscreen and our killer is taunting us (for an achievement) if ( GetVectorInScreenSpace( origin, iX, iY ) ) { C_TFPlayer *pKiller = ToTFPlayer( UTIL_PlayerByIndex( GetSpectatorTarget() ) ); if ( pKiller && pKiller->m_Shared.InCond( TF_COND_TAUNTING ) ) { // tell the server our ragdoll just got taunted during our freezecam char cmd[256]; int iPlayerID = pPlayer->GetUserID(); unsigned short mask = UTIL_GetAchievementEventMask(); Q_snprintf( cmd, sizeof( cmd ), "freezecam_taunt %d %d", GetSpectatorTarget() ^ mask, ( iPlayerID ^ GetSpectatorTarget() ) ^ mask ); engine->ClientCmd_Unrestricted( cmd ); } } } }
void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox( CParticleCollection *pParticles, int nControlPointNumber, int nNumPtsOut, float flBBoxScale, int nNumTrysToGetAPointInsideTheModel, Vector *pPntsOut, Vector vecDirectionalBias, Vector *pHitBoxRelativeCoordOut, int *pHitBoxIndexOut ) { bool bSucesss = false; #ifndef GAME_DLL EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->m_ControlPoints[nControlPointNumber].m_pObject ); CBaseEntity *pMoveParent = NULL; if ( phMoveParent ) { pMoveParent = *( phMoveParent ); } if ( pMoveParent ) { float flRandMax = flBBoxScale; float flRandMin = 1.0 - flBBoxScale; Vector vecBasePos; pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos ); s_BoneMutex.Lock(); C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating(); if ( pAnimating ) { matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) ) { studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if ( pStudioHdr ) { mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); if ( set ) { bSucesss = true; Vector vecWorldPosition; float u = 0, v = 0, w = 0; int nHitbox = 0; int nNumIters = nNumTrysToGetAPointInsideTheModel; if (! vecDirectionalBias.IsZero( 0.0001 ) ) nNumIters = max( nNumIters, 5 ); for( int i=0 ; i < nNumPtsOut; i++) { int nTryCnt = nNumIters; float flBestPointGoodness = -1.0e20; do { int nTryHitbox = pParticles->RandomInt( 0, set->numhitboxes - 1 ); mstudiobbox_t *pBox = set->pHitbox(nTryHitbox); float flTryU = pParticles->RandomFloat( flRandMin, flRandMax ); float flTryV = pParticles->RandomFloat( flRandMin, flRandMax ); float flTryW = pParticles->RandomFloat( flRandMin, flRandMax ); Vector vecLocalPosition; vecLocalPosition.x = GetSurfaceCoord( flTryU, pBox->bbmin.x, pBox->bbmax.x ); vecLocalPosition.y = GetSurfaceCoord( flTryV, pBox->bbmin.y, pBox->bbmax.y ); vecLocalPosition.z = GetSurfaceCoord( flTryW, pBox->bbmin.z, pBox->bbmax.z ); Vector vecTryWorldPosition; VectorTransform( vecLocalPosition, *hitboxbones[pBox->bone], vecTryWorldPosition ); float flPointGoodness = pParticles->RandomFloat( 0, 72 ) + DotProduct( vecTryWorldPosition - vecBasePos, vecDirectionalBias ); if ( nNumTrysToGetAPointInsideTheModel ) { // do a point in solid test Ray_t ray; trace_t tr; ray.Init( vecTryWorldPosition, vecTryWorldPosition ); enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); if ( tr.startsolid ) flPointGoodness += 1000.; // got a point inside! } if ( flPointGoodness > flBestPointGoodness ) { u = flTryU; v = flTryV; w = flTryW; vecWorldPosition = vecTryWorldPosition; nHitbox = nTryHitbox; flBestPointGoodness = flPointGoodness; } } while ( nTryCnt-- ); *( pPntsOut++ ) = vecWorldPosition; if ( pHitBoxRelativeCoordOut ) ( pHitBoxRelativeCoordOut++ )->Init( u, v, w ); if ( pHitBoxIndexOut ) *( pHitBoxIndexOut++ ) = nHitbox; } } } } } if ( pMoveParent->IsBrushModel() ) { Vector vecMin; Vector vecMax; matrix3x4_t matOrientation; Vector VecOrigin; pMoveParent->GetRenderBounds( vecMin, vecMax ); VecOrigin = pMoveParent->GetRenderOrigin(); matOrientation = pMoveParent->EntityToWorldTransform(); Vector vecWorldPosition; float u = 0, v = 0, w = 0; int nHitbox = 0; int nNumIters = nNumTrysToGetAPointInsideTheModel; if (! vecDirectionalBias.IsZero( 0.0001 ) ) nNumIters = max( nNumIters, 5 ); for( int i=0 ; i < nNumPtsOut; i++) { int nTryCnt = nNumIters; float flBestPointGoodness = -1.0e20; do { float flTryU = pParticles->RandomFloat( flRandMin, flRandMax ); float flTryV = pParticles->RandomFloat( flRandMin, flRandMax ); float flTryW = pParticles->RandomFloat( flRandMin, flRandMax ); Vector vecLocalPosition; vecLocalPosition.x = GetSurfaceCoord( flTryU, vecMin.x, vecMax.x ); vecLocalPosition.y = GetSurfaceCoord( flTryV, vecMin.y, vecMax.y ); vecLocalPosition.z = GetSurfaceCoord( flTryW, vecMin.z, vecMax.z ); Vector vecTryWorldPosition; VectorTransform( vecLocalPosition, matOrientation, vecTryWorldPosition ); float flPointGoodness = pParticles->RandomFloat( 0, 72 ) + DotProduct( vecTryWorldPosition - vecBasePos, vecDirectionalBias ); if ( nNumTrysToGetAPointInsideTheModel ) { // do a point in solid test Ray_t ray; trace_t tr; ray.Init( vecTryWorldPosition, vecTryWorldPosition ); enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr ); if ( tr.startsolid ) flPointGoodness += 1000.; // got a point inside! } if ( flPointGoodness > flBestPointGoodness ) { u = flTryU; v = flTryV; w = flTryW; vecWorldPosition = vecTryWorldPosition; nHitbox = 0; flBestPointGoodness = flPointGoodness; } } while ( nTryCnt-- ); *( pPntsOut++ ) = vecWorldPosition; if ( pHitBoxRelativeCoordOut ) ( pHitBoxRelativeCoordOut++ )->Init( u, v, w ); if ( pHitBoxIndexOut ) *( pHitBoxIndexOut++ ) = nHitbox; } } s_BoneMutex.Unlock(); } #endif if (! bSucesss ) { // don't have a model or am in editor or something - fill return with control point for( int i=0 ; i < nNumPtsOut; i++) { pPntsOut[i] = pParticles->m_ControlPoints[nControlPointNumber].m_Position; // fallback if anything goes wrong if ( pHitBoxIndexOut ) pHitBoxIndexOut[i] = 0; if ( pHitBoxRelativeCoordOut ) pHitBoxRelativeCoordOut[i].Init(); } } }
int CParticleSystemQuery::GetControllingObjectHitBoxInfo( CParticleCollection *pParticles, int nControlPointNumber, int nBufSize, // # of output slots available ModelHitBoxInfo_t *pHitBoxOutputBuffer ) { int nRet = 0; #ifndef GAME_DLL s_BoneMutex.Lock(); EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->m_ControlPoints[nControlPointNumber].m_pObject ); CBaseEntity *pMoveParent = NULL; if ( phMoveParent ) { pMoveParent = *( phMoveParent ); } if ( pMoveParent ) { C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating(); if ( pAnimating ) { matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) ) { studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if ( pStudioHdr ) { mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() ); if ( set ) { nRet = min( nBufSize, set->numhitboxes ); for( int i=0 ; i < nRet; i++ ) { mstudiobbox_t *pBox = set->pHitbox( i ); pHitBoxOutputBuffer[i].m_vecBoxMins.x = pBox->bbmin.x; pHitBoxOutputBuffer[i].m_vecBoxMins.y = pBox->bbmin.y; pHitBoxOutputBuffer[i].m_vecBoxMins.z = pBox->bbmin.z; pHitBoxOutputBuffer[i].m_vecBoxMaxes.x = pBox->bbmax.x; pHitBoxOutputBuffer[i].m_vecBoxMaxes.y = pBox->bbmax.y; pHitBoxOutputBuffer[i].m_vecBoxMaxes.z = pBox->bbmax.z; pHitBoxOutputBuffer[i].m_Transform = *hitboxbones[pBox->bone]; } } } } } if ( pMoveParent->IsBrushModel() ) { Vector vecMin; Vector vecMax; matrix3x4_t matOrientation; pMoveParent->GetRenderBounds( vecMin, vecMax ); matOrientation = pMoveParent->EntityToWorldTransform(); pHitBoxOutputBuffer[0].m_vecBoxMins = vecMin; pHitBoxOutputBuffer[0].m_vecBoxMaxes = vecMax; pHitBoxOutputBuffer[0].m_Transform = matOrientation; nRet = 1; } } s_BoneMutex.Unlock(); #endif return nRet; }
int CParticleSystemQuery::GetControllingObjectHitBoxInfo( CParticleCollection *pParticles, int nControlPointNumber, int nBufSize, // # of output slots available ModelHitBoxInfo_t *pHitBoxOutputBuffer ) { int nRet = 0; #ifndef GAME_DLL s_BoneMutex.Lock(); EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->ControlPoint( nControlPointNumber ).m_pObject ); CBaseEntity *pMoveParent = NULL; if ( phMoveParent ) { pMoveParent = *( phMoveParent ); } if ( pMoveParent ) { C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating(); if ( pAnimating ) { matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) ) { studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() ); if ( pStudioHdr ) { // Try to get the "effects" set first, otherwise use their current set int nEffectsHitboxSet = FindHitboxSetByName( pAnimating->GetModelPtr(), "effects" ); mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( nEffectsHitboxSet != -1 ? nEffectsHitboxSet : pAnimating->GetHitboxSet() ); if ( set ) { for( int i=0 ; i < set->numhitboxes; i++ ) { mstudiobbox_t *pBox = set->pHitbox( i ); // E3 HACK - check for hitboxes at the origin and ignore those if ( fabs( (*hitboxbones[pBox->bone])[0][3] ) < POINT_AT_ORIGIN_EPSILON && fabs( (*hitboxbones[pBox->bone])[1][3] ) < POINT_AT_ORIGIN_EPSILON && fabs( (*hitboxbones[pBox->bone])[2][3] ) < POINT_AT_ORIGIN_EPSILON ) { continue; } pHitBoxOutputBuffer[nRet].m_vecBoxMins.x = pBox->bbmin.x; pHitBoxOutputBuffer[nRet].m_vecBoxMins.y = pBox->bbmin.y; pHitBoxOutputBuffer[nRet].m_vecBoxMins.z = pBox->bbmin.z; pHitBoxOutputBuffer[nRet].m_vecBoxMaxes.x = pBox->bbmax.x; pHitBoxOutputBuffer[nRet].m_vecBoxMaxes.y = pBox->bbmax.y; pHitBoxOutputBuffer[nRet].m_vecBoxMaxes.z = pBox->bbmax.z; pHitBoxOutputBuffer[nRet].m_Transform = *hitboxbones[pBox->bone]; nRet++; if ( nRet >= nBufSize ) { break; } } } } } } if ( pMoveParent->IsBrushModel() ) { Vector vecMin; Vector vecMax; matrix3x4_t matOrientation; pMoveParent->GetRenderBounds( vecMin, vecMax ); matOrientation = pMoveParent->EntityToWorldTransform(); pHitBoxOutputBuffer[0].m_vecBoxMins = vecMin; pHitBoxOutputBuffer[0].m_vecBoxMaxes = vecMax; pHitBoxOutputBuffer[0].m_Transform = matOrientation; nRet = 1; } } s_BoneMutex.Unlock(); #endif return nRet; }