bool CFuncBulletShield::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace ) { // ignore unless a shot if ((mask & MASK_SHOT) == MASK_SHOT) { // use obb collision ICollideable *pCol = GetCollideable(); Assert(pCol); return IntersectRayWithOBB(ray,pCol->GetCollisionOrigin(),pCol->GetCollisionAngles(), pCol->OBBMins(),pCol->OBBMaxs(),1.0f,&trace); /* const model_t *pModel = this->GetCollisionModel(); if ( pModel && pModel->type == mod_brush ) { int nModelIndex = this->GetCollisionModelIndex(); cmodel_t *pCModel = CM_InlineModelNumber( nModelIndex - 1 ); int nHeadNode = pCModel->headnode; CM_TransformedBoxTrace( ray, nHeadNode, fMask, this->GetCollisionOrigin(), this->GetCollisionAngles(), *pTrace ); return true; } return false; */ // return BaseClass::TestCollision( ray, mask, trace ); } else return false; }
FORCEINLINE void Check( T *pEntity ) { // Hmmm.. everything in this list should be a trigger.... ICollideable *pTriggerCollideable = pEntity->GetCollideable(); if ( !m_pCollide->ShouldTouchTrigger(pTriggerCollideable->GetSolidFlags()) ) return; if ( pTriggerCollideable->GetSolidFlags() & FSOLID_USE_TRIGGER_BOUNDS ) { Vector vecTriggerMins, vecTriggerMaxs; pTriggerCollideable->WorldSpaceTriggerBounds( &vecTriggerMins, &vecTriggerMaxs ); if ( !IsBoxIntersectingRay( vecTriggerMins, vecTriggerMaxs, m_Ray ) ) { return; } } else { trace_t tr; enginetrace->ClipRayToCollideable( m_Ray, MASK_SOLID, pTriggerCollideable, &tr ); if ( !(tr.contents & MASK_SOLID) ) return; } trace_t tr; UTIL_ClearTrace( tr ); tr.endpos = (m_pEnt->GetAbsOrigin() + pEntity->GetAbsOrigin()) * 0.5; m_pEnt->PhysicsMarkEntitiesAsTouching( pEntity, tr ); }
virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ) { IClientUnknown *pUnk = (IClientUnknown*)pHandleEntity; ICollideable *pCollide = pUnk->GetCollideable(); if ( pCollide->GetSolid() != SOLID_VPHYSICS && pCollide->GetSolid() != SOLID_BSP ) return false; return BaseClass::ShouldHitEntity( pHandleEntity, contentsMask ); }
void UTIL_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, unsigned int mask, ITraceFilter *pFilter, trace_t *ptr ) { ICollideable *pCollision = VFuncs::GetCollideable(pEntity); // Adding this assertion here so game code catches it, but really the assertion belongs in the engine // because one day, rotated collideables will work! Assert( pCollision->GetCollisionAngles() == vec3_angle ); enginetrace->SweepCollideable( pCollision, vecAbsStart, vecAbsEnd, pCollision->GetCollisionAngles(), mask, pFilter, ptr ); }
IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ) { // Static props should never be in the trigger list Assert( !StaticPropMgr()->IsStaticProp( pHandleEntity ) ); IServerNetworkable *pNetworkable = static_cast<IServerNetworkable*>( pHandleEntity ); Assert( pNetworkable ); // Convert the IHandleEntity to an edict_t*... // Context is the thing we're testing everything against edict_t* pTouch = pNetworkable->GetEdict(); // Can't bump against itself if ( pTouch == m_pEnt ) return ITERATION_CONTINUE; IServerEntity *serverEntity = pTouch->GetIServerEntity(); if ( !serverEntity ) return ITERATION_CONTINUE; // Hmmm.. everything in this list should be a trigger.... ICollideable *pCollideable = serverEntity->GetCollideable(); Assert(pCollideable->GetSolidFlags() & FSOLID_TRIGGER ); if ( (pCollideable->GetSolidFlags() & FSOLID_TRIGGER) == 0 ) return ITERATION_CONTINUE; model_t* pModel = sv.GetModel( pCollideable->GetCollisionModelIndex() ); if ( pModel && pModel->type == mod_brush ) { int headnode = SV_HullForEntity( pTouch ); int contents; if (!m_Ray.m_IsSwept) { contents = CM_TransformedBoxContents( m_Ray.m_Start, m_mins, m_maxs, headnode, serverEntity->GetAbsOrigin(), serverEntity->GetAbsAngles() ); } else { trace_t trace; CM_TransformedBoxTrace( m_Ray, headnode, MASK_ALL, serverEntity->GetAbsOrigin(), serverEntity->GetAbsAngles(), trace ); contents = trace.contents; } if ( !(contents & MASK_SOLID) ) return ITERATION_CONTINUE; } m_TouchedEntities.AddToTail( pTouch ); return ITERATION_CONTINUE; }
//----------------------------------------------------------------------------- // Sweeps a particular entity through the world //----------------------------------------------------------------------------- void UTIL_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, unsigned int mask, trace_t *ptr ) { ICollideable *pCollision = pEntity->GetCollideable(); // Adding this assertion here so game code catches it, but really the assertion belongs in the engine // because one day, rotated collideables will work! Assert( pCollision->GetCollisionAngles() == vec3_angle ); CTraceFilterEntity traceFilter( pEntity, pCollision->GetCollisionGroup() ); #ifdef PORTAL UTIL_Portal_TraceEntity( pEntity, vecAbsStart, vecAbsEnd, mask, &traceFilter, ptr ); #else enginetrace->SweepCollideable( pCollision, vecAbsStart, vecAbsEnd, pCollision->GetCollisionAngles(), mask, &traceFilter, ptr ); #endif }
//----------------------------------------------------------------------------- // Purpose: Returns the color given trace information // Input : *trace - trace to get results for // *color - return color, gamma corrected (0.0f to 1.0f) //----------------------------------------------------------------------------- void GetColorForSurface( trace_t *trace, Vector *color ) { Vector baseColor, diffuseColor; Vector end = trace->startpos + ( ( Vector )trace->endpos - ( Vector )trace->startpos ) * 1.1f; if ( trace->DidHitWorld() ) { if ( trace->hitbox == 0 ) { // If we hit the world, then ask the world for the fleck color engine->TraceLineMaterialAndLighting( trace->startpos, end, diffuseColor, baseColor ); } else { // In this case we hit a static prop. staticpropmgr->GetStaticPropMaterialColorAndLighting( trace, trace->hitbox - 1, diffuseColor, baseColor ); } } else { // In this case, we hit an entity. Find out the model associated with it C_BaseEntity *pEnt = trace->m_pEnt; if ( !pEnt ) { Msg("Couldn't find surface in GetColorForSurface()\n"); color->x = 255; color->y = 255; color->z = 255; return; } ICollideable *pCollide = pEnt->GetCollideable(); int modelIndex = pCollide->GetCollisionModelIndex(); model_t* pModel = const_cast<model_t*>(modelinfo->GetModel( modelIndex )); // Ask the model info about what we need to know modelinfo->GetModelMaterialColorAndLighting( pModel, pCollide->GetCollisionOrigin(), pCollide->GetCollisionAngles(), trace, diffuseColor, baseColor ); } //Get final light value color->x = pow( diffuseColor[0], 1.0f/2.2f ) * baseColor[0]; color->y = pow( diffuseColor[1], 1.0f/2.2f ) * baseColor[1]; color->z = pow( diffuseColor[2], 1.0f/2.2f ) * baseColor[2]; }
//----------------------------------------------------------------------------- // Purpose: returns a headnode that can be used to collide against this entity // Input : *ent - // Output : int //----------------------------------------------------------------------------- int SV_HullForEntity( edict_t *ent ) { model_t *model; IServerEntity *serverEntity = ent->GetIServerEntity(); Assert( serverEntity ); if ( !serverEntity ) return -1; int modelindex = serverEntity->GetModelIndex(); model = sv.GetModel( modelindex ); if (model->type == mod_brush) { cmodel_t *pCModel = CM_InlineModelNumber( modelindex - 1 ); return pCModel->headnode; } ICollideable *pCollideable = serverEntity->GetCollideable(); Vector vecMins = pCollideable->WorldAlignMins(); Vector vecMaxs = pCollideable->WorldAlignMaxs(); return CM_HeadnodeForBoxHull( vecMins, vecMaxs ); }
IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ) { ICollideable *pCollide; const char *pDbgName; m_pEngineTrace->HandleEntityToCollideable( pHandleEntity, &pCollide, &pDbgName ); if (!pCollide) return ITERATION_CONTINUE; // Deal with static props // NOTE: I could have added static props to a different list and // enumerated them separately, but that would have been less efficient if ( StaticPropMgr()->IsStaticProp( pHandleEntity ) ) { Ray_t ray; trace_t trace; ray.Init( m_Pos, m_Pos ); m_pEngineTrace->ClipRayToCollideable( ray, MASK_ALL, pCollide, &trace ); if (trace.startsolid) { // We're in a static prop; that's solid baby // Pretend we hit the world m_Contents = CONTENTS_SOLID; m_pCollide = m_pEngineTrace->GetWorldCollideable(); return ITERATION_STOP; } return ITERATION_CONTINUE; } // We only care about solid volumes if ((pCollide->GetSolidFlags() & FSOLID_VOLUME_CONTENTS) == 0) return ITERATION_CONTINUE; model_t* pModel = (model_t*)pCollide->GetCollisionModel(); if ( pModel && pModel->type == mod_brush ) { Assert( pCollide->GetCollisionModelIndex() < MAX_MODELS && pCollide->GetCollisionModelIndex() >= 0 ); int nHeadNode = GetModelHeadNode( pCollide ); int contents = CM_TransformedPointContents( m_Pos, nHeadNode, pCollide->GetCollisionOrigin(), pCollide->GetCollisionAngles() ); if (contents != CONTENTS_EMPTY) { // Return the contents of the first thing we hit m_Contents = contents; m_pCollide = pCollide; return ITERATION_STOP; } } return ITERATION_CONTINUE; }
void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press) { #if defined MENU_DEBUG g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press); #endif CBaseMenuPlayer *player = GetMenuPlayer(client); /* First question: Are we in a menu? */ if (!player->bInMenu) { return; } bool cancel = false; unsigned int item = 0; MenuCancelReason reason = MenuCancel_Exit; MenuEndReason end_reason = MenuEnd_Selected; menu_states_t &states = player->states; /* Save variables */ IMenuHandler *mh = states.mh; IBaseMenu *menu = states.menu; unsigned int item_on_page = states.item_on_page; assert(mh != NULL); if (menu == NULL) { item = key_press; } else if (key_press < 1 || key_press > GetMaxPageItems()) { cancel = true; } else { ItemSelection type = states.slots[key_press].type; /* Check if we should play a sound about the type */ if (g_Menus.MenuSoundsEnabled() && (!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND)) { CellRecipientFilter filter; cell_t clients[1]; clients[0] = client; filter.Initialize(clients, 1); const char *sound = g_Menus.GetMenuSound(type); if (sound != NULL) { edict_t *pEdict = PEntityOfEntIndex(client); if (pEdict) { ICollideable *pCollideable = pEdict->GetCollideable(); if (pCollideable) { const Vector & pos = pCollideable->GetCollisionOrigin(); enginesound->EmitSound(filter, client, CHAN_AUTO, #if SOURCE_ENGINE >= SE_PORTAL2 sound, -1, #endif sound, VOL_NORM, ATTN_NORM, #if SOURCE_ENGINE >= SE_PORTAL2 0, #endif 0, PITCH_NORM, #if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \ || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2 0, #endif &pos); } } } } /* For navigational items, we're going to redisplay */ if (type == ItemSel_Back) { if (!RedoClientMenu(client, ItemOrder_Descending)) { cancel = true; reason = MenuCancel_NoDisplay; end_reason = MenuEnd_Cancelled; } else { return; } } else if (type == ItemSel_Next) { if (!RedoClientMenu(client, ItemOrder_Ascending)) { cancel = true; /* I like Saltines. */ reason = MenuCancel_NoDisplay; end_reason = MenuEnd_Cancelled; } else { return; } } else if (type == ItemSel_Exit || type == ItemSel_None) { cancel = true; reason = MenuCancel_Exit; end_reason = MenuEnd_Exit; } else if (type == ItemSel_ExitBack) { cancel = true; reason = MenuCancel_ExitBack; end_reason = MenuEnd_ExitBack; } else { item = states.slots[key_press].item; } } /* Clear states */ player->bInMenu = false; if (player->menuHoldTime) { RemoveClientFromWatch(client); } Handle_t hndl = menu ? menu->GetHandle() : BAD_HANDLE; AutoHandleRooter ahr(hndl); if (cancel) { mh->OnMenuCancel(menu, client, reason); } else { mh->OnMenuSelect(menu, client, item); if (mh->GetMenuAPIVersion2() >= 13) { mh->OnMenuSelect2(menu, client, item, item_on_page); } } /* Only fire end for valid menus */ if (menu) { mh->OnMenuEnd(menu, end_reason); } }
int SEditModelRender::MaterialPicker( char ***szMat ) { int mx, my; #ifdef SOURCE_2006 vgui::input()->GetCursorPos( mx, my ); #else vgui::input()->GetCursorPosition( mx, my ); #endif Vector ray; const CViewSetup *pViewSetup = view->GetPlayerViewSetup(); float ratio =engine->GetScreenAspectRatio( #ifdef SWARM_DLL pViewSetup->width, pViewSetup->height #endif ); ratio = ( 1.0f / ratio ) * (4.0f/3.0f); float flFov = ScaleFOVByWidthRatio( pViewSetup->fov, ratio ); ScreenToWorld( mx, my, flFov, pViewSetup->origin, pViewSetup->angles, ray ); Vector start = pViewSetup->origin; Vector end = start + ray * MAX_TRACE_LENGTH; trace_t tr; C_BaseEntity *pIgnore = input->CAM_IsThirdPerson() ? NULL : C_BasePlayer::GetLocalPlayer(); UTIL_TraceLine( start, end, MASK_SOLID, pIgnore, COLLISION_GROUP_NONE, &tr ); if ( !tr.DidHit() ) return 0; int numMaterials = 0; IMaterial **MatList = NULL; studiohdr_t *pSHdr = NULL; if ( tr.DidHitWorld() ) { if ( tr.hitbox == 0 ) { Vector dummy; IMaterial *pMat = engine->TraceLineMaterialAndLighting( start, end, dummy, dummy ); if ( pMat ) { numMaterials = 1; MatList = new IMaterial*[1]; MatList[0] = pMat; } } else { ICollideable *prop = staticpropmgr->GetStaticPropByIndex( tr.hitbox - 1 ); if ( prop ) { IClientRenderable *pRenderProp = prop->GetIClientUnknown()->GetClientRenderable(); if ( pRenderProp ) { const model_t *pModel = pRenderProp->GetModel(); if ( pModel ) pSHdr = modelinfo->GetStudiomodel( pModel ); } } } } else if ( tr.m_pEnt ) { const model_t *pModel = tr.m_pEnt->GetModel(); if ( pModel ) pSHdr = modelinfo->GetStudiomodel( pModel ); } if ( pSHdr ) { Assert( !numMaterials && !MatList ); numMaterials = pSHdr->numtextures; const int numPaths = pSHdr->numcdtextures; if ( numMaterials ) { CUtlVector< IMaterial* >hValidMaterials; for ( int i = 0; i < numMaterials; i++ ) { mstudiotexture_t *pStudioTex = pSHdr->pTexture( i ); const char *matName = pStudioTex->pszName(); for ( int p = 0; p < numPaths; p++ ) { char tmpPath[MAX_PATH]; Q_snprintf( tmpPath, MAX_PATH, "%s%s\0", pSHdr->pCdtexture( p ), matName ); Q_FixSlashes( tmpPath ); IMaterial *pTempMat = materials->FindMaterial( tmpPath, TEXTURE_GROUP_MODEL ); if ( !IsErrorMaterial( pTempMat ) ) { hValidMaterials.AddToTail( pTempMat ); break; } } } numMaterials = hValidMaterials.Count(); if ( numMaterials ) { MatList = new IMaterial*[ numMaterials ]; for ( int i = 0; i < numMaterials; i++ ) MatList[i] = hValidMaterials[i]; } hValidMaterials.Purge(); } } *szMat = new char*[ numMaterials ]; int iTotalLength = 0; for ( int i = 0; i < numMaterials; i++ ) iTotalLength += Q_strlen( MatList[i]->GetName() ) + 1; **szMat = new char[ iTotalLength ]; int curpos = 0; for ( int i = 0; i < numMaterials; i++ ) { const char *pszName = MatList[i]->GetName(); int curLength = Q_strlen( pszName ) + 1; (*szMat)[ i ] = **szMat + curpos; Q_strcpy( (*szMat)[ i ], pszName ); curpos += curLength; } if ( MatList ) delete [] MatList; return numMaterials; }
/* =============== SV_LinkEdict =============== */ void SV_LinkEdict( edict_t *ent, qboolean touch_triggers, const Vector* pPrevAbsOrigin ) { IServerEntity *pServerEntity = ent->GetIServerEntity(); if ( !pServerEntity ) return; // Remove it from whatever lists it may be in at the moment // We'll re-add it below if we need to. if (ent->partition != PARTITION_INVALID_HANDLE) { SpatialPartition()->Remove( ent->partition ); } if (ent->free) return; if (ent == sv.edicts) return; // don't add the world pServerEntity->CalcAbsolutePosition(); // set the abs box pServerEntity->SetObjectCollisionBox(); // link to PVS leafs SV_BuildEntityClusterList( ent ); // Update KD tree information ICollideable *pCollide = pServerEntity->GetCollideable(); if (ent->partition == PARTITION_INVALID_HANDLE) { // Here, we haven't added the entity to the partition before // So we have to make a new partition handle. ent->partition = SpatialPartition()->CreateHandle( pCollide->GetEntityHandle() ); } // Here, we indicate the entity has moved. Note that this call does // some fast early-outing to prevent unnecessary work SpatialPartition()->ElementMoved( ent->partition, pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs() ); // Make sure it's in the list of all entities SpatialPartition()->Insert( PARTITION_ENGINE_NON_STATIC_EDICTS, ent->partition ); SolidType_t iSolid = pCollide->GetSolid(); int nSolidFlags = pCollide->GetSolidFlags(); bool bIsSolid = IsSolid( iSolid, nSolidFlags ) || ((nSolidFlags & FSOLID_TRIGGER) != 0); if ( !bIsSolid ) { // If this ent's touch list isn't empty, it's transitioning to not solid if ( pServerEntity->IsCurrentlyTouching() ) { // mark ent so that at the end of frame it will check to see if it's no longer touch ents pServerEntity->SetCheckUntouch( true ); } return; } // Insert it into the appropriate lists. // We have to continually reinsert it because its solid type may have changed SpatialPartitionListMask_t mask = 0; if (( nSolidFlags & FSOLID_NOT_SOLID ) == 0) { mask |= PARTITION_ENGINE_SOLID_EDICTS; } if (( nSolidFlags & FSOLID_TRIGGER ) != 0 ) { mask |= PARTITION_ENGINE_TRIGGER_EDICTS; } Assert( mask != 0 ); SpatialPartition()->Insert( mask, ent->partition ); if ( iSolid == SOLID_BSP ) { model_t *model = sv.GetModel( pServerEntity->GetModelIndex() ); if ( !model && strlen( STRING( pServerEntity->GetModelName() ) ) == 0 ) { Con_DPrintf( "Inserted %s with no model\n", STRING( ent->classname ) ); return; } } // if touch_triggers, touch all entities at this node and descend for more if (touch_triggers) { // mark ent so that at the end of frame it will check to see if it's no longer touch ents pServerEntity->SetCheckUntouch( true ); // If this is a trigger that's moved, then query the solid list instead if ( mask == PARTITION_ENGINE_TRIGGER_EDICTS ) { CTriggerMoved triggerEnum( ent ); SpatialPartition()->EnumerateElementsInBox( PARTITION_ENGINE_SOLID_EDICTS, pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs(), false, &triggerEnum ); triggerEnum.HandleTouchedEntities( ); } else { if (!pPrevAbsOrigin) { CTouchLinks touchEnumerator(ent, NULL); SpatialPartition()->EnumerateElementsInBox( PARTITION_ENGINE_TRIGGER_EDICTS, pServerEntity->GetAbsMins(), pServerEntity->GetAbsMaxs(), false, &touchEnumerator ); touchEnumerator.HandleTouchedEntities( ); } else { CTouchLinks touchEnumerator(ent, pPrevAbsOrigin); // A version that checks against an extruded ray indicating the motion SpatialPartition()->EnumerateElementsAlongRay( PARTITION_ENGINE_TRIGGER_EDICTS, touchEnumerator.m_Ray, false, &touchEnumerator ); touchEnumerator.HandleTouchedEntities( ); } } } }
//----------------------------------------------------------------------------- // A version that simply accepts a ray (can work as a traceline or tracehull) //----------------------------------------------------------------------------- void CEngineTrace::TraceRay( const Ray_t &ray, unsigned int fMask, ITraceFilter *pTraceFilter, trace_t *pTrace ) { CTraceFilterHitAll traceFilter; if ( !pTraceFilter ) { pTraceFilter = &traceFilter; } // Gather statistics. g_EngineStats.IncrementCountedStat( ENGINE_STATS_NUM_TRACE_LINES, 1 ); MEASURE_TIMED_STAT( ENGINE_STATS_TRACE_LINE_TIME ); CM_ClearTrace( pTrace ); // Collide with the world. if ( pTraceFilter->GetTraceType() != TRACE_ENTITIES_ONLY ) { ICollideable *pCollide = GetWorldCollideable(); // Make sure the world entity is unrotated // FIXME: BAH! The !pCollide test here is because of // CStaticProp::PrecacheLighting.. it's occurring too early // need to fix that later Assert(!pCollide || pCollide->GetCollisionOrigin() == vec3_origin ); Assert(!pCollide || pCollide->GetCollisionAngles() == vec3_angle ); CM_BoxTrace( ray, 0, fMask, true, *pTrace ); SetTraceEntity( pCollide, pTrace ); // Blocked by the world. if ( pTrace->fraction == 0 ) return; // Early out if we only trace against the world if ( pTraceFilter->GetTraceType() == TRACE_WORLD_ONLY ) return; } // Save the world collision fraction. float flWorldFraction = pTrace->fraction; // Create a ray that extends only until we hit the world // and adjust the trace accordingly Ray_t entityRay = ray; entityRay.m_Delta *= pTrace->fraction; // We know this is safe because if pTrace->fraction == 0 // we would have exited above pTrace->fractionleftsolid /= pTrace->fraction; pTrace->fraction = 1.0; // Collide with entities along the ray // FIXME: Hitbox code causes this to be re-entrant for the IK stuff. // If we could eliminate that, this could be static and therefore // not have to reallocate memory all the time CEntitiesAlongRay enumerator; enumerator.Reset(); SpatialPartition()->EnumerateElementsAlongRay( SpatialPartitionMask(), entityRay, false, &enumerator ); bool bNoStaticProps = pTraceFilter->GetTraceType() == TRACE_ENTITIES_ONLY; bool bFilterStaticProps = pTraceFilter->GetTraceType() == TRACE_EVERYTHING_FILTER_PROPS; trace_t tr; ICollideable *pCollideable; const char *pDebugName; int nCount = enumerator.m_EntityHandles.Count(); for ( int i = 0; i < nCount; ++i ) { // Generate a collideable IHandleEntity *pHandleEntity = enumerator.m_EntityHandles[i]; HandleEntityToCollideable( pHandleEntity, &pCollideable, &pDebugName ); // Check for error condition if ( !IsSolid( pCollideable->GetSolid(), pCollideable->GetSolidFlags() ) ) { char temp[1024]; Q_snprintf(temp, sizeof( temp ), "%s in solid list (not solid)\n", pDebugName ); Sys_Error (temp); } if ( !StaticPropMgr()->IsStaticProp( pHandleEntity ) ) { if ( !pTraceFilter->ShouldHitEntity( pHandleEntity, fMask ) ) continue; } else { // FIXME: Could remove this check here by // using a different spatial partition mask. Look into it // if we want more speedups here. if ( bNoStaticProps ) continue; if ( bFilterStaticProps ) { if ( !pTraceFilter->ShouldHitEntity( pHandleEntity, fMask ) ) continue; } } ClipRayToCollideable( entityRay, fMask, pCollideable, &tr ); // Make sure the ray is always shorter than it currently is ClipTraceToTrace( tr, pTrace ); // Stop if we're in allsolid if (pTrace->allsolid) break; } // Fix up the fractions so they are appropriate given the original // unclipped-to-world ray pTrace->fraction *= flWorldFraction; pTrace->fractionleftsolid *= flWorldFraction; #ifdef _DEBUG Vector vecOffset, vecEndTest; VectorAdd( ray.m_Start, ray.m_StartOffset, vecOffset ); VectorMA( vecOffset, pTrace->fractionleftsolid, ray.m_Delta, vecEndTest ); Assert( VectorsAreEqual( vecEndTest, pTrace->startpos, 0.1f ) ); VectorMA( vecOffset, pTrace->fraction, ray.m_Delta, vecEndTest ); Assert( VectorsAreEqual( vecEndTest, pTrace->endpos, 0.1f ) ); // Assert( !ray.m_IsRay || pTrace->allsolid || pTrace->fraction >= pTrace->fractionleftsolid ); #endif if ( !ray.m_IsRay ) { // Make sure no fractionleftsolid can be used with box sweeps VectorAdd( ray.m_Start, ray.m_StartOffset, pTrace->startpos ); pTrace->fractionleftsolid = 0; #ifdef _DEBUG pTrace->fractionleftsolid = VEC_T_NAN; #endif } }