text: #include "stub/trace.h"
  #include "stub/gamerules.h"
  
  
  CFlaggedEntitiesEnum::CFlaggedEntitiesEnum( CBaseEntity **pList, int listMax, int flagMask )
  {
  	m_pList = pList;
  	m_listMax = listMax;
  	m_flagMask = flagMask;
  	m_count = 0;
  }
  
  bool CFlaggedEntitiesEnum::AddToList( CBaseEntity *pEntity )
  {
  	if ( m_count >= m_listMax )
  	{
  		//AssertMsgOnce( 0, "reached enumerated list limit.  Increase limit, decrease radius, or make it so entity flags will work for you" );
  		return false;
  	}
  	m_pList[m_count] = pEntity;
  	m_count++;
  	return true;
  }
  
  IterationRetval_t CFlaggedEntitiesEnum::EnumElement( IHandleEntity *pHandleEntity )
  {
  //	CBaseEntity *pEntity = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() );
  	CBaseEntity *pEntity = static_cast<IServerUnknown *>(pHandleEntity)->GetBaseEntity();
  	if ( pEntity )
  	{
  		if ( m_flagMask && !(pEntity->GetFlags() & m_flagMask) )	// Does it meet the criteria?
  			return ITERATION_CONTINUE;
  
  		if ( !AddToList( pEntity ) )
  			return ITERATION_STOP;
  	}
  
  	return ITERATION_CONTINUE;
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Add an overlay line with padding on the start and end
  //-----------------------------------------------------------------------------
  void DebugDrawLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, int r, int g, int b, bool test, float duration )
  {
  	NDebugOverlay::Line( vecAbsStart + Vector( 0,0,0.1), vecAbsEnd + Vector( 0,0,0.1), r,g,b, test, duration );
  }
  
  
  int UTIL_EntitiesAlongRay( const Ray_t &ray, CFlaggedEntitiesEnum *pEnum )
  {
  	partition->EnumerateElementsAlongRay( PARTITION_ENGINE_NON_STATIC_EDICTS, ray, false, pEnum );
  	return pEnum->GetCount();
  }
  
  int UTIL_EntitiesAlongRay( CBaseEntity **pList, int listMax, const Ray_t &ray, int flagMask )
  {
  	CFlaggedEntitiesEnum rayEnum( pList, listMax, flagMask );
  	return UTIL_EntitiesAlongRay( ray, &rayEnum );
  }
  
  
  //-----------------------------------------------------------------------------
  // Sweeps against a particular model, using collision rules 
  //-----------------------------------------------------------------------------
  void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, const Vector &hullMin, 
  					  const Vector &hullMax, CBaseEntity *pentModel, int collisionGroup, trace_t *ptr )
  {
  	// Cull it....
  	if ( pentModel && pentModel->ShouldCollide( collisionGroup, MASK_ALL ) )
  	{
  		Ray_t ray;
  		ray.Init( vecStart, vecEnd, hullMin, hullMax );
  		enginetrace->ClipRayToEntity( ray, MASK_ALL, pentModel, ptr ); 
  	}
  	else
  	{
  		memset( (void *)ptr, 0, sizeof(trace_t) );
  		ptr->fraction = 1.0f;
  	}
  }
  
  
  //-----------------------------------------------------------------------------
  //
  // Shared client/server trace filter code
  //
  //-----------------------------------------------------------------------------
  bool PassServerEntityFilter( const IHandleEntity *pTouch, const IHandleEntity *pPass ) 
  {
  	if ( !pPass )
  		return true;
  
  	if ( pTouch == pPass )
  		return false;
  
  	const CBaseEntity *pEntTouch = EntityFromEntityHandle( pTouch );
  	const CBaseEntity *pEntPass = EntityFromEntityHandle( pPass );
  	if ( !pEntTouch || !pEntPass )
  		return true;
  
  	// don't clip against own missiles
  	if ( pEntTouch->GetOwnerEntity() == pEntPass )
  		return false;
  	
  	// don't clip against owner
  	if ( pEntPass->GetOwnerEntity() == pEntTouch )
  		return false;	
  
  
  	return true;
  }
  
  
  //-----------------------------------------------------------------------------
  // A standard filter to be applied to just about everything.
  //-----------------------------------------------------------------------------
  bool StandardFilterRules( IHandleEntity *pHandleEntity, int fContentsMask )
  {
  	CBaseEntity *pCollide = EntityFromEntityHandle( pHandleEntity );
  
  	// Static prop case...
  	if ( !pCollide )
  		return true;
  
  	SolidType_t solid = pCollide->GetSolid();
  	const model_t *pModel = pCollide->GetModel();
  
  	if ( ( modelinfo->GetModelType( pModel ) != mod_brush ) || (solid != SOLID_BSP && solid != SOLID_VPHYSICS) )
  	{
  		if ( (fContentsMask & CONTENTS_MONSTER) == 0 )
  			return false;
  	}
  
  	// This code is used to cull out tests against see-thru entities
  	if ( !(fContentsMask & CONTENTS_WINDOW) && pCollide->IsTransparent() )
  		return false;
  
  	// FIXME: this is to skip BSP models that are entities that can be 
  	// potentially moved/deleted, similar to a monster but doors don't seem to 
  	// be flagged as monsters
  	// FIXME: the FL_WORLDBRUSH looked promising, but it needs to be set on 
  	// everything that's actually a worldbrush and it currently isn't
  	if ( !(fContentsMask & CONTENTS_MOVEABLE) && (pCollide->GetMoveType() == MOVETYPE_PUSH))// !(touch->flags & FL_WORLDBRUSH) )
  		return false;
  
  	return true;
  }
  
  
  #if 0
  //-----------------------------------------------------------------------------
  // Simple trace filter
  //-----------------------------------------------------------------------------
  CTraceFilterSimple::CTraceFilterSimple( const IHandleEntity *passedict, int collisionGroup,
  									   ShouldHitFunc_t pExtraShouldHitFunc )
  {
  	m_pPassEnt = passedict;
  	m_collisionGroup = collisionGroup;
  	m_pExtraShouldHitCheckFunction = pExtraShouldHitFunc;
  }
  #endif
  
  //-----------------------------------------------------------------------------
  // The trace filter!
  //-----------------------------------------------------------------------------
  bool CTraceFilterSimple::ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  {
  	if ( !StandardFilterRules( pHandleEntity, contentsMask ) )
  		return false;
  
  	if ( m_pPassEnt )
  	{
  		if ( !PassServerEntityFilter( pHandleEntity, m_pPassEnt ) )
  		{
  			return false;
  		}
  	}
  
  	// Don't test if the game code tells us we should ignore this collision...
  	CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
  	if ( !pEntity )
  		return false;
  	if ( !pEntity->ShouldCollide( m_collisionGroup, contentsMask ) )
  		return false;
  	if ( pEntity && !g_pGameRules->ShouldCollide( m_collisionGroup, pEntity->GetCollisionGroup() ) )
  		return false;
  	if ( m_pExtraShouldHitCheckFunction &&
  		(! ( m_pExtraShouldHitCheckFunction( pHandleEntity, contentsMask ) ) ) )
  		return false;
  
  	return true;
  }
  
  CTraceFilterSkipTwoEntities::CTraceFilterSkipTwoEntities( const IHandleEntity *passentity, const IHandleEntity *passentity2, int collisionGroup ) :
  	CTraceFilterSimple( passentity, collisionGroup ), m_pPassEnt2(passentity2)
  {
  }
  
  bool CTraceFilterSkipTwoEntities::ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  {
  	Assert( pHandleEntity );
  	if ( !PassServerEntityFilter( pHandleEntity, m_pPassEnt2 ) )
  		return false;
  
  	return CTraceFilterSimple::ShouldHitEntity( pHandleEntity, contentsMask );
  }