//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CEP2GameStats::Event_PlayerKilled( CBasePlayer *pPlayer, const CTakeDamageInfo &info )
{
	BaseClass::Event_PlayerKilled( pPlayer, info );

	if ( info.GetDamageType() & DMG_FALL )
	{
		++m_pCurrentMap->m_IntCounters[ Ep2LevelStats_t::COUNTER_FALLINGDEATHS ];
	}

	Ep2LevelStats_t::PlayerDeathsLump_t death;

	// set the location where the target died
	const Vector &org = pPlayer->GetAbsOrigin();
	death.nPosition[ 0 ] = static_cast<short>( org.x );
	death.nPosition[ 1 ] = static_cast<short>( org.y );
	death.nPosition[ 2 ] = static_cast<short>( org.z );

	StatsLog( "CEP2GameStats::Event_PlayerKilled at location [%d %d %d]\n", (int)death.nPosition[ 0 ], (int)death.nPosition[ 1 ], (int)death.nPosition[ 2 ] );

	// set the class of the attacker
	CBaseEntity *pInflictor = info.GetInflictor();
	CBaseEntity *pKiller = info.GetAttacker();

	if ( pInflictor )
	{
		StatsLog( "Inflictor: %s\n", pInflictor->GetClassname() );
	}

	if ( pKiller )
	{
		char const *pchKiller = pKiller->GetClassname();
		Ep2LevelStats_t::EntityDeathsLump_t *lump = FindDeathsLump( pchKiller );
		if ( lump )
		{
			++lump->m_nKilledPlayer;
			StatsLog( "Player has been killed %d times by %s's\n", lump->m_nKilledPlayer, pchKiller );
		}
		else
		{
			StatsLog( "Player killed by %s (not tracked)\n", pchKiller );
		}
	}

	// add it to the list of deaths
	Ep2LevelStats_t *map = FindOrAddMapStats( STRING( gpGlobals->mapname ) );
	int slot = map->m_aPlayerDeaths.AddToTail( death );

	Ep2LevelStats_t::SaveGameInfoRecord2_t *rec = map->m_SaveGameInfo.m_pCurrentRecord;
	if ( rec )
	{
		if ( rec->m_nFirstDeathIndex == -1 )
		{
			rec->m_nFirstDeathIndex = slot;
		}
		++rec->m_nNumDeaths;

		StatsLog( "Player has died %d times since last save/load\n", rec->m_nNumDeaths );
	}
}
void CTFOClassnameFinder::FindTarget( inputdata_t &inputdata )
{
	bool bFound = false;
	CBaseEntity *pMyFoundEnt = NULL;

	// Try classname
	pMyFoundEnt = gEntList.FindEntityByClassname( NULL, szTarget.ToCStr() );
	while ( pMyFoundEnt )
	{
		if ( !strcmp( pMyFoundEnt->GetClassname(), szTarget.ToCStr() ) )
		{
			pFoundTarget.FireOutput( this, this );
			bFound = true;
			break;
		}

		pMyFoundEnt = gEntList.FindEntityByClassname( pMyFoundEnt, szTarget.ToCStr() );
	}

	if ( bFound ) 
		return;

	// Try the actual name
	pMyFoundEnt = gEntList.FindEntityByName( NULL, szTarget.ToCStr() );
	while ( pMyFoundEnt )
	{
		if ( !strcmp( pMyFoundEnt->GetEntityName().ToCStr(), szTarget.ToCStr() ) )
		{
			pFoundTarget.FireOutput( this, this );
			break;
		}

		pMyFoundEnt = gEntList.FindEntityByName( pMyFoundEnt, szTarget.ToCStr() );
	}
}
	virtual const char			*GetSceneFile( EntitySearchResult sr )
	{
		CBaseEntity *ent = reinterpret_cast< CBaseEntity* >( sr );
		if ( !sr )
			return "";

		if ( Q_stricmp( ent->GetClassname(), "logic_choreographed_scene" ) )
			return "";

		return GetSceneFilename( ent );
	}
//-----------------------------------------------------------------------------
// Returns the name for debugging purposes
//-----------------------------------------------------------------------------
char const* CMoveHelperServer::GetName( EntityHandle_t handle ) const
{
	// This ain't pertickulerly fast, but it's for debugging anyways
	edict_t* pEdict = GetEdict(handle);
	CBaseEntity *ent = CBaseEntity::Instance( pEdict );
	
	// Is it the world?
	if (ENTINDEX(pEdict) == 0)
		return STRING(gpGlobals->mapname);

	// Is it a model?
	if ( ent && ent->GetModelName() != NULL_STRING )
		return STRING( ent->GetModelName() );

	if ( ent->GetClassname() != NULL )
	{
		return ent->GetClassname();
	}

	return "?";
}	
void cc_asw_inventory()
{
	CASW_Player *pPlayer = ToASW_Player(UTIL_GetCommandClient());
	if ( pPlayer->GetMarine() )
	{
		for (int i=0;i<pPlayer->GetMarine()->WeaponCount();i++)
		{
			CBaseEntity *pWeapon = pPlayer->GetMarine()->GetWeapon(i);
			if ( pWeapon )
			{
				Msg(" Inventory[%d] = %s (%d)\n", i, pWeapon->GetClassname(), pWeapon->entindex() );
			}
		}
	}
}
void CFuncTankControls::Think()
{
	CBaseEntity* pTarget = nullptr;

	do
	{
		pTarget = UTIL_FindEntityByTargetname( pTarget, GetTarget() );
	}
	while( !FNullEnt( pTarget ) && strncmp( pTarget->GetClassname(), "func_tank", 9 ) );

	if( FNullEnt( pTarget ) )
	{
		ALERT( at_console, "No tank %s\n", GetTarget() );
		return;
	}

	m_pTank = static_cast<CFuncTank*>( pTarget );
}
//-----------------------------------------------------------------------------
// Purpose: Push a physics object in our wash. Return false if it's now out of our wash
//-----------------------------------------------------------------------------
bool CBaseHelicopter::DoWashPush( washentity_t *pWash, Vector vecWashOrigin )
{
	if ( !pWash || !pWash->hEntity.Get() )
		return false;

	// Make sure the entity is still within our wash's radius
	CBaseEntity *pEntity = pWash->hEntity;
	Vector vecSpot = pEntity->BodyTarget( vecWashOrigin );
	Vector vecToSpot = ( vecSpot - vecWashOrigin );
	vecToSpot.z = 0;
	float flDist = VectorNormalize( vecToSpot );
	if ( flDist > BASECHOPPER_WASH_RADIUS )
		return false;

	IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();

	if ( pPhysObject == NULL )
		return false;

	// Push it away from the center of the wash
	float flMass = pPhysObject->GetMass();
	float flPushTime = (gpGlobals->curtime - pWash->flWashStartTime);
	float flMinPush = BASECHOPPER_WASH_PUSH_MIN * flMass;
	float flMaxPush = BASECHOPPER_WASH_PUSH_MAX * flMass;
	float flWashAmount = min( flMaxPush, RemapVal( flPushTime, 0, BASECHOPPER_WASH_RAMP_TIME, flMinPush, flMaxPush ) );
	Vector vecForce = flWashAmount * vecToSpot * phys_pushscale.GetFloat();
	pEntity->VPhysicsTakeDamage( CTakeDamageInfo( this, this, vecForce, vecWashOrigin, flWashAmount, DMG_BLAST ) );

	// Debug
	if ( g_debug_basehelicopter.GetInt() == BASECHOPPER_DEBUG_WASH )
	{
		NDebugOverlay::Cross3D( pEntity->GetAbsOrigin(), -Vector(4,4,4), Vector(4,4,4), 255, 0, 0, true, 0.1f );
		NDebugOverlay::Line( pEntity->GetAbsOrigin(), pEntity->GetAbsOrigin() + vecForce, 255, 255, 0, true, 0.1f );

		IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();
		Msg("Pushed %s (mass %f) with force %f (min %.2f max %.2f) at time %.2f\n", pEntity->GetClassname(), pPhysObject->GetMass(), flWashAmount, flMinPush, flMaxPush, gpGlobals->curtime );
	}

	// If we've pushed this thing for some time, remove it to give us a chance to find lighter things nearby
	if ( flPushTime > 2.0 )
		return false;

	return true;
}
	void ReportEntityList()
	{
		const char *pLastClass = "";
		int count = 0;
		int edicts = 0;
		for ( int i = 0; i < m_sortedList.Count(); i++ )
		{
			CBaseEntity *pEntity = m_sortedList[i];
			if ( !pEntity )
				continue;

			if ( pEntity->edict() )
				edicts++;

			const char *pClassname = pEntity->GetClassname();
			if ( !FStrEq( pClassname, pLastClass ) )
			{
				if ( count )
				{
					Msg("Class: %s (%d)\n", pLastClass, count );
				}

				pLastClass = pClassname;
				count = 1;
			}
			else
				count++;
		}
		if ( pLastClass[0] != 0 && count )
		{
			Msg("Class: %s (%d)\n", pLastClass, count );
		}
		if ( m_sortedList.Count() )
		{
			Msg("Total %d entities (%d empty, %d edicts)\n", m_sortedList.Count(), m_emptyCount, edicts );
		}
	}
Exemple #9
0
	entityIndex = trace.m_pEnt ? (short)trace.m_pEnt->entindex() : 0;
	if ( entityIndex )
	{
		CBaseEntity *ent = trace.m_pEnt;
		if ( ent )
		{
			modelIndex = ent->GetModelIndex();
			VectorITransform( GetAbsOrigin(), ent->EntityToWorldTransform(), position );

			canDraw = ( modelIndex != 0 );
			if ( !canDraw )
			{
				Warning( "Suppressed StaticDecal which would have hit entity %i (class:%s, name:%s) with modelindex = 0\n",
					ent->entindex(),
					ent->GetClassname(),
					STRING( ent->GetEntityName() ) );
			}
		}
	}

	if ( canDraw )
	{
		engine->StaticDecal( position, m_nTexture, entityIndex, modelIndex, m_bLowPriority );
	}

	SUB_Remove();
}


bool CDecal::KeyValue( const char *szKeyName, const char *szValue )
//-----------------------------------------------------------------------------
// Purpose: Push a physics object in our wash. Return false if it's now out of our wash
//-----------------------------------------------------------------------------
bool CBaseHelicopter::DoWashPush( washentity_t *pWash, const Vector &vecWashOrigin )
{
	if ( !pWash || !pWash->hEntity.Get() )
		return false;

	// Make sure the entity is still within our wash's radius
	CBaseEntity *pEntity = pWash->hEntity;

	// This can happen because we can dynamically turn this flag on and off
	if ( pEntity->IsEFlagSet( EFL_NO_ROTORWASH_PUSH ))
		return false;

	Vector vecSpot = pEntity->BodyTarget( vecWashOrigin );
	Vector vecToSpot = ( vecSpot - vecWashOrigin );
	vecToSpot.z = 0;
	float flDist = VectorNormalize( vecToSpot );
	if ( flDist > BASECHOPPER_WASH_RADIUS )
		return false;

	IRotorWashShooter *pShooter = GetRotorWashShooter( pEntity );
	IPhysicsObject *pPhysObject;

	
	float flPushTime = (gpGlobals->curtime - pWash->flWashStartTime);
	flPushTime = clamp( flPushTime, 0, BASECHOPPER_WASH_RAMP_TIME );
	float flWashAmount = RemapVal( flPushTime, 0, BASECHOPPER_WASH_RAMP_TIME, BASECHOPPER_WASH_PUSH_MIN, BASECHOPPER_WASH_PUSH_MAX );

	if ( pShooter )
	{
		Vector vecForce = (0.015f / 0.1f) * flWashAmount * vecToSpot * phys_pushscale.GetFloat();
		pEntity = pShooter->DoWashPush( pWash->flWashStartTime, vecForce );
		if ( !pEntity )
			return true;

		washentity_t Wash;
		Wash.hEntity = pEntity;
		Wash.flWashStartTime = pWash->flWashStartTime;
		int i = m_hEntitiesPushedByWash.AddToTail( Wash );
		pWash = &m_hEntitiesPushedByWash[i];
		
		pPhysObject = pEntity->VPhysicsGetObject();
		if ( !pPhysObject )
			return true;
	}
	else
	{
		// Airboat gets special treatment
		if ( FClassnameIs( pEntity, "prop_vehicle_airboat" ) )
		{
			DoWashPushOnAirboat( pEntity, vecToSpot, flWashAmount );
			return true;
		}

		pPhysObject = pEntity->VPhysicsGetObject();
		if ( !pPhysObject )
			return false;
	}

	// Push it away from the center of the wash
	float flMass = pPhysObject->GetMass();

	// This used to be mass independent, which is a bad idea because it blows 200kg engine blocks
	// as much as it blows cardboard and soda cans. Make this force mass-independent, but clamp at
	// 30kg. 
	flMass = MIN( flMass, 30.0f );

	Vector vecForce = (0.015f / 0.1f) * flWashAmount * flMass * vecToSpot * phys_pushscale.GetFloat();
	pEntity->VPhysicsTakeDamage( CTakeDamageInfo( this, this, vecForce, vecWashOrigin, flWashAmount, DMG_BLAST ) );

	// Debug
	if ( g_debug_basehelicopter.GetInt() == BASECHOPPER_DEBUG_WASH )
	{
		NDebugOverlay::Cross3D( pEntity->GetAbsOrigin(), -Vector(4,4,4), Vector(4,4,4), 255, 0, 0, true, 0.1f );
		NDebugOverlay::Line( pEntity->GetAbsOrigin(), pEntity->GetAbsOrigin() + vecForce, 255, 255, 0, true, 0.1f );

		IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();
		Msg("Pushed %s (index %d) (mass %f) with force %f (min %.2f max %.2f) at time %.2f\n", 
			pEntity->GetClassname(), pEntity->entindex(), pPhysObject->GetMass(), flWashAmount, 
			BASECHOPPER_WASH_PUSH_MIN * flMass, BASECHOPPER_WASH_PUSH_MAX * flMass, gpGlobals->curtime );
	}

	// If we've pushed this thing for some time, remove it to give us a chance to find lighter things nearby
	if ( flPushTime > 2.0 )
		return false;

	return true;
}
Exemple #11
0
CBaseEntity	* CASW_Rocket::FindPotentialTarget( void ) const
{
	float		bestdist = 0;		
	CBaseEntity	*bestent = NULL;

	Vector v_forward, v_right, v_up;
	AngleVectors( GetAbsAngles(), &v_forward, &v_right, &v_up );

	// find the aimtarget nearest us
	int count = AimTarget_ListCount();		
	if ( count )
	{
		CBaseEntity **pList = (CBaseEntity **)stackalloc( sizeof(CBaseEntity *) * count );
		AimTarget_ListCopy( pList, count );

		CTraceFilterSkipTwoEntities filter(this, GetOwnerEntity(), COLLISION_GROUP_NONE);

		for ( int i = 0; i < count; i++ )
		{
			CBaseEntity *pEntity = pList[i];

			if (!pEntity || !pEntity->IsAlive() || !pEntity->edict() || !pEntity->IsNPC() )
			{
				//Msg("not alive or not an edict, skipping\n");
				continue;
			}

			if (!pEntity || !pEntity->IsAlive() || !pEntity->edict() || !pEntity->IsNPC() )
			{
				//Msg("not alive or not an edict, skipping\n");
				continue;
			}
	
			// don't autoaim onto marines
			if (pEntity->Classify() == CLASS_ASW_MARINE || pEntity->Classify() == CLASS_ASW_COLONIST)
				continue;

			if ( pEntity->Classify() == CLASS_ASW_PARASITE )
			{
				CASW_Parasite *pParasite = static_cast< CASW_Parasite* >( pEntity );
				if ( pParasite->m_bInfesting )
				{
					continue;
				}
			}

			Vector center = pEntity->BodyTarget( GetAbsOrigin() );
			Vector center_flat = center;
			center_flat.z = GetAbsOrigin().z;

			Vector dir = (center - GetAbsOrigin());
			VectorNormalize( dir );

			Vector dir_flat = (center_flat - GetAbsOrigin());
			VectorNormalize( dir_flat );

			// make sure it's in front of the rocket
			float dot = DotProduct (dir, v_forward );
			//if (dot < 0)
			//{					
			//continue;
			//}

			float dist = (pEntity->GetAbsOrigin() - GetAbsOrigin()).LengthSqr();
			if (dist > ASW_ROCKET_MAX_HOMING_RANGE)
				continue;

			// check another marine isn't between us and the target to reduce FF
			trace_t tr;
			UTIL_TraceLine(GetAbsOrigin(), pEntity->WorldSpaceCenter(), MASK_SHOT, &filter, &tr);
			if (tr.fraction < 1.0f && tr.m_pEnt != pEntity && tr.m_pEnt && tr.m_pEnt->Classify() == CLASS_ASW_MARINE)
				continue;

			// does this critter already have enough rockets to kill it?
			{ 
				CASW_DamageAllocationMgr::IndexType_t assignmentIndex = m_RocketAssigner.Find( pEntity );
				if ( m_RocketAssigner.IsValid(assignmentIndex) )
				{
					if ( m_RocketAssigner[assignmentIndex].m_flAccumulatedDamage > pEntity->GetHealth() )
					{
						continue;
					}
				}
			}


			// check another marine isn't between us and the target to reduce FF
			UTIL_TraceLine(GetAbsOrigin(), pEntity->WorldSpaceCenter(), MASK_SHOT, &filter, &tr);
			if (tr.fraction < 1.0f && tr.m_pEnt != pEntity && tr.m_pEnt && tr.m_pEnt->Classify() == CLASS_ASW_MARINE)
				continue;

			// increase distance if dot isn't towards us
			dist += (1.0f - dot) * 150;	// bias of x units when object is 90 degrees to the side
			if (bestdist == 0 || dist < bestdist)
			{
				bestdist = dist;
				bestent = pEntity;
			}
		}

		if ( bestent && asw_rocket_debug.GetBool() )
		{
			Vector center = bestent->BodyTarget( GetAbsOrigin() );
			Vector center_flat = center;
			center_flat.z = GetAbsOrigin().z;

			Vector dir = (center - GetAbsOrigin());
			VectorNormalize( dir );
			Msg( "Rocket[%d] starting homing in on %s(%d) dir = %f %f %f\n", entindex(), bestent->GetClassname(), bestent->entindex(), VectorExpand( dir ) );
		}
	}

	return bestent;
}
void CHL2MPRules::CleanUpMap()
{
    // Recreate all the map entities from the map data (preserving their indices),
    // then remove everything else except the players.

    // Get rid of all entities except players.
    CBaseEntity *pCur = gEntList.FirstEnt();
    while ( pCur )
    {
        CBaseHL2MPCombatWeapon *pWeapon = dynamic_cast< CBaseHL2MPCombatWeapon* >( pCur );
        // Weapons with owners don't want to be removed..
        if ( pWeapon )
        {
            if ( !pWeapon->GetPlayerOwner() )
            {
                UTIL_Remove( pCur );
            }
        }
        // remove entities that has to be restored on roundrestart (breakables etc)
        else if ( !FindInList( s_PreserveEnts, pCur->GetClassname() ) )
        {
            UTIL_Remove( pCur );
        }

        pCur = gEntList.NextEnt( pCur );
    }

    // Really remove the entities so we can have access to their slots below.
    gEntList.CleanupDeleteList();

    // Cancel all queued events, in case a func_bomb_target fired some delayed outputs that
    // could kill respawning CTs
    g_EventQueue.Clear();

    // Now reload the map entities.
    class CHL2MPMapEntityFilter : public IMapEntityFilter
    {
    public:
        virtual bool ShouldCreateEntity( const char *pClassname )
        {
            // Don't recreate the preserved entities.
            if ( !FindInList( s_PreserveEnts, pClassname ) )
            {
                return true;
            }
            else
            {
                // Increment our iterator since it's not going to call CreateNextEntity for this ent.
                if ( m_iIterator != g_MapEntityRefs.InvalidIndex() )
                    m_iIterator = g_MapEntityRefs.Next( m_iIterator );

                return false;
            }
        }


        virtual CBaseEntity* CreateNextEntity( const char *pClassname )
        {
            if ( m_iIterator == g_MapEntityRefs.InvalidIndex() )
            {
                // This shouldn't be possible. When we loaded the map, it should have used
                // CCSMapLoadEntityFilter, which should have built the g_MapEntityRefs list
                // with the same list of entities we're referring to here.
                Assert( false );
                return NULL;
            }
            else
            {
                CMapEntityRef &ref = g_MapEntityRefs[m_iIterator];
                m_iIterator = g_MapEntityRefs.Next( m_iIterator );	// Seek to the next entity.

                if ( ref.m_iEdict == -1 || engine->PEntityOfEntIndex( ref.m_iEdict ) )
                {
                    // Doh! The entity was delete and its slot was reused.
                    // Just use any old edict slot. This case sucks because we lose the baseline.
                    return CreateEntityByName( pClassname );
                }
                else
                {
                    // Cool, the slot where this entity was is free again (most likely, the entity was
                    // freed above). Now create an entity with this specific index.
                    return CreateEntityByName( pClassname, ref.m_iEdict );
                }
            }
        }

    public:
        int m_iIterator; // Iterator into g_MapEntityRefs.
    };
    CHL2MPMapEntityFilter filter;
    filter.m_iIterator = g_MapEntityRefs.Head();

    // DO NOT CALL SPAWN ON info_node ENTITIES!

    MapEntity_ParseAllEntities( engine->GetMapEntitiesString(), &filter, true );
}
Exemple #13
0
/*
==============================
SUB_UseTargets

If self.delay is set, a DelayedUse entity will be created that will actually
do the SUB_UseTargets after that many seconds have passed.

Removes all entities with a targetname that match self.killtarget,
and removes them, so some events can remove other triggers.

Search for (string)targetname in all entities that
match (string)self.target and call their .use function (if they have one)

==============================
*/
void CBaseDelay::SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value )
{
	//
	// exit immediatly if we don't have a target or kill target
	//
	if( !HasTarget() && !m_iszKillTarget )
		return;

	//
	// check for a delay
	//
	if( m_flDelay != 0 )
	{
		// create a temp object to fire at a later time
		auto pTemp = static_cast<CBaseDelay*>( UTIL_CreateNamedEntity( "DelayedUse" ) );

		pTemp->SetNextThink( gpGlobals->time + m_flDelay );

		pTemp->SetThink( &CBaseDelay::DelayThink );

		// Save the useType
		pTemp->GetButtons().Set( ( int ) useType );
		pTemp->m_iszKillTarget = m_iszKillTarget;
		pTemp->m_flDelay = 0; // prevent "recursion"
		pTemp->SetTarget( GetTarget() );

		// HACKHACK
		// This wasn't in the release build of Half-Life.  We should have moved m_hActivator into this class
		// but changing member variable hierarchy would break save/restore without some ugly code.
		// This code is not as ugly as that code
		if( pActivator && pActivator->IsPlayer() )		// If a player activates, then save it
		{
			pTemp->SetOwner( pActivator );
		}
		else
		{
			pTemp->SetOwner( NULL );
		}

		return;
	}

	//
	// kill the killtargets
	//

	if( m_iszKillTarget )
	{
		CBaseEntity* pKillTarget = nullptr;

		ALERT( at_aiconsole, "KillTarget: %s\n", STRING( m_iszKillTarget ) );
		while( ( pKillTarget = UTIL_FindEntityByTargetname( pKillTarget, STRING( m_iszKillTarget ) ) ) != nullptr )
		{
			UTIL_Remove( pKillTarget );

			ALERT( at_aiconsole, "killing %s\n", pKillTarget->GetClassname() );
		}
	}

	//
	// fire targets
	//
	if( HasTarget() )
	{
		FireTargets( GetTarget(), pActivator, this, useType, value );
	}
}
	void DrawOverlays(CTFBotMissionSuicideBomber *action, CTFBot *actor)
	{
		constexpr float dt = 0.1f;
		
		constexpr float target_cross_size = 5.0f;
		constexpr int   target_cross_r    = 0x00;
		constexpr int   target_cross_g    = 0xff;
		constexpr int   target_cross_b    = 0x00;
		
		constexpr float det_cross_size = 5.0f;
		constexpr int   det_cross_r    = 0xff;
		constexpr int   det_cross_g    = 0x00;
		constexpr int   det_cross_b    = 0x00;
		
		
		int line;
		char buf[1024];
		
		
		/* OVERLAYS: BOT */
		line = 0;
		
		auto pos = actor->GetAbsOrigin();
		snprintf(buf, sizeof(buf), "POS: (%4.0f, %4.0f, %4.0f)", pos.x, pos.y, pos.z);
		NDebugOverlay::EntityText(ENTINDEX(actor), line++, buf, dt, 255, 255, 255, 255);
		
		snprintf(buf, sizeof(buf), "HEALTH: %d", actor->GetHealth());
		NDebugOverlay::EntityText(ENTINDEX(actor), line++, buf, dt, 255, 255, 255, 255);
		
		CBaseEntity *target = action->m_hTarget;
		if (target == nullptr) {
			snprintf(buf, sizeof(buf), "TARGET: null");
		} else {
			const char *name;
			if (target->IsPlayer()) {
				name = static_cast<CBasePlayer *>(target)->GetPlayerName();
			} else {
				name = STRING(target->GetEntityName());
			}
			snprintf(buf, sizeof(buf), "TARGET: #%d '%s' '%s'",
				ENTINDEX(target), target->GetClassname(), name);
		}
		NDebugOverlay::EntityText(ENTINDEX(actor), line++, buf, dt, 255, 255, 255, 255);
		
		snprintf(buf, sizeof(buf), "PATH FAILS: %d", action->m_nConsecutivePathFailures);
		NDebugOverlay::EntityText(ENTINDEX(actor), line++, buf, dt, 255, 255, 255, 255);
		
		if (action->m_ctRecomputePath.HasStarted()) {
			snprintf(buf, sizeof(buf), "TIMER(path): %.1f / %.1f",
				action->m_ctRecomputePath.GetElapsedTime(),
				action->m_ctRecomputePath.GetCountdownDuration());
		} else {
			snprintf(buf, sizeof(buf), "TIMER(path): NOT STARTED");
		}
		NDebugOverlay::EntityText(ENTINDEX(actor), line++, buf, dt, 255, 255, 255, 255);
		
		if (action->m_ctPlaySound.HasStarted()) {
			snprintf(buf, sizeof(buf), "TIMER(sound): %.1f / %.1f",
				action->m_ctPlaySound.GetElapsedTime(),
				action->m_ctPlaySound.GetCountdownDuration());
		} else {
			snprintf(buf, sizeof(buf), "TIMER(sound): NOT STARTED");
		}
		NDebugOverlay::EntityText(ENTINDEX(actor), line++, buf, dt, 255, 255, 255, 255);
		
		if (action->m_ctDetonation.HasStarted()) {
			snprintf(buf, sizeof(buf), "TIMER(det): %.1f / %.1f",
				action->m_ctDetonation.GetElapsedTime(),
				action->m_ctDetonation.GetCountdownDuration());
		} else {
			snprintf(buf, sizeof(buf), "TIMER(det): NOT STARTED");
		}
		NDebugOverlay::EntityText(ENTINDEX(actor), line++, buf, dt, 255, 255, 255, 255);
		
		snprintf(buf, sizeof(buf), "DETONATING: %s",
			(action->m_bDetonating ? "yes" : "no"));
		NDebugOverlay::EntityText(ENTINDEX(actor), line++, buf, dt, 255, 255, 255, 255);
		
		snprintf(buf, sizeof(buf), "DET(reached_goal): %s",
			(action->m_bDetReachedGoal ? "yes" : "no"));
		NDebugOverlay::EntityText(ENTINDEX(actor), line++, buf, dt, 255, 255, 255, 255);
		
		snprintf(buf, sizeof(buf), "DET(lost_all_health): %s",
			(action->m_bDetLostAllHealth ? "yes" : "no"));
		NDebugOverlay::EntityText(ENTINDEX(actor), line++, buf, dt, 255, 255, 255, 255);
		
		ConVarRef tf_bot_suicide_bomb_range("tf_bot_suicide_bomb_range");
		float det_range = tf_bot_suicide_bomb_range.GetFloat() / 3.0f;
		
		int det_sphere_r = 0xff;
		int det_sphere_g = 0x00;
		int det_sphere_b = 0x00;
		int det_sphere_a = 0x00;
		
		if (action->m_vecTargetPos.DistToSqr(actor->GetAbsOrigin()) < det_range * det_range) {
			Vector vec_clear = action->m_vecTargetPos;
			vec_clear.z += 18.0f;
			
			if (actor->IsLineOfFireClear(vec_clear)) {
				det_sphere_r = 0x00;
				det_sphere_g = 0xff;
				det_sphere_b = 0x00;
			} else {
				det_sphere_r = 0xff;
				det_sphere_g = 0xff;
				det_sphere_b = 0x00;
			}
		}
		
		NDebugOverlay::Sphere(actor->GetAbsOrigin(), vec3_angle, det_range,
			det_sphere_r, det_sphere_g, det_sphere_b, det_sphere_a, true, dt);
		
		
		/* OVERLAYS: TARGET POS */
		line = 0;
		
		snprintf(buf, sizeof(buf), "TARGET POS: (%4.0f, %4.0f, %4.0f)",
			action->m_vecTargetPos.x, action->m_vecTargetPos.y, action->m_vecTargetPos.z);
		NDebugOverlay::EntityTextAtPosition(action->m_vecTargetPos, line++, buf, dt, 255, 255, 255, 255);
		
		snprintf(buf, sizeof(buf), "DIST TO: %.1f", action->m_vecTargetPos.DistToSqr(actor->GetAbsOrigin()));
		
		NDebugOverlay::Cross3D(action->m_vecTargetPos,
			target_cross_size, target_cross_r, target_cross_g, target_cross_b, true, dt);
		
		
		/* OVERLAYS: DETONATE POS */
		line = 0;
		
		snprintf(buf, sizeof(buf), "DET POS: (%4.0f, %4.0f, %4.0f)",
			action->m_vecDetonatePos.x, action->m_vecDetonatePos.y, action->m_vecDetonatePos.z);
		NDebugOverlay::EntityTextAtPosition(action->m_vecDetonatePos, line++, buf, dt, 255, 255, 255, 255);
		
		NDebugOverlay::Cross3D(action->m_vecDetonatePos,
			det_cross_size, det_cross_r, det_cross_g, det_cross_b, true, dt);
	}
Exemple #15
0
void RadiusFlash(
    Vector vecSrc,
    CBaseEntity *pevInflictor,
    CBaseEntity *pevAttacker,
    float flDamage,
    int iClassIgnore,
    int bitsDamageType)
{
    vecSrc.z += 1;// in case grenade is lying on the ground

    if (!pevAttacker)
        pevAttacker = pevInflictor;

    trace_t		tr;
    float		flAdjustedDamage;
    variant_t	var;
    Vector		vecEyePos;
    float		fadeTime, fadeHold;
    Vector		vForward;
    Vector		vecLOS;
    float		flDot;

    CBaseEntity		*pEntity = NULL;
    static float	flRadius = 1500;
    float			falloff = flDamage / flRadius;

    bool bInWater = (UTIL_PointContents(vecSrc) == CONTENTS_WATER);

    // iterate on all entities in the vicinity.
    while ((pEntity = gEntList.FindEntityInSphere(pEntity, vecSrc, flRadius)) != NULL)
    {
        bool bPlayer = pEntity->IsPlayer();
        bool bHostage = (Q_stricmp(pEntity->GetClassname(), "hostage_entity") == 0);

        if (!bPlayer && !bHostage)
            continue;

        vecEyePos = pEntity->EyePosition();

        // blasts don't travel into or out of water
        if (bInWater && pEntity->GetWaterLevel() == 0)
            continue;
        if (!bInWater && pEntity->GetWaterLevel() == 3)
            continue;

        float percentageOfFlash = PercentageOfFlashForPlayer(pEntity, vecSrc, pevInflictor);

        if (percentageOfFlash > 0.0)
        {
            // decrease damage for an ent that's farther from the grenade
            flAdjustedDamage = flDamage - (vecSrc - pEntity->EyePosition()).Length() * falloff;

            if (flAdjustedDamage > 0)
            {
                // See if we were facing the flash
                AngleVectors(pEntity->EyeAngles(), &vForward);

                vecLOS = (vecSrc - vecEyePos);

                //float flDistance = vecLOS.Length();

                // Normalize both vectors so the dotproduct is in the range -1.0 <= x <= 1.0 
                vecLOS.NormalizeInPlace();

                flDot = DotProduct(vecLOS, vForward);

                float startingAlpha = 255;

                // if target is facing the bomb, the effect lasts longer
                if (flDot >= 0.5)
                {
                    // looking at the flashbang
                    fadeTime = flAdjustedDamage * 2.5f;
                    fadeHold = flAdjustedDamage * 1.25f;
                }
                else if (flDot >= -0.5)
                {
                    // looking to the side
                    fadeTime = flAdjustedDamage * 1.75f;
                    fadeHold = flAdjustedDamage * 0.8f;
                }
                else
                {
                    // facing away
                    fadeTime = flAdjustedDamage * 1.0f;
                    fadeHold = flAdjustedDamage * 0.75f;
                    startingAlpha = 200;
                }

                fadeTime *= percentageOfFlash;
                fadeHold *= percentageOfFlash;

                if (bPlayer)
                {
                    //MOM_TODO: do we want this functionality?
                    // blind players and bots
                    //CMomentumPlayer *player = static_cast<CMomentumPlayer *>(pEntity);
                    //player->Blind( fadeHold, fadeTime, startingAlpha );

                    // deafen players and bots
                    //player->Deafen( flDistance );
                }
                else if (bHostage)
                {
                    variant_t val;
                    val.SetFloat(fadeTime);
                    pEntity->AcceptInput("flashbang", pevInflictor, pevAttacker, val, 0);
                }
            }
        }
    }

    CPVSFilter filter(vecSrc);
    te->DynamicLight(filter, 0.0, &vecSrc, 255, 255, 255, 2, 400, 0.1, 768);
}
Exemple #16
0
CBaseEntity *CBasePlayer::FindUseEntity()
{
	Vector forward, up;
	EyeVectors( &forward, NULL, &up );

	trace_t tr;
	// Search for objects in a sphere (tests for entities that are not solid, yet still useable)
	Vector searchCenter = EyePosition();

	// NOTE: Some debris objects are useable too, so hit those as well
	// A button, etc. can be made out of clip brushes, make sure it's +useable via a traceline, too.
	int useableContents = MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_PLAYERCLIP;

#ifdef CSTRIKE_DLL
	useableContents = MASK_NPCSOLID_BRUSHONLY | MASK_OPAQUE_AND_NPCS;
#endif

#ifdef HL1_DLL
	useableContents = MASK_SOLID;
#endif
#ifndef CLIENT_DLL
	CBaseEntity *pFoundByTrace = NULL;
#endif

	// UNDONE: Might be faster to just fold this range into the sphere query
	CBaseEntity *pObject = NULL;

	float nearestDist = FLT_MAX;
	// try the hit entity if there is one, or the ground entity if there isn't.
	CBaseEntity *pNearest = NULL;

	const int NUM_TANGENTS = 8;
	// trace a box at successive angles down
	//							forward, 45 deg, 30 deg, 20 deg, 15 deg, 10 deg, -10, -15
	const float tangents[NUM_TANGENTS] = { 0, 1, 0.57735026919f, 0.3639702342f, 0.267949192431f, 0.1763269807f, -0.1763269807f, -0.267949192431f };
	for ( int i = 0; i < NUM_TANGENTS; i++ )
	{
		if ( i == 0 )
		{
			UTIL_TraceLine( searchCenter, searchCenter + forward * 1024, useableContents, this, COLLISION_GROUP_NONE, &tr );
		}
		else
		{
			Vector down = forward - tangents[i]*up;
			VectorNormalize(down);
			UTIL_TraceHull( searchCenter, searchCenter + down * 72, -Vector(16,16,16), Vector(16,16,16), useableContents, this, COLLISION_GROUP_NONE, &tr );
		}
		pObject = tr.m_pEnt;

#ifndef CLIENT_DLL
		pFoundByTrace = pObject;
#endif
		bool bUsable = IsUseableEntity(pObject, 0);
		while ( pObject && !bUsable && pObject->GetMoveParent() )
		{
			pObject = pObject->GetMoveParent();
			bUsable = IsUseableEntity(pObject, 0);
		}

		if ( bUsable )
		{
			Vector delta = tr.endpos - tr.startpos;
			float centerZ = CollisionProp()->WorldSpaceCenter().z;
			delta.z = IntervalDistance( tr.endpos.z, centerZ + CollisionProp()->OBBMins().z, centerZ + CollisionProp()->OBBMaxs().z );
			float dist = delta.Length();
			if ( dist < PLAYER_USE_RADIUS )
			{
#ifndef CLIENT_DLL

				if ( sv_debug_player_use.GetBool() )
				{
					NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
					NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
				}

				if ( pObject->MyNPCPointer() && pObject->MyNPCPointer()->IsPlayerAlly( this ) )
				{
					// If about to select an NPC, do a more thorough check to ensure
					// that we're selecting the right one from a group.
					pObject = DoubleCheckUseNPC( pObject, searchCenter, forward );
				}
#endif
				if ( sv_debug_player_use.GetBool() )
				{
					Msg( "Trace using: %s\n", pObject ? pObject->GetDebugName() : "no usable entity found" );
				}

				pNearest = pObject;
				
				// if this is directly under the cursor just return it now
				if ( i == 0 )
					return pObject;
			}
		}
	}

	// check ground entity first
	// if you've got a useable ground entity, then shrink the cone of this search to 45 degrees
	// otherwise, search out in a 90 degree cone (hemisphere)
	if ( GetGroundEntity() && IsUseableEntity(GetGroundEntity(), FCAP_USE_ONGROUND) )
	{
		pNearest = GetGroundEntity();
	}
	if ( pNearest )
	{
		// estimate nearest object by distance from the view vector
		Vector point;
		pNearest->CollisionProp()->CalcNearestPoint( searchCenter, &point );
		nearestDist = CalcDistanceToLine( point, searchCenter, forward );
		if ( sv_debug_player_use.GetBool() )
		{
			Msg("Trace found %s, dist %.2f\n", pNearest->GetClassname(), nearestDist );
		}
	}

	for ( CEntitySphereQuery sphere( searchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
	{
		if ( !pObject )
			continue;

		if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) )
			continue;

		// see if it's more roughly in front of the player than previous guess
		Vector point;
		pObject->CollisionProp()->CalcNearestPoint( searchCenter, &point );

		Vector dir = point - searchCenter;
		VectorNormalize(dir);
		float dot = DotProduct( dir, forward );

		// Need to be looking at the object more or less
		if ( dot < 0.8 )
			continue;

		float dist = CalcDistanceToLine( point, searchCenter, forward );

		if ( sv_debug_player_use.GetBool() )
		{
			Msg("Radius found %s, dist %.2f\n", pObject->GetClassname(), dist );
		}

		if ( dist < nearestDist )
		{
			// Since this has purely been a radius search to this point, we now
			// make sure the object isn't behind glass or a grate.
			trace_t trCheckOccluded;
			UTIL_TraceLine( searchCenter, point, useableContents, this, COLLISION_GROUP_NONE, &trCheckOccluded );

			if ( trCheckOccluded.fraction == 1.0 || trCheckOccluded.m_pEnt == pObject )
			{
				pNearest = pObject;
				nearestDist = dist;
			}
		}
	}

#ifndef CLIENT_DLL
	if ( !pNearest )
	{
		// Haven't found anything near the player to use, nor any NPC's at distance.
		// Check to see if the player is trying to select an NPC through a rail, fence, or other 'see-though' volume.
		trace_t trAllies;
		UTIL_TraceLine( searchCenter, searchCenter + forward * PLAYER_USE_RADIUS, MASK_OPAQUE_AND_NPCS, this, COLLISION_GROUP_NONE, &trAllies );

		if ( trAllies.m_pEnt && IsUseableEntity( trAllies.m_pEnt, 0 ) && trAllies.m_pEnt->MyNPCPointer() && trAllies.m_pEnt->MyNPCPointer()->IsPlayerAlly( this ) )
		{
			// This is an NPC, take it!
			pNearest = trAllies.m_pEnt;
		}
	}

	if ( pNearest && pNearest->MyNPCPointer() && pNearest->MyNPCPointer()->IsPlayerAlly( this ) )
	{
		pNearest = DoubleCheckUseNPC( pNearest, searchCenter, forward );
	}

	if ( sv_debug_player_use.GetBool() )
	{
		if ( !pNearest )
		{
			NDebugOverlay::Line( searchCenter, tr.endpos, 255, 0, 0, true, 30 );
			NDebugOverlay::Cross3D( tr.endpos, 16, 255, 0, 0, true, 30 );
		}
		else if ( pNearest == pFoundByTrace )
		{
			NDebugOverlay::Line( searchCenter, tr.endpos, 0, 255, 0, true, 30 );
			NDebugOverlay::Cross3D( tr.endpos, 16, 0, 255, 0, true, 30 );
		}
		else
		{
			NDebugOverlay::Box( pNearest->WorldSpaceCenter(), Vector(-8, -8, -8), Vector(8, 8, 8), 0, 255, 0, true, 30 );
		}
	}
#endif

	if ( sv_debug_player_use.GetBool() )
	{
		Msg( "Radial using: %s\n", pNearest ? pNearest->GetDebugName() : "no usable entity found" );
	}

	return pNearest;
}
bool CSDKPlayer::PlayerUse()
{
#ifdef GAME_DLL
	// Was use pressed or released?
	if ( ((m_nButtons | m_afButtonPressed | m_afButtonReleased) & IN_USE) && !IsObserver() )
	{
		Vector forward, up;
		EyeVectors( &forward, NULL, &up );

		Vector vecSearchCenter = EyePosition();
		CBaseEntity *pObject = nullptr;
		CBaseEntity *pNearest = nullptr;
		float flNearest = FLT_MAX;

		// Look for grenades so we can prioritize picking them up first.
		for ( CEntitySphereQuery sphere( vecSearchCenter, PLAYER_USE_RADIUS ); ( pObject = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
		{
			if ( !pObject )
				continue;

			if ( !IsUseableEntity( pObject, FCAP_USE_IN_RADIUS ) )
				continue;

			CWeaponSDKBase* pWeapon = dynamic_cast<CWeaponSDKBase*>(pObject);
			if (!pWeapon)
				continue;

			if (pWeapon->GetWeaponID() != SDK_WEAPON_GRENADE)
				continue;

			// If we're full up on grenades, pass over to whatever other weapons are lying around.
			if (!g_pGameRules->CanHavePlayerItem(this, pWeapon))
				continue;

			// see if it's more roughly in front of the player than previous guess
			Vector point;
			pObject->CollisionProp()->CalcNearestPoint( vecSearchCenter, &point );

			Vector dir = point - vecSearchCenter;
			VectorNormalize(dir);
			float dot = DotProduct( dir, forward );

			// Need to be looking at the object more or less
			if ( dot < 0.8 )
				continue;

			float dist = CalcDistanceToLine( point, vecSearchCenter, forward );

			ConVarRef sv_debug_player_use("sv_debug_player_use");
			if ( sv_debug_player_use.GetBool() )
			{
				Msg("Radius found %s, dist %.2f\n", pObject->GetClassname(), dist );
			}

			// Not worried about shit being behind a wall at this point.
			// Just greedily gobble up all nearby grenades since there's
			// no penalty to the player for doing so.

			if ( dist < flNearest )
			{
				pNearest = pObject;
				flNearest = dist;
			}
		}

		if (pNearest)
		{
			// This is a grenade. Use it to pick it up.
			variant_t emptyVariant;
			pNearest->AcceptInput( "Use", this, this, emptyVariant, USE_TOGGLE );
			return true;
		}
	}
#endif

	bool bUsed = BaseClass::PlayerUse();

	if (bUsed)
		return bUsed;

	if (!(m_afButtonPressed & IN_USE))
		return false;

	if (!IsAlive())
		return false;

	return false;
}
//=========================================================
// Deathnotice.
//=========================================================
void CHL2MPRules::DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info )
{
#ifndef CLIENT_DLL
    // Work out what killed the player, and send a message to all clients about it
    const char *killer_weapon_name = "world";		// by default, the player is killed by the world
    int killer_ID = 0;

    // Find the killer & the scorer
    CBaseEntity *pInflictor = info.GetInflictor();
    CBaseEntity *pKiller = info.GetAttacker();
    CBasePlayer *pScorer = GetDeathScorer( pKiller, pInflictor );

    // Custom kill type?
    if ( info.GetDamageCustom() )
    {
        killer_weapon_name = GetDamageCustomString( info );
        if ( pScorer )
        {
            killer_ID = pScorer->GetUserID();
        }
    }
    else
    {
        // Is the killer a client?
        if ( pScorer )
        {
            killer_ID = pScorer->GetUserID();

            if ( pInflictor )
            {
                if ( pInflictor == pScorer )
                {
                    // If the inflictor is the killer,  then it must be their current weapon doing the damage
                    if ( pScorer->GetActiveWeapon() )
                    {
                        killer_weapon_name = pScorer->GetActiveWeapon()->GetClassname();
                    }
                }
                else
                {
                    killer_weapon_name = pInflictor->GetClassname();  // it's just that easy
                }
            }
        }
        else
        {
            killer_weapon_name = pInflictor->GetClassname();
        }

        // strip the NPC_* or weapon_* from the inflictor's classname
        if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 )
        {
            killer_weapon_name += 7;
        }
        else if ( strncmp( killer_weapon_name, "npc_", 4 ) == 0 )
        {
            killer_weapon_name += 4;
        }
        else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 )
        {
            killer_weapon_name += 5;
        }
        else if ( strstr( killer_weapon_name, "physics" ) )
        {
            killer_weapon_name = "physics";
        }

        if ( strcmp( killer_weapon_name, "prop_combine_ball" ) == 0 )
        {
            killer_weapon_name = "combine_ball";
        }
        else if ( strcmp( killer_weapon_name, "grenade_ar2" ) == 0 )
        {
            killer_weapon_name = "smg1_grenade";
        }
        else if ( strcmp( killer_weapon_name, "satchel" ) == 0 || strcmp( killer_weapon_name, "tripmine" ) == 0)
        {
            killer_weapon_name = "slam";
        }


    }

    IGameEvent *event = gameeventmanager->CreateEvent( "player_death" );
    if( event )
    {
        event->SetInt("userid", pVictim->GetUserID() );
        event->SetInt("attacker", killer_ID );
        event->SetString("weapon", killer_weapon_name );
        event->SetInt( "priority", 7 );
        gameeventmanager->FireEvent( event );
    }
#endif

}
//---------------------------------------------------------
// Purpose: See if it is time to poll and do so. 
//
// SOON: We need to load-balance this. 
//---------------------------------------------------------
void CVisibilityMonitor::FrameUpdatePostEntityThink()
{
	if( gpGlobals->curtime < m_flTimeNextPoll )
		return;

	m_flTimeNextPoll = gpGlobals->curtime + vismon_poll_frequency.GetFloat();

	int iDebugging = debug_visibility_monitor.GetInt();

	if( m_Entities.Count() > m_iMaxEntitiesPerThink )
		m_iMaxEntitiesPerThink = m_Entities.Count();

	if( iDebugging > 1 )
	{
		Msg("\nVisMon: Polling now. (Frequency: %f)\n", m_flPollFrequency );
		Msg("VisMon: Time: %f - Tracking %d Entities. (Max:%d)\n", gpGlobals->curtime, m_Entities.Count(), m_iMaxEntitiesPerThink );
	}

	// Cleanup, dump entities that have been removed since we last polled.
	for ( int i = 0 ; i < m_Entities.Count() ; i++ )
	{
		if ( m_Entities[i].entity == NULL )
		{
			m_Entities.FastRemove(i);
			if ( i >= m_Entities.Count() )
			{
				break;
			}
		}
	}

	int numTraces = 0;
	bool bHitTraceLimit = false;

	if( m_iStartElement >= m_Entities.Count() )
	{
		if( iDebugging > 1 )
		{
			Msg("VisMon: RESET\n");
		}

		m_iStartElement = 0;
	}

	if( iDebugging > 1 )
	{
		Msg("VisMon: Starting at element: %d\n", m_iStartElement );
	}

	for( int i = m_iStartElement ; i < m_Entities.Count() ; i++ )
	{
		for( int j = 1 ; j <= gpGlobals->maxClients ; j++ )
		{
			CBasePlayer *pPlayer =UTIL_PlayerByIndex( j );

			if( pPlayer != NULL && pPlayer->IsAlive() && !pPlayer->IsBot() )
			{
				int memoryBit = 1 << j; // The bit that is used to remember whether a given entity has been seen by a given player.

				CBaseEntity *pSeeEntity = m_Entities[ i ].entity.Get();

				if( pSeeEntity == NULL )
				{
					continue;
				}

				if( !(m_Entities[i].memory & memoryBit) )
				{
					// If this player hasn't seen this entity yet, check it.
					if( EntityIsVisibleToPlayer( m_Entities[i], pPlayer, &numTraces ) )
					{
						bool bIgnore = false;

						if( m_Entities[i].pfnEvaluator != NULL && !m_Entities[i].pfnEvaluator( m_Entities[i].entity, pPlayer ) )
						{
							bIgnore = true;
						}

						// See it! Generate our event.
						if( iDebugging > 0 )
						{
							if( bIgnore )
							{
								Msg("VisMon: Player %s IGNORING VISIBILE Entity: %s\n", pPlayer->GetDebugName(), pSeeEntity->GetDebugName() );
								NDebugOverlay::Cross3D( pSeeEntity->WorldSpaceCenter(), 16, 255, 0, 0, false, 10.0f );
							}
							else
							{
								Msg("VisMon: Player %s sees Entity: %s\n", pPlayer->GetDebugName(), pSeeEntity->GetDebugName() );
								NDebugOverlay::Cross3D( pSeeEntity->WorldSpaceCenter(), 16, 0, 255, 0, false, 10.0f );
							}
						}

						if( !bIgnore )
						{
							bool bGenerateEvent = true;

							if( m_Entities[i].pfnCallback != NULL )
							{
								// Make the callback, and let it determine whether to generate the simple event.
								bGenerateEvent = m_Entities[i].pfnCallback( m_Entities[i].entity, pPlayer );
							}

							if( bGenerateEvent )
							{
								// No callback, generate the generic game event.
								IGameEvent * event = gameeventmanager->CreateEvent( "entity_visible" );
								if ( event )
								{
									event->SetInt( "userid", pPlayer->GetUserID() );
									event->SetInt( "subject", pSeeEntity->entindex() );
									event->SetString( "classname", pSeeEntity->GetClassname() );
									event->SetString( "entityname", STRING( pSeeEntity->GetEntityName() ) );
									gameeventmanager->FireEvent( event );
								}
							}

							// Remember that this entity was visible to the player
							m_Entities[i].memory |= memoryBit;
						}
					}
				}
			}
		}

		if( numTraces >= vismon_trace_limit.GetInt() )
		{
			if( iDebugging > 1 )
			{
				Msg("VisMon: MAX Traces. Stopping after element %d\n", i );
			}

			m_iStartElement = i + 1; // Pick up here next think.
			bHitTraceLimit = true;
			break;
		}
	}

	if( !bHitTraceLimit )
	{
		m_iStartElement = 0;
	}

	if( numTraces > m_iMaxTracesPerThink )
		m_iMaxTracesPerThink = numTraces;

	if( iDebugging > 1 )
	{
		Msg("VisMon: %d traces performed during this polling cycle (Max: %d)\n\n", numTraces, m_iMaxTracesPerThink );
	}
}