Exemple #1
0
void CVoiceGameMgr::UpdateMasks()
{
	m_UpdateInterval = 0;

	bool bAllTalk = !!g_engfuncs.pfnCVarGetFloat( "sv_alltalk" );

	for(int iClient=0; iClient < m_nMaxPlayers; iClient++)
	{
		CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient+1);
		if(!pEnt || !pEnt->IsPlayer())
			continue;

		// Request the state of their "VModEnable" cvar.
		if(g_bWantModEnable[iClient])
		{
			MESSAGE_BEGIN(MSG_ONE, m_msgRequestState, NULL, pEnt->pev);
			MESSAGE_END();
		}

		CBasePlayer *pPlayer = (CBasePlayer*)pEnt;

		CPlayerBitVec gameRulesMask;
		if(g_PlayerModEnable[iClient])
		{
			// Build a mask of who they can hear based on the game rules.
			for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++)
			{
				CBaseEntity *pEnt = UTIL_PlayerByIndex(iOtherClient+1);
				if(pEnt && pEnt->IsPlayer() && 
					(bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt)) )
				{
					gameRulesMask[iOtherClient] = true;
				}
			}
		}

		// If this is different from what the client has, send an update. 
		if(gameRulesMask != g_SentGameRulesMasks[iClient] || 
			g_BanMasks[iClient] != g_SentBanMasks[iClient])
		{
			g_SentGameRulesMasks[iClient] = gameRulesMask;
			g_SentBanMasks[iClient] = g_BanMasks[iClient];

			MESSAGE_BEGIN(MSG_ONE, m_msgPlayerVoiceMask, NULL, pPlayer->pev);
				int dw;
				for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++)
				{
					WRITE_LONG(gameRulesMask.GetDWord(dw));
					WRITE_LONG(g_BanMasks[iClient].GetDWord(dw));
				}
			MESSAGE_END();
		}

		// Tell the engine.
		for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++)
		{
			bool bCanHear = gameRulesMask[iOtherClient] && !g_BanMasks[iClient][iOtherClient];
			g_engfuncs.pfnVoice_SetClientListening(iClient+1, iOtherClient+1, bCanHear);
		}
	}
}
Exemple #2
0
//// HOST_SAY
// String comes in as
// say blah blah blah
// or as
// blah blah blah
//
void Host_Say( edict_t *pEdict, const CCommand &args, bool teamonly )
{
	CBasePlayer *client;
	int		j;
	char	*p;
	char	text[256];
	char    szTemp[256];
	const char *cpSay = "say";
	const char *cpSayTeam = "say_team";
	const char *pcmd = args[0];
	bool bSenderDead = false;

	// We can get a raw string now, without the "say " prepended
	if ( args.ArgC() == 0 )
		return;

	if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) )
	{
		if ( args.ArgC() >= 2 )
		{
			p = (char *)args.ArgS();
		}
		else
		{
			// say with a blank message, nothing to do
			return;
		}
	}
	else  // Raw text, need to prepend argv[0]
	{
		if ( args.ArgC() >= 2 )
		{
			Q_snprintf( szTemp,sizeof(szTemp), "%s %s", ( char * )pcmd, (char *)args.ArgS() );
		}
		else
		{
			// Just a one word command, use the first word...sigh
			Q_snprintf( szTemp,sizeof(szTemp), "%s", ( char * )pcmd );
		}
		p = szTemp;
	}

	CBasePlayer *pPlayer = NULL;
	if ( pEdict )
	{
		pPlayer = ((CBasePlayer *)CBaseEntity::Instance( pEdict ));
		Assert( pPlayer );

		// make sure the text has valid content
		p = CheckChatText( pPlayer, p );
	}

	if ( !p )
		return;

	if ( pEdict )
	{
		if ( !pPlayer->CanSpeak() )
			return;

		// See if the player wants to modify of check the text
		pPlayer->CheckChatText( p, 127 );	// though the buffer szTemp that p points to is 256, 
											// chat text is capped to 127 in CheckChatText above

		Assert( strlen( pPlayer->GetPlayerName() ) > 0 );

		bSenderDead = ( pPlayer->m_lifeState != LIFE_ALIVE );
	}
	else
	{
		bSenderDead = false;
	}

	const char *pszFormat = NULL;
	const char *pszPrefix = NULL;
	const char *pszLocation = NULL;
	if ( g_pGameRules )
	{
		pszFormat = g_pGameRules->GetChatFormat( teamonly, pPlayer );
		pszPrefix = g_pGameRules->GetChatPrefix( teamonly, pPlayer );	
		pszLocation = g_pGameRules->GetChatLocation( teamonly, pPlayer );
	}

	const char *pszPlayerName = pPlayer ? pPlayer->GetPlayerName():"Console";

	if ( pszPrefix && strlen( pszPrefix ) > 0 )
	{
		if ( pszLocation && strlen( pszLocation ) )
		{
			Q_snprintf( text, sizeof(text), "%s %s @ %s: ", pszPrefix, pszPlayerName, pszLocation );
		}
		else
		{
			Q_snprintf( text, sizeof(text), "%s %s: ", pszPrefix, pszPlayerName );
		}
	}
	else
	{
		Q_snprintf( text, sizeof(text), "%s: ", pszPlayerName );
	}

	j = sizeof(text) - 2 - strlen(text);  // -2 for /n and null terminator
	if ( (int)strlen(p) > j )
		p[j] = 0;

	Q_strncat( text, p, sizeof( text ), COPY_ALL_CHARACTERS );
	Q_strncat( text, "\n", sizeof( text ), COPY_ALL_CHARACTERS );
 
	// loop through all players
	// Start with the first player.
	// This may return the world in single player if the client types something between levels or during spawn
	// so check it, or it will infinite loop

	client = NULL;
	for ( int i = 1; i <= gpGlobals->maxClients; i++ )
	{
		client = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( i ) );
		if ( !client || !client->edict() )
			continue;
		
		if ( client->edict() == pEdict )
			continue;

		if ( !(client->IsNetClient()) )	// Not a client ? (should never be true)
			continue;

		if ( teamonly && g_pGameRules->PlayerCanHearChat( client, pPlayer ) != GR_TEAMMATE )
			continue;

		if ( pPlayer && !client->CanHearAndReadChatFrom( pPlayer ) )
			continue;

		if ( pPlayer && GetVoiceGameMgr() && GetVoiceGameMgr()->IsPlayerIgnoringPlayer( pPlayer->entindex(), i ) )
			continue;

		CSingleUserRecipientFilter user( client );
		user.MakeReliable();

		if ( pszFormat )
		{
			UTIL_SayText2Filter( user, pPlayer, true, pszFormat, pszPlayerName, p, pszLocation );
		}
		else
		{
			UTIL_SayTextFilter( user, text, pPlayer, true );
		}
	}

	if ( pPlayer )
	{
		// print to the sending client
		CSingleUserRecipientFilter user( pPlayer );
		user.MakeReliable();

		if ( pszFormat )
		{
			UTIL_SayText2Filter( user, pPlayer, true, pszFormat, pszPlayerName, p, pszLocation );
		}
		else
		{
			UTIL_SayTextFilter( user, text, pPlayer, true );
		}
	}

	// echo to server console
	// Adrian: Only do this if we're running a dedicated server since we already print to console on the client.
	if ( engine->IsDedicatedServer() )
		 Msg( "%s", text );

	Assert( p );

	int userid = 0;
	const char *networkID = "Console";
	const char *playerName = "Console";
	const char *playerTeam = "Console";
	if ( pPlayer )
	{
		userid = pPlayer->GetUserID();
		networkID = pPlayer->GetNetworkIDString();
		playerName = pPlayer->GetPlayerName();
		CTeam *team = pPlayer->GetTeam();
		if ( team )
		{
			playerTeam = team->GetName();
		}
	}
		
	if ( teamonly )
		UTIL_LogPrintf( "\"%s<%i><%s><%s>\" say_team \"%s\"\n", playerName, userid, networkID, playerTeam, p );
	else
		UTIL_LogPrintf( "\"%s<%i><%s><%s>\" say \"%s\"\n", playerName, userid, networkID, playerTeam, p );

	IGameEvent * event = gameeventmanager->CreateEvent( "player_say", true );

	if ( event )
	{
		event->SetInt("userid", userid );
		event->SetString("text", p );
		event->SetInt("priority", 1 );	// HLTV event priority, not transmitted
		gameeventmanager->FireEvent( event, true );
	}
}
//---------------------------------------------------------
// 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 );
	}
}
//------------------------------------------------------------------------------
// Purpose : 
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CNPC_CombineDropship::PrescheduleThink( void )
{
	BaseClass::PrescheduleThink();
	
	// keep track of think time deltas for burn calc below
	float dt = gpGlobals->curtime - m_flLastTime;
	m_flLastTime = gpGlobals->curtime;

	switch( m_iLandState )
	{
	case LANDING_NO:
		{
			if ( IsActivityFinished() && (GetActivity() != ACT_DROPSHIP_FLY_IDLE_EXAGG && GetActivity() != ACT_DROPSHIP_FLY_IDLE_CARGO) )
			{
				if ( m_hContainer )
				{
					SetIdealActivity( (Activity)ACT_DROPSHIP_FLY_IDLE_CARGO );
				}
				else
				{
					SetIdealActivity( (Activity)ACT_DROPSHIP_FLY_IDLE_EXAGG );
				}
			}

			DoRotorWash();
		}
		break;

	case LANDING_LEVEL_OUT:
		{
			// Approach the drop point
			Vector vecToTarget = (GetDesiredPosition() - GetAbsOrigin());
			float flDistance = vecToTarget.Length();

			// If we're slowing, make it look like we're slowing
			/*
			if ( IsActivityFinished() && GetActivity() != ACT_DROPSHIP_DESCEND_IDLE )
			{
				SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE );
			}
			*/

			// Are we there yet?
			float flSpeed = GetAbsVelocity().Length();
			if ( flDistance < 70 && flSpeed < 100 )
			{
				m_flLandingSpeed = flSpeed;
				m_iLandState = LANDING_DESCEND;
				// save off current angles so we can work them out over time
				QAngle angles = GetLocalAngles();
				m_existPitch = angles.x;
				m_existRoll = angles.z;

			}

			DoRotorWash();
		}
		break;

	case LANDING_DESCEND:
		{
			float	flAltitude;

			SetLocalAngularVelocity( vec3_angle );

			// Ensure we land on the drop point
			Vector vecToTarget = (GetDesiredPosition() - GetAbsOrigin());
			float flDistance = vecToTarget.Length();
			float flRampedSpeed = m_flLandingSpeed * (flDistance / 70);
			Vector vecVelocity = (flRampedSpeed / flDistance) * vecToTarget;
			vecVelocity.z = -75;
			SetAbsVelocity( vecVelocity );

			flAltitude = GetAltitude();			

			if ( IsActivityFinished() && GetActivity() != ACT_DROPSHIP_DESCEND_IDLE )
			{
				SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE );
			}

			if ( flAltitude < 72 )
			{
				QAngle angles = GetLocalAngles();

				// Level out quickly.
				angles.x = UTIL_Approach( 0.0, angles.x, 0.2 );
				angles.z = UTIL_Approach( 0.0, angles.z, 0.2 );

				SetLocalAngles( angles );
			}
			else
			{
				// randomly move as if buffeted by ground effects
				// gently flatten ship from starting pitch/yaw
				m_existPitch = UTIL_Approach( 0.0, m_existPitch, 1 );
				m_existRoll = UTIL_Approach( 0.0, m_existRoll, 1 );

				QAngle angles = GetLocalAngles();
				angles.x = m_existPitch + ( sin( gpGlobals->curtime * 3.5f ) * DROPSHIP_MAX_LAND_TILT );
				angles.z = m_existRoll + ( sin( gpGlobals->curtime * 3.75f ) * DROPSHIP_MAX_LAND_TILT );
				SetLocalAngles( angles );

				// figure out where to face (nav point)
				Vector targetDir = GetDesiredPosition() - GetAbsOrigin();
//				NDebugOverlay::Cross3D( m_pGoalEnt->GetAbsOrigin(), -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 20 );

				QAngle targetAngles = GetAbsAngles();
				targetAngles.y += UTIL_AngleDiff(UTIL_VecToYaw( targetDir ), targetAngles.y);
				// orient ship towards path corner on the way down
				angles = GetAbsAngles();
				angles.y = UTIL_Approach(targetAngles.y, angles.y, 2 );
				SetAbsAngles( angles );
			}

			if ( flAltitude <= 0.5f )
			{
				m_iLandState = LANDING_TOUCHDOWN;

				// upon landing, make sure ship is flat
				QAngle angles = GetLocalAngles();
				angles.x = 0;
				angles.z = 0;
				SetLocalAngles( angles );

				// TODO: Release cargo anim
				SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE );
			}

			DoRotorWash();

			// place danger sounds 1 foot above ground to get troops to scatter if they are below dropship
			Vector vecBottom = GetAbsOrigin();
			vecBottom.z += WorldAlignMins().z;
			Vector vecSpot = vecBottom + Vector(0, 0, -1) * (GetAltitude() - 12 );
			CSoundEnt::InsertSound( SOUND_DANGER, vecSpot, 400, 0.2, this, 0 );
			CSoundEnt::InsertSound( SOUND_PHYSICS_DANGER, vecSpot, 400, 0.2, this, 1 );
//			NDebugOverlay::Cross3D( vecSpot, -Vector(4,4,4), Vector(4,4,4), 255, 0, 255, false, 10.0f );

			// now check to see if player is below us, if so, cause heat damage to them (i.e. get them to move)
			trace_t tr;
			Vector vecBBoxMin = CRATE_BBOX_MIN;		// use flat box for check
			vecBBoxMin.z = -5;
			Vector vecBBoxMax = CRATE_BBOX_MAX;
			vecBBoxMax.z = 5;
			Vector pEndPoint = vecBottom + Vector(0, 0, -1) * ( GetAltitude() - 12 );
			AI_TraceHull( vecBottom, pEndPoint, vecBBoxMin, vecBBoxMax, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );

			if ( tr.fraction < 1.0f )
			{
				if ( tr.GetEntityIndex() == 1 )			// player???
				{
					CTakeDamageInfo info( this, this, 20 * dt, DMG_BURN );
					CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
					pPlayer->TakeDamage( info );
				}
			}

		}
		break;

	case LANDING_TOUCHDOWN:
		{
			if ( IsActivityFinished() && ( GetActivity() != ACT_DROPSHIP_DESCEND_IDLE ) )
			{
				SetActivity( (Activity)ACT_DROPSHIP_DESCEND_IDLE );
			}

			m_iLandState = LANDING_UNLOADING;
			m_flTroopDeployPause = gpGlobals->curtime + DROPSHIP_PAUSE_B4_TROOP_UNLOAD;
			m_flTimeTakeOff = m_flTroopDeployPause + DROPSHIP_DEPLOY_TIME;
		}
		break;

	case LANDING_UNLOADING:
		{
			// pause before dropping troops
			if ( gpGlobals->curtime > m_flTroopDeployPause )
			{
				if ( m_hContainer )	// don't drop troops if we don't have a crate any more
				{
					SpawnTroops();
					m_flTroopDeployPause = m_flTimeTakeOff + 2;	// only drop once
				}
			}
			// manage engine wash and volume
			if ( m_flTimeTakeOff - gpGlobals->curtime < 0.5f )
			{
				m_engineThrust = UTIL_Approach( 1.0f, m_engineThrust, 0.1f );
				DoRotorWash();
			}
			else
			{
				float idleVolume = 0.2f;
				m_engineThrust = UTIL_Approach( idleVolume, m_engineThrust, 0.04f );
				if ( m_engineThrust > idleVolume ) 
				{
					DoRotorWash();				// make sure we're kicking up dust/water as long as engine thrust is up
				}
			}

			if( gpGlobals->curtime > m_flTimeTakeOff )
			{
				m_iLandState = LANDING_LIFTOFF;
				SetActivity( (Activity)ACT_DROPSHIP_LIFTOFF );
				m_engineThrust = 1.0f;			// ensure max volume once we're airborne
				if ( m_bIsFiring )
				{
					StopCannon();				// kill cannon sounds if they are on
				}

				// detach container from ship
				if ( m_hContainer && m_leaveCrate )
				{
					m_hContainer->SetParent(NULL);
					m_hContainer->SetMoveType( (MoveType_t)m_iContainerMoveType );

					// If the container has a physics object, remove it's shadow
					IPhysicsObject *pPhysicsObject = m_hContainer->VPhysicsGetObject();
					if ( pPhysicsObject )
					{
						pPhysicsObject->RemoveShadowController();
					}

					m_hContainer = NULL;
				}
			}
		}
		break;

	case LANDING_LIFTOFF:
		{
			// give us some clearance before changing back to larger hull -- keeps ship from getting stuck on
			// things like the player, etc since we "pop" the hull...
			if ( GetAltitude() > 120 )		
			{
				m_OnFinishedDropoff.FireOutput( this, this );

				m_iLandState = LANDING_NO;

				// change bounding box back to normal ship hull
				Vector vecBBMin, vecBBMax;
				ExtractBbox( SelectHeaviestSequence( ACT_DROPSHIP_DEPLOY_IDLE ), vecBBMin, vecBBMax ); 
				UTIL_SetSize( this, vecBBMin, vecBBMax );
				Relink();
			}
		}
		break;

	case LANDING_SWOOPING:
		{
			// Did we lose our pickup target?
			if ( !m_hPickupTarget )
			{
				m_iLandState = LANDING_NO;
			}
			else
			{
				// Decrease altitude and speed to hit the target point.
				Vector vecToTarget = (GetDesiredPosition() - GetAbsOrigin());
				float flDistance = vecToTarget.Length();

				// Start cheating when we get near it
				if ( flDistance < 50 )
				{
					/*
					if ( flDistance > 10 )
					{
						// Cheat and ensure we touch the target
						float flSpeed = GetAbsVelocity().Length();
						Vector vecVelocity = vecToTarget;
						VectorNormalize( vecVelocity );
						SetAbsVelocity( vecVelocity * min(flSpeed,flDistance) );
					}
					else
					*/
					{
						// Grab the target
						m_hContainer = m_hPickupTarget;
						m_hPickupTarget = NULL;
						m_iContainerMoveType = m_hContainer->GetMoveType();

						// If the container has a physics object, move it to shadow
						IPhysicsObject *pPhysicsObject = m_hContainer->VPhysicsGetObject();
						if ( pPhysicsObject )
						{
							pPhysicsObject->SetShadow( Vector(1e4,1e4,1e4), AngularImpulse(1e4,1e4,1e4), false, false );
							pPhysicsObject->UpdateShadow( GetAbsOrigin(), GetAbsAngles(), false, 0 );
						}

						int iIndex = 0;//LookupAttachment("Cargo");
						/*
						Vector vecOrigin;
						QAngle vecAngles;
						GetAttachment( iIndex, vecOrigin, vecAngles );
						m_hContainer->SetAbsOrigin( vecOrigin );
						m_hContainer->SetAbsAngles( vec3_angle );
						*/
						m_hContainer->SetAbsOrigin( GetAbsOrigin() );
						m_hContainer->SetParent(this, iIndex);
						m_hContainer->SetMoveType( MOVETYPE_PUSH );
						m_hContainer->RemoveFlag( FL_ONGROUND );
						m_hContainer->Relink();
						m_hContainer->SetAbsAngles( vec3_angle );

						m_OnFinishedPickup.FireOutput( this, this );
						m_iLandState = LANDING_NO;
					}
				}
			}

			DoRotorWash();
		}
		break;
	}

	DoCombatStuff();

	if ( GetActivity() != GetIdealActivity() )
	{
		//Msg( "setactivity" );
		SetActivity( GetIdealActivity() );
	}
}
//===============================================================================
//===============================================================================
bool CInternalLight::ComputeLightPosAndOrientation( const Vector &vecPos, const Vector &vecForward, const Vector &vecRight, const Vector &vecUp, Vector& vecFinalPos, Quaternion& quatOrientation )
{
    vecFinalPos = vecPos;
    BasisToQuaternion( vecForward, vecRight, vecUp, quatOrientation );
    return true;

    const float flEpsilon = 0.1f;            // Offset flashlight position along vecUp
    float flDistCutoff = r_projectedtexture_tracedistcutoff.GetFloat();
    const float flDistDrag = 0.2;
    bool bDebugVis = r_projectedtexture_visualizetrace.GetBool();

    C_BasePlayer *pPlayer = UTIL_PlayerByIndex( m_iEntIndex );

    if ( !pPlayer ) {
        pPlayer = C_BasePlayer::GetLocalPlayer();

        if ( !pPlayer )
            return false;
    }

    // We will lock some of the flashlight params if player is on a ladder, to prevent oscillations due to the trace-rays
    bool bPlayerOnLadder = (pPlayer->GetMoveType() == MOVETYPE_LADDER);

    CTraceFilterSkipPlayerAndViewModel traceFilter( pPlayer, true );

    //    Vector vOrigin = vecPos + r_flashlightoffsety.GetFloat() * vecUp;
    Vector vecOffset;
    pPlayer->GetFlashlightOffset( vecForward, vecRight, vecUp, &vecOffset );
    Vector vOrigin = vecPos + vecOffset;

    // Not on ladder...trace a hull
    if ( !bPlayerOnLadder ) {
        Vector vecPlayerEyePos = pPlayer->GetRenderOrigin() + pPlayer->GetViewOffset();

        trace_t pmOriginTrace;
        UTIL_TraceHull( vecPlayerEyePos, vOrigin, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), (MASK_SOLID & ~(CONTENTS_HITBOX)) | CONTENTS_WINDOW | CONTENTS_GRATE, &traceFilter, &pmOriginTrace );//1

        if ( bDebugVis ) {
            debugoverlay->AddBoxOverlay( pmOriginTrace.endpos, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), QAngle( 0, 0, 0 ), 0, 255, 0, 16, 0 );

            if ( pmOriginTrace.DidHit() || pmOriginTrace.startsolid ) {
                debugoverlay->AddLineOverlay( pmOriginTrace.startpos, pmOriginTrace.endpos, 255, 128, 128, true, 0 );
            }
            else {
                debugoverlay->AddLineOverlay( pmOriginTrace.startpos, pmOriginTrace.endpos, 255, 0, 0, true, 0 );
            }
        }

        if ( pmOriginTrace.DidHit() || pmOriginTrace.startsolid ) {
            vOrigin = pmOriginTrace.endpos;
        }
        else {
            if ( pPlayer->m_vecFlashlightOrigin != vecPlayerEyePos ) {
                vOrigin = vecPos;
            }
        }
    }
    else // on ladder...skip the above hull trace
    {
        vOrigin = vecPos;
    }

    // Now do a trace along the flashlight direction to ensure there is nothing within range to pull back from
    int iMask = MASK_OPAQUE_AND_NPCS;
    iMask &= ~CONTENTS_HITBOX;
    iMask |= CONTENTS_WINDOW | CONTENTS_GRATE | CONTENTS_IGNORE_NODRAW_OPAQUE;

    Vector vTarget = vOrigin + vecForward * m_nState.m_FarZ;

    // Work with these local copies of the basis for the rest of the function
    Vector vDir = vTarget - vOrigin;
    Vector vRight = vecRight;
    Vector vUp = vecUp;
    VectorNormalize( vDir );
    VectorNormalize( vRight );
    VectorNormalize( vUp );

    // Orthonormalize the basis, since the flashlight texture projection will require this later...
    vUp -= DotProduct( vDir, vUp ) * vDir;
    VectorNormalize( vUp );
    vRight -= DotProduct( vDir, vRight ) * vDir;
    VectorNormalize( vRight );
    vRight -= DotProduct( vUp, vRight ) * vUp;
    VectorNormalize( vRight );

    AssertFloatEquals( DotProduct( vDir, vRight ), 0.0f, 1e-3 );
    AssertFloatEquals( DotProduct( vDir, vUp ), 0.0f, 1e-3 );
    AssertFloatEquals( DotProduct( vRight, vUp ), 0.0f, 1e-3 );

    trace_t pmDirectionTrace;
    UTIL_TraceHull( vOrigin, vTarget, Vector( -1.5, -1.5, -1.5 ), Vector( 1.5, 1.5, 1.5 ), iMask, &traceFilter, &pmDirectionTrace );//.5

    if ( bDebugVis ) {
        debugoverlay->AddBoxOverlay( pmDirectionTrace.endpos, Vector( -4, -4, -4 ), Vector( 4, 4, 4 ), QAngle( 0, 0, 0 ), 0, 0, 255, 16, 0 );
        debugoverlay->AddLineOverlay( vOrigin, pmDirectionTrace.endpos, 255, 0, 0, false, 0 );
    }

    float flTargetPullBackDist = 0.0f;
    float flDist = (pmDirectionTrace.endpos - vOrigin).Length();

    if ( flDist < flDistCutoff ) {
        // We have an intersection with our cutoff range
        // Determine how far to pull back, then trace to see if we are clear
        float flPullBackDist = bPlayerOnLadder ? r_projectedtexture_ladderdist.GetFloat() : flDistCutoff - flDist;    // Fixed pull-back distance if on ladder

        flTargetPullBackDist = flPullBackDist;

        if ( !bPlayerOnLadder ) {
            trace_t pmBackTrace;

            // start the trace away from the actual trace origin a bit, to avoid getting stuck on small, close "lips"
            UTIL_TraceHull( vOrigin - vDir * (flDistCutoff * r_projectedtexture_backtraceoffset.GetFloat()), vOrigin - vDir * (flPullBackDist - flEpsilon),
                            Vector( -1.5f, -1.5f, -1.5f ), Vector( 1.5f, 1.5f, 1.5f ), iMask, &traceFilter, &pmBackTrace );

            if ( bDebugVis ) {
                debugoverlay->AddLineOverlay( pmBackTrace.startpos, pmBackTrace.endpos, 255, 0, 255, true, 0 );
            }

            if ( pmBackTrace.DidHit() ) {
                // We have an intersection behind us as well, so limit our flTargetPullBackDist
                float flMaxDist = (pmBackTrace.endpos - vOrigin).Length() - flEpsilon;
                flTargetPullBackDist = MIN( flMaxDist, flTargetPullBackDist );
                //m_flCurrentPullBackDist = MIN( flMaxDist, m_flCurrentPullBackDist );    // possible pop
            }
        }
    }

    if ( bDebugVis ) {
        // visualize pullback
        debugoverlay->AddBoxOverlay( vOrigin - vDir * m_flCurrentPullBackDist, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), QAngle( 0, 0, 0 ), 255, 255, 0, 16, 0 );
        debugoverlay->AddBoxOverlay( vOrigin - vDir * flTargetPullBackDist, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), QAngle( 0, 0, 0 ), 128, 128, 0, 16, 0 );
    }

    m_flCurrentPullBackDist = Lerp( flDistDrag, m_flCurrentPullBackDist, flTargetPullBackDist );
    m_flCurrentPullBackDist = MIN( m_flCurrentPullBackDist, flDistCutoff );    // clamp to max pullback dist
    vOrigin = vOrigin - vDir * m_flCurrentPullBackDist;

    vecFinalPos = vOrigin;
    BasisToQuaternion( vDir, vRight, vUp, quatOrientation );

    return true;
}
//---------------------------------------------------------
//---------------------------------------------------------
void CAI_Relationship::ChangeRelationships( int disposition, int iReverting, CBaseEntity *pActivator, CBaseEntity *pCaller )
{
 	if( iReverting != NOT_REVERTING && m_iPreviousDisposition == -1 )
	{
		// Trying to revert without having ever set the relationships!
		DevMsg( 2, "ai_relationship cannot revert changes before they are applied!\n");
		return;
	}

	const int MAX_HANDLED = 512;
	CUtlVectorFixed<CBaseCombatCharacter *, MAX_HANDLED> subjectList;
	CUtlVectorFixed<CBaseCombatCharacter *, MAX_HANDLED> targetList;

	// Add any special subjects we found
	CBaseEntity *pSpecialSubject = FindEntityForProceduralName( m_iszSubject, pActivator, pCaller );
	if ( pSpecialSubject && pSpecialSubject->MyCombatCharacterPointer() )
	{
		subjectList.AddToTail( pSpecialSubject->MyCombatCharacterPointer() );
	}

	// Add any special targets we found
	CBaseEntity *pSpecialTarget = FindEntityForProceduralName( m_target, pActivator, pCaller );
	if ( pSpecialTarget && pSpecialTarget->MyCombatCharacterPointer() )
	{
		targetList.AddToTail( pSpecialTarget->MyCombatCharacterPointer() );
	}

	// -------------------------------
	// Search for targets and subjects
	// -------------------------------

	float radiusSq = Square( m_flRadius );
	
	// Search players first
	for ( int i = 1; i <= gpGlobals->maxClients; i++ )
	{
		if ( subjectList.Count() == MAX_HANDLED || targetList.Count() == MAX_HANDLED )
		{
			DevMsg( "Too many entities handled by ai_relationship %s\n", GetDebugName() );
			break;
		}

		CBasePlayer	*pPlayer = UTIL_PlayerByIndex( i );
		if ( pPlayer )
		{
			if( IsASubject( pPlayer ) )
			{
				if ( m_flRadius == 0.0 || GetAbsOrigin().DistToSqr( pPlayer->GetAbsOrigin() ) <= radiusSq )
					subjectList.AddToTail( pPlayer );
			}
			else if( IsATarget( pPlayer ) )
			{
				targetList.AddToTail( pPlayer );
			}
		}
	}

	// Search NPCs
	for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ )
	{
		if ( subjectList.Count() == MAX_HANDLED || targetList.Count() == MAX_HANDLED )
		{
			DevMsg( "Too many entities handled by ai_relationship %s\n", GetDebugName() );
			break;
		}

		CAI_BaseNPC *pNPC = (g_AI_Manager.AccessAIs())[i];
		if ( pNPC )
		{
			if( IsASubject( pNPC ) )
			{
				if ( m_flRadius == 0.0 || GetAbsOrigin().DistToSqr( pNPC->GetAbsOrigin() ) <= radiusSq )
					subjectList.AddToTail( pNPC );
			}
			else if( IsATarget( pNPC ) )
			{
				targetList.AddToTail( pNPC );
			}
		}
	}

	// If either list is still empty, we have a problem.
	if( subjectList.Count() == 0 )
	{
		DevMsg( 2, "ai_relationship '%s' finds no subject(s) called: %s\n", GetDebugName(), STRING( m_iszSubject ) );
		return;
	}
	else if ( targetList.Count() == 0 )
	{
		DevMsg( 2, "ai_relationship '%s' finds no target(s) called: %s\n", GetDebugName(), STRING( m_target ) );
		return;
	}

	// Ok, lists are populated. Apply all relationships.
	for ( int i = 0 ; i < subjectList.Count(); i++ )
	{
		CBaseCombatCharacter *pSubject = subjectList[ i ];

		for ( int j = 0 ; j < targetList.Count(); j++ )
		{
			CBaseCombatCharacter *pTarget = targetList[ j ];

			if ( m_iPreviousDisposition == -1 && iReverting == NOT_REVERTING )
			{
				// Set previous disposition.
				m_iPreviousDisposition = pSubject->IRelationType( pTarget );
				m_iPreviousRank = pSubject->IRelationPriority( pTarget );
			}

			if ( iReverting == REVERTING_TO_PREV )
			{
				pSubject->AddEntityRelationship( pTarget, (Disposition_t)m_iPreviousDisposition, m_iPreviousRank );

				if( m_bReciprocal )
				{
					pTarget->AddEntityRelationship( pSubject, (Disposition_t)m_iPreviousDisposition, m_iPreviousRank );
				}
			}
			else if ( iReverting == REVERTING_TO_DEFAULT )
			{
				pSubject->RemoveEntityRelationship( pTarget );

				if( m_bReciprocal )
				{
					pTarget->RemoveEntityRelationship( pSubject );
				}
			}
			else if( pSubject->IRelationType(pTarget) != disposition || 
				     pSubject->IRelationPriority(pTarget) != m_iRank || 
					 HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_SUBJECT ) ||
					 HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_TARGET ) )
			{
				// Apply the relationship to the subject
				pSubject->AddEntityRelationship( pTarget, (Disposition_t)disposition, m_iRank );

				// Make the subject aware of the target
				if ( HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_SUBJECT ) )
				{
					DiscloseNPCLocation( pSubject, pTarget );
				}

				// Make the target aware of the subject
				if ( HasSpawnFlags( SF_RELATIONSHIP_NOTIFY_TARGET ) )
				{
					DiscloseNPCLocation( pTarget, pSubject );
				}

				// This relationship is applied to target and subject alike
				if ( m_bReciprocal )
				{
					// Apply the relationship to the target
					pTarget->AddEntityRelationship( pSubject, (Disposition_t)disposition, m_iRank );
				}
			}
		}
	}
}
bool CDiscArena::CheckBattleOver( void )
{
	bool bTeamOneAlive = false;
	bool bTeamTwoAlive = false;

	// See if the battle is finished
	for ( int i = 0; i < (m_iPlayersPerTeam * 2); i++ )
	{
		if ( m_hCombatants[i] != NULL && ((CBasePlayer*)(CBaseEntity*)m_hCombatants[i])->IsAlive() )
		{
			if ( ((CBaseEntity*)m_hCombatants[i])->pev->team == 1 )
				bTeamOneAlive = true;
			else if ( ((CBaseEntity*)m_hCombatants[i])->pev->team == 2 )
				bTeamTwoAlive = true;
		}
	}

	if ( !bTeamOneAlive || !bTeamTwoAlive )
	{
		// Battle is finished.
		if (bTeamOneAlive)
		{
			m_iWinningTeam = 1;
			m_iTeamOneScore++;
		}
		else
		{
			m_iWinningTeam = 2;
			m_iTeamTwoScore++;
		}

		int iTeamInTheLead = 0;
		if ( m_iTeamOneScore > m_iTeamTwoScore )
			iTeamInTheLead = 1;
		else if ( m_iTeamOneScore < m_iTeamTwoScore )
			iTeamInTheLead = 2;

		// Send the message to the clients in the arena
		for ( int iPlayerNum = 1; iPlayerNum <= gpGlobals->maxClients; iPlayerNum++ )
		{
			CBasePlayer *pPlayer = (CBasePlayer*)UTIL_PlayerByIndex( iPlayerNum );

			if (pPlayer && (pPlayer->pev->groupinfo & pev->groupinfo) && (pPlayer->m_bHasDisconnected != TRUE) )
			{
				MESSAGE_BEGIN( MSG_ONE, gmsgEndRnd, NULL, pPlayer->edict() );
					WRITE_BYTE( m_iCurrRound );
					WRITE_BYTE( 1 );
					WRITE_BYTE( m_iPlayersPerTeam );

					// Send down the winners of this round
					for (i = 0; i < (m_iPlayersPerTeam * 2); i++)
					{
						CBasePlayer *pPlayer = (CBasePlayer*)(CBaseEntity*)m_hCombatants[i];
						if ( !pPlayer || pPlayer->pev->team != m_iWinningTeam )
							continue;

						WRITE_SHORT( pPlayer->entindex() );
					}

					// Send down the team who's winning the battle now
					if ( iTeamInTheLead == 0 )
					{
						// It's a draw at the moment.
						// No need to send down player data.
						WRITE_BYTE( 0 );
					}
					else
					{
						WRITE_BYTE( m_iPlayersPerTeam );
						// Send down the winners of this round
						for (i = 0; i < (m_iPlayersPerTeam * 2); i++)
						{
							CBasePlayer *pPlayer = (CBasePlayer*)(CBaseEntity*)m_hCombatants[i];
							if ( !pPlayer || pPlayer->pev->team != iTeamInTheLead )
								continue;

							WRITE_SHORT( ((CBaseEntity*)m_hCombatants[i])->entindex() );
						}
					}

					// Send down the scores
					if ( iTeamInTheLead == 1 )
					{
						WRITE_BYTE( m_iTeamOneScore );
						WRITE_BYTE( m_iTeamTwoScore );
					}
					else
					{
						WRITE_BYTE( m_iTeamTwoScore );
						WRITE_BYTE( m_iTeamOneScore );
					}

					// Send down over or not
					if ( m_iTeamOneScore == m_iMaxRounds || m_iTeamTwoScore == m_iMaxRounds )
						WRITE_BYTE( 1 );
					else
						WRITE_BYTE( 0 );

				MESSAGE_END();
			}
		}

		BattleOver();
		return true;
	}

	return false;
}
Exemple #8
0
void UpdateClientEffects(CBasePlayer *pObserver, int oldMode)
{
	bool clearProgress = false;
	bool clearBlindness = false;
	bool blindnessOk = (fadetoblack.value == 0);
	bool clearNightvision = false;

	if (pObserver->IsObserver() == OBS_IN_EYE)
	{
		clearProgress = true;
		clearBlindness = true;
		clearNightvision = true;

		if (pObserver->m_hObserverTarget->IsPlayer())
		{
			CBasePlayer *pPlayer = UTIL_PlayerByIndex(pObserver->m_hObserverTarget->entindex());

			if (pPlayer)
			{
				if (pPlayer->m_progressStart && pPlayer->m_progressEnd > pPlayer->m_progressStart)
				{
					if (pPlayer->m_progressEnd > gpGlobals->time)
					{
						float percentRemaining = gpGlobals->time - pPlayer->m_progressStart;
						pObserver->SetProgressBarTime2(int(pPlayer->m_progressEnd - pPlayer->m_progressStart), percentRemaining);
						clearProgress = false;
					}
				}

				if (blindnessOk && pPlayer->m_blindStartTime && pPlayer->m_blindFadeTime)
				{
					float fadeTime, holdTime, alpha, ratio;
					float endTime = pPlayer->m_blindFadeTime + pPlayer->m_blindHoldTime + pPlayer->m_blindStartTime;

					if (endTime > gpGlobals->time)
					{
						clearBlindness = false;

						fadeTime = pPlayer->m_blindFadeTime;
						alpha = float(pPlayer->m_blindAlpha);
						holdTime = pPlayer->m_blindHoldTime + pPlayer->m_blindStartTime - gpGlobals->time;

						if (holdTime <= 0)
						{
							holdTime = 0;
							ratio = (endTime - gpGlobals->time) / fadeTime;
							alpha = pPlayer->m_blindAlpha * ratio;
							fadeTime = ratio * fadeTime;
						}

						UTIL_ScreenFade(pObserver, Vector(255, 255, 255), fadeTime, holdTime, alpha);
					}
				}

				clearNightvision = false;

				if (pPlayer->m_bNightVisionOn != pObserver->m_bNightVisionOn)
				{
					MESSAGE_BEGIN(MSG_ONE, gmsgNVGToggle, NULL, pObserver->pev);
						WRITE_BYTE(pPlayer->m_bNightVisionOn ? STATUS_NIGHTVISION_ON : STATUS_NIGHTVISION_OFF);
					MESSAGE_END();

					pObserver->m_bNightVisionOn = pPlayer->m_bNightVisionOn;
				}
			}
		}
	}
	else if (oldMode == OBS_IN_EYE)
	{
		clearProgress = true;
		clearBlindness = true;
		clearNightvision = true;
	}

	if (clearProgress)
		pObserver->SetProgressBarTime(0);

	if (blindnessOk && clearBlindness)
		UTIL_ScreenFade(pObserver, Vector(0, 0, 0), 0.001);

	if (clearNightvision)
	{
		MESSAGE_BEGIN(MSG_ONE, gmsgNVGToggle, NULL, pObserver->pev);
			WRITE_BYTE(STATUS_NIGHTVISION_OFF);
		MESSAGE_END();

		pObserver->m_bNightVisionOn = false;
	}
}
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input  : pTarget - 
//-----------------------------------------------------------------------------
CEntityDissolve *CEntityDissolve::Create( CBaseEntity *pTarget, const char *pMaterialName, 
	float flStartTime, int nDissolveType, bool *pRagdollCreated )
{
	if ( pRagdollCreated )
	{
		*pRagdollCreated = false;
	}

	if ( !pMaterialName )
	{
		pMaterialName = DISSOLVE_SPRITE_NAME;
	}

	if ( pTarget->IsPlayer() )
	{
		// Simply immediately kill the player.
		CBasePlayer *pPlayer = assert_cast< CBasePlayer* >( pTarget );
		pPlayer->SetArmorValue( 0 );
		CTakeDamageInfo info( pPlayer, pPlayer, pPlayer->GetHealth(), DMG_GENERIC | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
		pPlayer->TakeDamage( info );
		return NULL;
	}

	CEntityDissolve *pDissolve = (CEntityDissolve *) CreateEntityByName( "env_entity_dissolver" );

	if ( pDissolve == NULL )
		return NULL;

	pDissolve->m_nDissolveType = nDissolveType;
	if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
	{
		if ( pTarget->IsNPC() && pTarget->MyNPCPointer()->CanBecomeRagdoll() )
		{
			CTakeDamageInfo info;
			CBaseEntity *pRagdoll = CreateServerRagdoll( pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_DEBRIS, true );
			pRagdoll->SetCollisionBounds( pTarget->CollisionProp()->OBBMins(), pTarget->CollisionProp()->OBBMaxs() );

			// Necessary to cause it to do the appropriate death cleanup
			if ( pTarget->m_lifeState == LIFE_ALIVE )
			{
				CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
				CTakeDamageInfo ragdollInfo( pPlayer, pPlayer, 10000.0, DMG_SHOCK | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
				pTarget->TakeDamage( ragdollInfo );
			}

			if ( pRagdollCreated )
			{
				*pRagdollCreated = true;
			}

			UTIL_Remove( pTarget );
			pTarget = pRagdoll;
		}
	}

	pDissolve->SetModelName( AllocPooledString(pMaterialName) );
	pDissolve->AttachToEntity( pTarget );
	pDissolve->SetStartTime( flStartTime );
	pDissolve->Spawn();

	// Send to the client even though we don't have a model
	pDissolve->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );

	// Play any appropriate noises when we start to dissolve
	if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
	{
		pTarget->DispatchResponse( "TLK_ELECTROCUTESCREAM" );
	}
	else
	{
		pTarget->DispatchResponse( "TLK_DISSOLVESCREAM" );
	}
	return pDissolve;
}
Exemple #10
0
// Find the next client in the game for this player to spectate
void CBasePlayer::Observer_FindNextPlayer(bool bReverse, const char *name)
{
	int iStart;
	int iCurrent;
	int iDir;
	bool bForceSameTeam;

	if (m_flNextFollowTime && m_flNextFollowTime > gpGlobals->time)
		return;

	m_flNextFollowTime = gpGlobals->time + 0.25f;

	iStart = m_hObserverTarget ? ENTINDEX(m_hObserverTarget->edict()) : ENTINDEX(edict());
	iCurrent = iStart;

	m_hObserverTarget = NULL;

	iDir = bReverse ? -1 : 1;

	bForceSameTeam = (GetForceCamera(this) != CAMERA_MODE_SPEC_ANYONE && m_iTeam != SPECTATOR);

	do
	{
		iCurrent += iDir;

		// Loop through the clients
		if (iCurrent > gpGlobals->maxClients)
			iCurrent = 1;

		else if (iCurrent < 1)
			iCurrent = gpGlobals->maxClients;

		m_hObserverTarget = Observer_IsValidTarget(iCurrent, bForceSameTeam);

		if (m_hObserverTarget)
		{
			if (!name)
				break;

			CBasePlayer *pPlayer = UTIL_PlayerByIndex(m_hObserverTarget->entindex());
			if (!Q_strcmp(name, STRING(pPlayer->pev->netname)))
				break;
		}
	}
	while (iCurrent != iStart);

	// Did we find a target?
	if (m_hObserverTarget)
	{
		// Move to the target
		UTIL_SetOrigin(pev, m_hObserverTarget->pev->origin);

		if (m_hObserverTarget->pev->health < 0.0f)
			m_hObserverTarget->pev->health = 0.0f;

		MESSAGE_BEGIN(MSG_ONE, gmsgSpecHealth2, NULL, pev);
			WRITE_BYTE(int(m_hObserverTarget->pev->health));
			WRITE_BYTE(ENTINDEX(m_hObserverTarget->edict()));
		MESSAGE_END();

		// Store the target in pev so the physics DLL can get to it
		if (pev->iuser1 != OBS_ROAMING)
			pev->iuser2 = ENTINDEX(m_hObserverTarget->edict());

		UpdateClientEffects(this, pev->iuser1);
	}
}
Exemple #11
0
void CBasePlayer::Observer_CheckProperties()
{
	// try to find a traget if we have no current one
	if (pev->iuser1 == OBS_IN_EYE && m_hObserverTarget != NULL)
	{
		CBasePlayer *target = UTIL_PlayerByIndex(m_hObserverTarget->entindex());

		if (!target)
			return;

		int weapon = target->m_pActiveItem ? target->m_pActiveItem->m_iId : 0;
		int targetBombState = STATUSICON_HIDE;

		// use fov of tracked client
		if (m_iFOV != target->m_iFOV || m_iObserverWeapon != weapon)
		{
			m_iClientFOV = m_iFOV = target->m_iFOV;

			// write fov before wepon data, so zoomed crosshair is set correctly
			MESSAGE_BEGIN(MSG_ONE, gmsgSetFOV, NULL, pev);
				WRITE_BYTE(m_iFOV);
			MESSAGE_END();

			m_iObserverWeapon = weapon;

			//send weapon update
			MESSAGE_BEGIN(MSG_ONE, gmsgCurWeapon, NULL, pev);
				WRITE_BYTE(1);	// 1 = current weapon, not on target
				WRITE_BYTE(m_iObserverWeapon);
				WRITE_BYTE(0);	// clip
			MESSAGE_END();
		}

		if (target->m_bHasC4)
		{
			if (target->m_signals.GetState() & SIGNAL_BOMB)
				targetBombState = STATUSICON_FLASH;
			else
				targetBombState = STATUSICON_SHOW;
		}

		if (m_iObserverC4State != targetBombState)
		{
			m_iObserverC4State = targetBombState;

			if (targetBombState)
			{
				MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, NULL, pev);
					WRITE_BYTE(m_iObserverC4State);
					WRITE_STRING("c4");
					WRITE_BYTE(0);
					WRITE_BYTE(160);
					WRITE_BYTE(0);
				MESSAGE_END();
			}
			else
			{
				MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, NULL, pev);
					WRITE_BYTE(STATUSICON_HIDE);
					WRITE_STRING("c4");
				MESSAGE_END();
			}
		}

		if (m_bObserverHasDefuser != target->m_bHasDefuser)
		{
			m_bObserverHasDefuser = target->m_bHasDefuser;

			if (target->m_bHasDefuser)
			{
				MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, NULL, pev);
					WRITE_BYTE(STATUSICON_SHOW);
					WRITE_STRING("defuser");
					WRITE_BYTE(0);
					WRITE_BYTE(160);
					WRITE_BYTE(0);
				MESSAGE_END();
			}
			else
			{
				MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, NULL, pev);
					WRITE_BYTE(STATUSICON_HIDE);
					WRITE_STRING("defuser");
				MESSAGE_END();
			}
		}
	}
	else
	{
		m_iFOV = DEFAULT_FOV;

		if (m_iObserverWeapon)
		{
			m_iObserverWeapon = 0;

			MESSAGE_BEGIN(MSG_ONE, gmsgCurWeapon, NULL, pev);
				WRITE_BYTE(1);	// 1 = current weapon
				WRITE_BYTE(m_iObserverWeapon);
				WRITE_BYTE(0);	// clip
			MESSAGE_END();
		}

		if (m_iObserverC4State)
		{
			m_iObserverC4State = 0;

			MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, NULL, pev);
				WRITE_BYTE(0);
				WRITE_STRING("c4");
			MESSAGE_END();
		}

		if (m_bObserverHasDefuser)
		{
			m_bObserverHasDefuser = false;

			MESSAGE_BEGIN(MSG_ONE, gmsgStatusIcon, NULL, pev);
				WRITE_BYTE(0);
				WRITE_STRING("defuser");
			MESSAGE_END();
		}
	}
}
Exemple #12
0
int CAI_Senses::LookForHighPriorityEntities( int iDistance )
{
	int nSeen = 0;
	if ( gpGlobals->curtime - m_TimeLastLookHighPriority > AI_HIGH_PRIORITY_SEARCH_TIME )
	{
		AI_PROFILE_SENSES(CAI_Senses_LookForHighPriorityEntities);
		m_TimeLastLookHighPriority = gpGlobals->curtime;
		
		BeginGather();
	
		float distSq = ( iDistance * iDistance );
		const Vector &origin = GetAbsOrigin();
		
		// Players
CNPC_BaseZombie *pZombie = dynamic_cast<CNPC_BaseZombie*>( GetOuter() );

		if ( pZombie )
		{
			for ( int i = 1; i <= gpGlobals->maxClients; i++ )
			{
				CBaseEntity *pPlayer = UTIL_PlayerByIndex( i );

				if ( pPlayer )
				{
					if ( Look( pPlayer ) ) //Look
					{
						nSeen++;
					}
				}
			}
		}
		else
		{
			for ( int i = 1; i <= gpGlobals->maxClients; i++ )
			{
				CBaseEntity *pPlayer = UTIL_PlayerByIndex( i );

				if ( pPlayer )
				{
					if ( origin.DistToSqr(pPlayer->GetAbsOrigin()) < distSq && Look( pPlayer ) )
					{
						nSeen++;
					}
#ifdef PORTAL
				else
				{
					CProp_Portal *pPortal = GetOuter()->FInViewConeThroughPortal( pPlayer );
					if ( pPortal && UTIL_Portal_DistanceThroughPortalSqr( pPortal, origin, pPlayer->GetAbsOrigin() ) < distSq && LookThroughPortal( pPortal, pPlayer ) )
					{
						nSeen++;
					}
				}
#endif
				}
			}
		}
	
		EndGather( nSeen, &m_SeenHighPriority );
    }
    else
    {
    	for ( int i = m_SeenHighPriority.Count() - 1; i >= 0; --i )
    	{
    		if ( m_SeenHighPriority[i].Get() == NULL )
    			m_SeenHighPriority.FastRemove( i );    			
    	}
    	nSeen = m_SeenHighPriority.Count();
    }
	
	return nSeen;
}
Exemple #13
0
// This runs on both the client and the server.
// On the server, it only does the damage calculations.
// On the client, it does all the effects.
void FX_FireBullets( 
	int	iPlayerIndex,
	const Vector &vOrigin,
	const QAngle &vAngles,
	const CSDK_WeaponInfo *pWeaponInfo,
	int	iMode,
	int iSeed,
	float flSpread
	)
{
	bool bDoEffects = true;

#ifdef CLIENT_DLL
	C_SDK_Player *pPlayer = ToSDK_Player( ClientEntityList().GetBaseEntity( iPlayerIndex ) );
#else
	CSDK_Player *pPlayer = ToSDK_Player( UTIL_PlayerByIndex( iPlayerIndex) );
#endif

	iSeed++;

	int		iDamage = pWeaponInfo->m_iDamage;
	int		iAmmoType = pWeaponInfo->iAmmoType;

	WeaponSound_t sound_type = SINGLE;

	if ( bDoEffects)
	{
		FX_WeaponSound( iPlayerIndex, sound_type, vOrigin, pWeaponInfo );
	}


	// Fire bullets, calculate impacts & effects

	if ( !pPlayer )
		return;
	
	StartGroupingSounds();

#if !defined (CLIENT_DLL)
	// Move other players back to history positions based on local player's lag
	//lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
#endif

	for ( int iBullet=0; iBullet < pWeaponInfo->m_iBullets; iBullet++ )
	{
		RandomSeed( iSeed );	// init random system with this seed

		// Get circular gaussian spread.
		float x, y;
		x = RandomFloat( -0.5, 0.5 ) + RandomFloat( -0.5, 0.5 );
		y = RandomFloat( -0.5, 0.5 ) + RandomFloat( -0.5, 0.5 );
	
		iSeed++; // use new seed for next bullet

		pPlayer->FireBullet(
			vOrigin,
			vAngles,
			flSpread,
			iDamage,
			iAmmoType,
			pPlayer,
			bDoEffects,
			x,y );
	}

#if !defined (CLIENT_DLL)
	//lagcompensation->FinishLagCompensation( pPlayer );
#endif

	EndGroupingSounds();
}
//-----------------------------------------------------------------------------
// Creates the explosion effect
//-----------------------------------------------------------------------------
void CEnvHeadcrabCanister::Detonate( )
{
	// Send the impact output
	m_OnImpacted.FireOutput( this, this, 0 );

	if ( !HasSpawnFlags( SF_NO_IMPACT_SOUND ) )
	{
		StopSound( "HeadcrabCanister.IncomingSound" );
		EmitSound( "HeadcrabCanister.Explosion" );
	}

	// If we're supposed to be removed, do that now
	if ( HasSpawnFlags( SF_REMOVE_ON_IMPACT ) )
	{
		SetAbsOrigin( m_vecImpactPosition );
		SetModel( ENV_HEADCRABCANISTER_BROKEN_MODEL );
		SetMoveType( MOVETYPE_NONE );
		AddEffects( EF_NOINTERP );
		m_bLanded = true;
		
		// Become invisible so our trail can finish up
		AddEffects( EF_NODRAW );
		SetSolidFlags( FSOLID_NOT_SOLID );

		SetThink( &CEnvHeadcrabCanister::SUB_Remove );
		SetNextThink( gpGlobals->curtime + ENV_HEADCRABCANISTER_TRAIL_TIME );

		return;
	}

	// Test for damaging things
	TestForCollisionsAgainstWorld( m_vecImpactPosition );

	// Shake the screen unless flagged otherwise
	if ( !HasSpawnFlags( SF_NO_SHAKE ) )
	{
		CPlayer *pPlayer = UTIL_PlayerByIndex( 1 );

		// If the player is on foot, then do a more limited shake
		float shakeRadius = ( pPlayer && pPlayer->IsInAVehicle() ) ? sk_env_headcrabcanister_shake_radius_vehicle.GetFloat() : sk_env_headcrabcanister_shake_radius.GetFloat();

		UTIL_ScreenShake( m_vecImpactPosition, sk_env_headcrabcanister_shake_amplitude.GetFloat(), 150.0, 1.0, shakeRadius, SHAKE_START );
	}

	// Do explosion effects
	if ( !HasSpawnFlags( SF_NO_IMPACT_EFFECTS ) )
	{
		// Normal explosion
		ExplosionCreate( m_vecImpactPosition, GetAbsAngles(), BaseEntity(), 50, 500, 
			SF_ENVEXPLOSION_NODLIGHTS | SF_ENVEXPLOSION_NOSPARKS | SF_ENVEXPLOSION_NODAMAGE | SF_ENVEXPLOSION_NOSOUND, 1300.0f );
			
		// Dust explosion
		//CE_TODO
		/*AR2Explosion *pExplosion = AR2Explosion::CreateAR2Explosion( m_vecImpactPosition );
		
		if( pExplosion )
		{
			pExplosion->SetLifetime(10);
		}*/
	}
}
//=========================================================
//=========================================================
void CHalfLifeMultiplay :: Think ( void )
{
	g_VoiceGameMgr.Update(gpGlobals->frametime);

	///// Check game rules /////
	static int last_frags;
	static int last_time;

	int frags_remaining = 0;
	int time_remaining = 0;

	if ( g_fGameOver )   // someone else quit the game already
	{
		// bounds check
		int time = (int)CVAR_GET_FLOAT( "mp_chattime" );
		if ( time < 1 )
			CVAR_SET_STRING( "mp_chattime", "1" );
		else if ( time > MAX_INTERMISSION_TIME )
			CVAR_SET_STRING( "mp_chattime", UTIL_dtos1( MAX_INTERMISSION_TIME ) );

		m_flIntermissionEndTime = g_flIntermissionStartTime + mp_chattime.value;

		// check to see if we should change levels now
		if ( m_flIntermissionEndTime < gpGlobals->time )
		{
			if ( m_iEndIntermissionButtonHit  // check that someone has pressed a key, or the max intermission time is over
				|| ( ( g_flIntermissionStartTime + MAX_INTERMISSION_TIME ) < gpGlobals->time) ) 
				ChangeLevel(); // intermission is over
		}

		return;
	}

	float flTimeLimit = timelimit.value * 60;
	float flFragLimit = fraglimit.value;

	time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0);
	
	if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit )
	{
		GoToIntermission();
		return;
	}

	if ( flFragLimit )
	{
		int bestfrags = 9999;
		int remain;

		// check if any player is over the frag limit
		for ( int i = 1; i <= gpGlobals->maxClients; i++ )
		{
			CBaseEntity *pPlayer = UTIL_PlayerByIndex( i );

			if ( pPlayer && pPlayer->pev->frags >= flFragLimit )
			{
				GoToIntermission();
				return;
			}


			if ( pPlayer )
			{
				remain = flFragLimit - pPlayer->pev->frags;
				if ( remain < bestfrags )
				{
					bestfrags = remain;
				}
			}

		}
		frags_remaining = bestfrags;
	}

	// Updates when frags change
	if ( frags_remaining != last_frags )
	{
		g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) );
	}

	// Updates once per second
	if ( timeleft.value != last_time )
	{
		g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) );
	}

	last_frags = frags_remaining;
	last_time  = time_remaining;
}
//-----------------------------------------------------------------------------
// Purpose: Sets the new owner of the point, plays the appropriate sound and shows the right model
//-----------------------------------------------------------------------------
void CTeamControlPoint::InternalSetOwner( int iCapTeam, bool bMakeSound, int iNumCappers, int *pCappingPlayers )
{
	Assert( iCapTeam >= 0 && iCapTeam < GetNumberOfTeams() );

	int iOldTeam = m_iTeam;

	m_iTeam = iCapTeam;
	ChangeTeam( iCapTeam );

	if ( bMakeSound )
	{
		CBroadcastRecipientFilter filter;
		EmitSound( filter, entindex(), STRING( m_TeamData[m_iTeam].iszCapSound ) );
	}

	// Update visuals
	SetModel( STRING(m_TeamData[m_iTeam].iszModel) );
	SetBodygroup( 0, m_iTeam );
	m_nSkin = ( m_iTeam == TEAM_UNASSIGNED ) ? 2 : (m_iTeam - 2);
	ResetSequence( LookupSequence("idle") );

	// We add 1 to the index because we consider the default "no points capped" as 0.
	TeamplayGameRules()->SetLastCapPointChanged( m_iPointIndex+1 );

	// Determine the pose parameters for each team
	for ( int i = 0; i < m_TeamData.Count(); i++ )
	{
		// Skip spectator
		if ( i == TEAM_SPECTATOR )
			continue;

		if ( GetModelPtr() && GetModelPtr()->SequencesAvailable() )
		{
			m_TeamData[i].iTeamPoseParam = LookupPoseParameter( UTIL_VarArgs( "cappoint_%d_percentage", i ) );
		}
		else
		{
			m_TeamData[i].iTeamPoseParam = -1;
		}
	}
	UpdateCapPercentage();

	if ( m_iTeam == TEAM_UNASSIGNED )
	{
		m_OnCapReset.FireOutput( this, this );
	}
	else
	{
		// Remap team to get first game team = 1
		switch ( m_iTeam - FIRST_GAME_TEAM+1 )
		{
		case 1: 
			m_OnCapTeam1.FireOutput( this, this );
			break;
		case 2: 
			m_OnCapTeam2.FireOutput( this, this );
			break;
		default:
			Assert(0);
			break;
		}
	}

	// If we're playing a sound, this is a true cap by players.
	if ( bMakeSound )	
	{
		if ( iOldTeam > LAST_SHARED_TEAM && iOldTeam != m_iTeam )
		{
			// Make the members of our old team say something
			for ( int i = 1; i <= gpGlobals->maxClients; i++ )
			{
				CBaseMultiplayerPlayer *pPlayer = ToBaseMultiplayerPlayer( UTIL_PlayerByIndex( i ) );
				if ( !pPlayer )
					continue;
				if ( pPlayer->GetTeamNumber() == iOldTeam )
				{
					pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_LOST_CONTROL_POINT );
				}
			}
		}

		for( int i = 0; i < iNumCappers; i++ )
		{
			int playerIndex = pCappingPlayers[i];

			Assert( playerIndex > 0 && playerIndex <= gpGlobals->maxClients );

			PlayerCapped( ToBaseMultiplayerPlayer(UTIL_PlayerByIndex( playerIndex )) );
		}

		// Remap team to get first game team = 1
		switch ( m_iTeam - FIRST_GAME_TEAM+1 )
		{
		case 1: 
			m_OnOwnerChangedToTeam1.FireOutput( this, this );
			break;
		case 2: 
			m_OnOwnerChangedToTeam2.FireOutput( this, this );
			break;
		}

		if ( m_iTeam != TEAM_UNASSIGNED && iNumCappers )
		{
			SendCapString( m_iTeam, iNumCappers, pCappingPlayers );
		}
	}

	// Have control point master check the win conditions now!
	CBaseEntity *pEnt =	gEntList.FindEntityByClassname( NULL, GetControlPointMasterName() );

	while( pEnt )
	{
		CTeamControlPointMaster *pMaster = dynamic_cast<CTeamControlPointMaster *>( pEnt );

		if ( pMaster->IsActive() )
		{
			pMaster->CheckWinConditions();
		}

		pEnt = gEntList.FindEntityByClassname( pEnt, GetControlPointMasterName() );
	}
}
void CHalfLifeMultiplay :: InitHUD( CBasePlayer *pl )
{
	// notify other clients of player joining the game
	UTIL_ClientPrintAll( HUD_PRINTNOTIFY, UTIL_VarArgs( "%s has joined the game\n", 
		( pl->pev->netname && STRING(pl->pev->netname)[0] != 0 ) ? STRING(pl->pev->netname) : "unconnected" ) );

	// team match?
	if ( g_teamplay )
	{
		UTIL_LogPrintf( "\"%s<%i><%s><%s>\" entered the game\n",  
			STRING( pl->pev->netname ), 
			GETPLAYERUSERID( pl->edict() ),
			GETPLAYERAUTHID( pl->edict() ),
			g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( pl->edict() ), "model" ) );
	}
	else
	{
		UTIL_LogPrintf( "\"%s<%i><%s><%i>\" entered the game\n",  
			STRING( pl->pev->netname ), 
			GETPLAYERUSERID( pl->edict() ),
			GETPLAYERAUTHID( pl->edict() ),
			GETPLAYERUSERID( pl->edict() ) );
	}

	UpdateGameMode( pl );

	// sending just one score makes the hud scoreboard active;  otherwise
	// it is just disabled for single play
	MESSAGE_BEGIN( MSG_ONE, gmsgScoreInfo, NULL, pl->edict() );
		WRITE_BYTE( ENTINDEX(pl->edict()) );
		WRITE_SHORT( 0 );
		WRITE_SHORT( 0 );
		WRITE_SHORT( 0 );
		WRITE_SHORT( 0 );
	MESSAGE_END();

	SendMOTDToClient( pl->edict() );

	// loop through all active players and send their score info to the new client
	for ( int i = 1; i <= gpGlobals->maxClients; i++ )
	{
		// FIXME:  Probably don't need to cast this just to read m_iDeaths
		CBasePlayer *plr = (CBasePlayer *)UTIL_PlayerByIndex( i );

		if ( plr )
		{
			MESSAGE_BEGIN( MSG_ONE, gmsgScoreInfo, NULL, pl->edict() );
				WRITE_BYTE( i );	// client number
				WRITE_SHORT( plr->pev->frags );
				WRITE_SHORT( plr->m_iDeaths );
				WRITE_SHORT( 0 );
				WRITE_SHORT( GetTeamIndex( plr->m_szTeamName ) + 1 );
			MESSAGE_END();
		}
	}

	if ( g_fGameOver )
	{
		MESSAGE_BEGIN( MSG_ONE, SVC_INTERMISSION, NULL, pl->edict() );
		MESSAGE_END();
	}
}
	void EmitCloseCaption( IRecipientFilter& filter, int entindex, bool fromplayer, char const *token, CUtlVector< Vector >& originlist, float duration, bool warnifmissing /*= false*/ )
	{
		// No close captions in multiplayer...
		if ( gpGlobals->maxClients > 1 || (gpGlobals->maxClients==1 && !g_pClosecaption->GetBool()))
		{
			return;
		}

		// A negative duration means fill it in from the wav file if possible
		if ( duration < 0.0f )
		{
			char const *wav = soundemitterbase->GetWavFileForSound( token, GENDER_NONE );
			if ( wav )
			{
				duration = enginesound->GetSoundDuration( wav );
			}
			else
			{
				duration = 2.0f;
			}
		}

		char lowercase[ 256 ];
		Q_strncpy( lowercase, token, sizeof( lowercase ) );
		Q_strlower( lowercase );
		if ( Q_strstr( lowercase, "\\" ) )
		{
			Hack_FixEscapeChars( lowercase );
		}

		// NOTE:  We must make a copy or else if the filter is owned by a SoundPatch, we'll end up destructively removing
		//  all players from it!!!!
		CRecipientFilter filterCopy;
		filterCopy.CopyFrom( (CRecipientFilter &)filter );

		// Remove any players who don't want close captions
		CBaseEntity::RemoveRecipientsIfNotCloseCaptioning( (CRecipientFilter &)filterCopy );

#if !defined( CLIENT_DLL )
		{
			// Defined in sceneentity.cpp
			bool AttenuateCaption( const char *token, const Vector& listener, CUtlVector< Vector >& soundorigins );

			if ( filterCopy.GetRecipientCount() > 0 )
			{
				int c = filterCopy.GetRecipientCount();
				for ( int i = c - 1 ; i >= 0; --i )
				{
					CBasePlayer *player = UTIL_PlayerByIndex( filterCopy.GetRecipientIndex( i ) );
					if ( !player )
						continue;

					Vector playerOrigin = player->GetAbsOrigin();

					if ( AttenuateCaption( lowercase, playerOrigin, originlist ) )
					{
						filterCopy.RemoveRecipient( player );
					}
				}
			}
		}
#endif
		// Anyone left?
		if ( filterCopy.GetRecipientCount() > 0 )
		{

#if !defined( CLIENT_DLL )

			byte byteflags = 0;
			if ( warnifmissing )
			{
				byteflags |= CLOSE_CAPTION_WARNIFMISSING;
			}
			if ( fromplayer )
			{
				byteflags |= CLOSE_CAPTION_FROMPLAYER;
			}

			CBaseEntity *pActor = CBaseEntity::Instance( entindex );
			if ( pActor )
			{
				char const *pszActorModel = STRING( pActor->GetModelName() );
				gender_t gender = soundemitterbase->GetActorGender( pszActorModel );

				if ( gender == GENDER_MALE )
				{
					byteflags |= CLOSE_CAPTION_GENDER_MALE;
				}
				else if ( gender == GENDER_FEMALE )
				{ 
					byteflags |= CLOSE_CAPTION_GENDER_FEMALE;
				}
			}

			// Send caption and duration hint down to client
			UserMessageBegin( filterCopy, "CloseCaption" );
				WRITE_STRING( lowercase );
				WRITE_SHORT( MIN( 255, (int)( duration * 10.0f ) ) ),
				WRITE_BYTE( byteflags ),
			MessageEnd();
#else
			// Direct dispatch
			CHudCloseCaption *cchud = GET_HUDELEMENT( CHudCloseCaption );
			if ( cchud )
			{
				cchud->ProcessCaption( lowercase, duration, fromplayer );
			}
#endif
		}
	}
//=========================================================
//=========================================================
void CTeamplayRules::RecountTeams( void )
{
	char	*pName;
	char	teamlist[TEAMPLAY_TEAMLISTLENGTH];

	// loop through all teams, recounting everything
	num_teams = 0;

	// Copy all of the teams from the teamlist
	// make a copy because strtok is destructive
	Q_strncpy( teamlist, m_szTeamList, sizeof(teamlist) );
	pName = teamlist;
	pName = strtok( pName, ";" );
	while ( pName != NULL && *pName )
	{
		if ( GetTeamIndex( pName ) < 0 )
		{
			Q_strncpy( team_names[num_teams], pName, sizeof(team_names[num_teams]));
			num_teams++;
		}
		pName = strtok( NULL, ";" );
	}

	if ( num_teams < 2 )
	{
		num_teams = 0;
		m_teamLimit = false;
	}

	// Sanity check
	memset( team_scores, 0, sizeof(team_scores) );

	// loop through all clients
	for ( int i = 1; i <= gpGlobals->maxClients; i++ )
	{
		CBasePlayer *plr = UTIL_PlayerByIndex( i );

		if ( plr )
		{
			const char *pTeamName = plr->TeamID();
			// try add to existing team
			int tm = GetTeamIndex( pTeamName );
			
			if ( tm < 0 ) // no team match found
			{ 
				if ( !m_teamLimit )
				{
					// add to new team
					tm = num_teams;
					num_teams++;
					team_scores[tm] = 0;
					Q_strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH );
				}
			}

			if ( tm >= 0 )
			{
				team_scores[tm] += plr->FragCount();
			}
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether or not it is OK to make an NPC at this instant.
//-----------------------------------------------------------------------------
bool CBaseNPCMaker::CanMakeNPC( bool bIgnoreSolidEntities )
{
	if( ai_inhibit_spawners.GetBool() )
		return false;

	if ( m_nMaxLiveChildren > 0 && m_nLiveChildren >= m_nMaxLiveChildren )
	{// not allowed to make a new one yet. Too many live ones out right now.
		return false;
	}

	if ( m_iszIngoreEnt != NULL_STRING )
	{
		m_hIgnoreEntity = gEntList.FindEntityByName( NULL, m_iszIngoreEnt );
	}

	Vector mins = GetAbsOrigin() - Vector( 34, 34, 0 );
	Vector maxs = GetAbsOrigin() + Vector( 34, 34, 0 );
	maxs.z = GetAbsOrigin().z;
	
	// If we care about not hitting solid entities, look for 'em
	if ( !bIgnoreSolidEntities )
	{
		CBaseEntity *pList[128];

		int count = UTIL_EntitiesInBox( pList, 128, mins, maxs, FL_CLIENT|FL_NPC );
		if ( count )
		{
			//Iterate through the list and check the results
			for ( int i = 0; i < count; i++ )
			{
				//Don't build on top of another entity
				if ( pList[i] == NULL )
					continue;

				//If one of the entities is solid, then we may not be able to spawn now
				if ( ( pList[i]->GetSolidFlags() & FSOLID_NOT_SOLID ) == false )
				{
					// Since the outer method doesn't work well around striders on account of their huge bounding box.
					// Find the ground under me and see if a human hull would fit there.
					trace_t tr;
					UTIL_TraceHull( GetAbsOrigin() + Vector( 0, 0, 2 ),
									GetAbsOrigin() - Vector( 0, 0, 8192 ),
									NAI_Hull::Mins(HULL_HUMAN),
									NAI_Hull::Maxs(HULL_HUMAN),
									MASK_NPCSOLID,
									m_hIgnoreEntity,
									COLLISION_GROUP_NONE,
									&tr );

					if( !HumanHullFits( tr.endpos + Vector( 0, 0, 1 ) ) )
					{
						return false;
					}
				}
			}
		}
	}

	// Do we need to check to see if the player's looking?
	if ( HasSpawnFlags( SF_NPCMAKER_HIDEFROMPLAYER ) )
	{
		for ( int i = 1; i <= gpGlobals->maxClients; i++ )
		{
			CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
			if ( pPlayer )
			{
				// Only spawn if the player's looking away from me
				if( pPlayer->FInViewCone( GetAbsOrigin() ) && pPlayer->FVisible( GetAbsOrigin() ) )
				{
					if ( !(pPlayer->GetFlags() & FL_NOTARGET) )
						return false;
					DevMsg( 2, "Spawner %s spawning even though seen due to notarget\n", STRING( GetEntityName() ) );
				}
			}
		}
	}

	return true;
}
#endif

	weapons.PurgeAndDeleteElements();

	return true;
}


#ifdef _DEBUG

CON_COMMAND( ge_showstats, "USAGE: ge_showstats [PLAYERID]\n Shows PLAYERID's current statistics" )
{
	if ( args.ArgC() < 2 )
		return;

	CGEPlayer *player = ToGEPlayer(UTIL_PlayerByIndex( atoi(args.Arg(1)) ));
	if ( !player )
		return;

	DevMsg( "Stats for %s:\n", player->GetPlayerName() );

	const char* ident;
	for ( int i=0; i < GE_AWARD_GIVEMAX; i++ )
	{
		ident = AwardIDToIdent( i );
		if ( ident )
			DevMsg( "%s: %i\n", ident, GEStats()->GetPlayerStat(i, player) );
	}
}

#endif
CNPCSpawnDestination *CTemplateNPCMaker::FindSpawnDestination()
{
	CNPCSpawnDestination *pDestinations[ MAX_DESTINATION_ENTS ];
	CBaseEntity *pEnt = NULL;
	CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 ); //BP CO HACK
	int	count = 0;

	if( !pPlayer )
	{
		return NULL;
	}

	// Collect all the qualifiying destination ents
	pEnt = gEntList.FindEntityByName( NULL, m_iszDestinationGroup );

	if( !pEnt )
	{
		DevWarning("Template NPC Spawner (%s) doesn't have any spawn destinations!\n", GetDebugName() );
		return NULL;
	}
	
	while( pEnt )
	{
		CNPCSpawnDestination *pDestination;

		pDestination = dynamic_cast <CNPCSpawnDestination*>(pEnt);

		if( pDestination && pDestination->IsAvailable() )
		{
			bool fValid = true;
			Vector vecTest = pDestination->GetAbsOrigin();

			if( m_CriterionVisibility != TS_YN_DONT_CARE )
			{
				// Right now View Cone check is omitted intentionally.
				Vector vecTopOfHull = NAI_Hull::Maxs( HULL_HUMAN );
				vecTopOfHull.x = 0;
				vecTopOfHull.y = 0;
				bool fVisible = (pPlayer->FVisible( vecTest ) || pPlayer->FVisible( vecTest + vecTopOfHull ) );

				if( m_CriterionVisibility == TS_YN_YES )
				{
					if( !fVisible )
						fValid = false;
				}
				else
				{
					if( fVisible )
					{
						if ( !(pPlayer->GetFlags() & FL_NOTARGET) )
							fValid = false;
						else
							DevMsg( 2, "Spawner %s spawning even though seen due to notarget\n", STRING( GetEntityName() ) );
					}
				}
			}

			if( fValid )
			{
				pDestinations[ count ] = pDestination;
				count++;
			}
		}

		pEnt = gEntList.FindEntityByName( pEnt, m_iszDestinationGroup );
	}

	if( count < 1 )
		return NULL;

	// Now find the nearest/farthest based on distance criterion
	if( m_CriterionDistance == TS_DIST_DONT_CARE )
	{
		// Pretty lame way to pick randomly. Try a few times to find a random
		// location where a hull can fit. Don't try too many times due to performance
		// concerns.
		for( int i = 0 ; i < 5 ; i++ )
		{
			CNPCSpawnDestination *pRandomDest = pDestinations[ rand() % count ];

			if( HumanHullFits( pRandomDest->GetAbsOrigin() ) )
			{
				return pRandomDest;
			}
		}

		return NULL;
	}
	else
	{
		if( m_CriterionDistance == TS_DIST_NEAREST )
		{
			float flNearest = FLT_MAX;
			CNPCSpawnDestination *pNearest = NULL;

			for( int i = 0 ; i < count ; i++ )
			{
				Vector vecTest = pDestinations[ i ]->GetAbsOrigin();
				float flDist = ( vecTest - pPlayer->GetAbsOrigin() ).Length();

				if ( m_iMinSpawnDistance != 0 && m_iMinSpawnDistance > flDist )
					continue;

				if( flDist < flNearest && HumanHullFits( vecTest ) )
				{
					flNearest = flDist;
					pNearest = pDestinations[ i ];
				}
			}

			return pNearest;
		}
		else
		{
			float flFarthest = 0;
			CNPCSpawnDestination *pFarthest = NULL;

			for( int i = 0 ; i < count ; i++ )
			{
				Vector vecTest = pDestinations[ i ]->GetAbsOrigin();
				float flDist = ( vecTest - pPlayer->GetAbsOrigin() ).Length();

				if ( m_iMinSpawnDistance != 0 && m_iMinSpawnDistance > flDist )
					continue;

				if( flDist > flFarthest && HumanHullFits( vecTest ) )
				{
					flFarthest = flDist;
					pFarthest = pDestinations[ i ];
				}
			}

			return pFarthest;
		}
	}

	return NULL;
}
//=========================================================
// FindNearestFriend
// Scan for nearest, visible friend. If fPlayer is true, look for
// nearest player
//=========================================================
CBaseEntity *CAI_PlayerAlly::FindNearestFriend(bool fPlayer)
{
	CBaseEntity *pFriend = NULL;
	CBaseEntity *pNearest = NULL;
	float range = 10000000.0;
	trace_t tr;
	Vector vecStart = GetAbsOrigin();
	Vector vecCheck;
	int i;
	const char *pszFriend;
	int cfriends;

	vecStart.z = GetAbsMaxs().z;
	
	if (fPlayer)
		cfriends = 1;
	else
		cfriends = TLK_CFRIENDS;

	// for each type of friend...

	for (i = cfriends-1; i > -1; i--)
	{
		if (fPlayer)
		{
			CBaseEntity *pPlayer = UTIL_PlayerByIndex(1);
			if ( pPlayer )
			{
				pszFriend = STRING(pPlayer->m_iClassname);
			}
			else
			{
				pszFriend = "player";
			}
		}
		else
			pszFriend = m_szFriends[FriendNumber(i)];

		if (!pszFriend)
			continue;

		// for each friend in this bsp...
		while (pFriend = gEntList.FindEntityByClassname( pFriend, pszFriend ))
		{
			if (pFriend == this || !pFriend->IsAlive())
				// don't talk to self or dead people
				continue;

			CAI_BaseNPC *pNPC = pFriend->MyNPCPointer();

			// If not a NPC for some reason, or in a script.
			if ( pNPC && (pNPC->m_NPCState == NPC_STATE_SCRIPT || pNPC->m_NPCState == NPC_STATE_PRONE))
				continue;

			if( pNPC && pNPC->IsSelected() )
			{
				// Don't bother people that are awaiting orders.
				return false;
			}

			vecCheck = pFriend->GetLocalOrigin();
			vecCheck.z = pFriend->GetAbsMaxs().z;

			// if closer than previous friend, and in range, see if he's visible

			if (range > (vecStart - vecCheck).Length())
			{
				UTIL_TraceLine(vecStart, vecCheck, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);

				if (tr.fraction == 1.0)
				{
					// visible and in range, this is the new nearest scientist
					if ((vecStart - vecCheck).Length() < TALKRANGE_MIN)
					{
						pNearest = pFriend;
						range = (vecStart - vecCheck).Length();
					}
				}
			}
		}
	}
	return pNearest;
}
void CFlextalkActor::ProcessSceneEvents( void )
{
	if ( HasSceneEvents() )
	{
		BaseClass::ProcessSceneEvents( );
		return;
	}
	
	// only do this if they have more than eyelid movement
	if (GetNumFlexControllers() > 2)
	{
		const char *pszExpression = flex_expression.GetString();

		if (pszExpression && pszExpression[0] == '+' && pszExpression[1] != '\0')
		{
			int i;
			int j = atoi( &pszExpression[1] );
			for (i = 0; i < GetNumFlexControllers(); i++)
			{
				m_flextarget[m_flexnum] = 0;
			}

			for (i = 0; i < 35 && predef_flexcontroller_names[i]; i++)
			{
				m_flexnum = LookupFlex( predef_flexcontroller_names[i] );
				m_flextarget[m_flexnum] = predef_flexcontroller_values[j][i];
				// Msg( "%s %.3f\n", predef_flexcontroller_names[i], predef_flexcontroller_values[j][i] );
			}
		}
		else if (pszExpression && pszExpression[0] != '\0' && strcmp(pszExpression, "+") != 0)
		{
			char szExpression[128];
			char szTemp[32];

			Q_strncpy( szExpression, pszExpression ,sizeof(szExpression));
			char *pszExpression = szExpression;

			while (*pszExpression != '\0')
			{
				if (*pszExpression == '+')
					*pszExpression = ' ';
				
				pszExpression++;
			}

			pszExpression = szExpression;

			while (*pszExpression)
			{
				if (*pszExpression != ' ')
				{
					if (*pszExpression == '-')
					{
						for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
						{
							m_flextarget[i] = 0;
						}
					}
					else if (*pszExpression == '?')
					{
						for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
						{
							Msg( "\"%s\" ", GetFlexControllerName( i ) );
						}
						Msg( "\n" );
						flex_expression.SetValue( "" );
					}
					else
					{
						if (sscanf( pszExpression, "%31s", szTemp ) == 1)
						{
							m_flexnum = LookupFlex( szTemp );

							if (m_flexnum != -1 && m_flextarget[m_flexnum] != 1)
							{
								m_flextarget[m_flexnum] = 1.0;
								// SetFlexTarget( m_flexnum );
							}
							pszExpression += strlen( szTemp ) - 1;
						}
					}
				}
				pszExpression++;
			}
		} 
		else if (m_flextime < gpGlobals->curtime)
		{
			m_flextime = gpGlobals->curtime + random->RandomFloat( 0.3, 0.5 ) * (30.0 / GetNumFlexControllers());
			m_flexnum = (LocalFlexController_t)random->RandomInt( 0, GetNumFlexControllers() - 1 );

			if (m_flextarget[m_flexnum] == 1)
			{
				m_flextarget[m_flexnum] = 0;
			}
			else if (stricmp( GetFlexControllerType( m_flexnum ), "phoneme" ) != 0)
			{
				if (strstr( GetFlexControllerName( m_flexnum ), "upper_raiser" ) == NULL)
				{
					Msg( "%s:%s\n", GetFlexControllerType( m_flexnum ), GetFlexControllerName( m_flexnum ) );
					SetFlexTarget( m_flexnum, random->RandomFloat( 0.5, 1.0 ) );
				}
			}
		}

		// slide it up.
		for (LocalFlexController_t i = LocalFlexController_t(0); i < GetNumFlexControllers(); i++)
		{
			float weight = GetFlexWeight( i );

			if (weight != m_flextarget[i])
			{
				weight = weight + (m_flextarget[i] - weight) / random->RandomFloat( 2.0, 4.0 );
			}
			weight = clamp( weight, 0.0f, 1.0f );
			SetFlexWeight( i, weight );
		}

		if (flex_talk.GetInt() == -1)
		{
			m_istalking = 1;

			char pszSentence[256];
			Q_snprintf( pszSentence,sizeof(pszSentence), "%s%d", STRING(m_iszSentence), m_sentence++ );
			int sentenceIndex = engine->SentenceIndexFromName( pszSentence );
			if (sentenceIndex >= 0)
			{
				Msg( "%d : %s\n", sentenceIndex, pszSentence );
				CPASAttenuationFilter filter( this );
				CBaseEntity::EmitSentenceByIndex( filter, entindex(), CHAN_VOICE, sentenceIndex, 1, SNDLVL_TALKING, 0, PITCH_NORM );
			}
			else
			{
				m_sentence = 0;
			}

			flex_talk.SetValue( "0" );
		}
		else if (flex_talk.GetInt() == -2)
		{
			m_flNextEyeLookTime = gpGlobals->curtime + 1000.0;
		}
		else if (flex_talk.GetInt() == -3)
		{
			m_flNextEyeLookTime = gpGlobals->curtime;
			flex_talk.SetValue( "0" );
		}
		else if (flex_talk.GetInt() == -4)
		{
			AddLookTarget( UTIL_PlayerByIndex( 1 ), 0.5, flex_looktime.GetFloat()  );
			flex_talk.SetValue( "0" );
		}
		else if (flex_talk.GetInt() == -5)
		{
			PickLookTarget( true );
			flex_talk.SetValue( "0" );
		}
	}
}
void CTriggerCamera::PostActivate( void )
{
	if (FStrEq( STRING( pev->target ), "player" ) || ( pev->spawnflags & SF_CAMERA_PLAYER_TARGET ))
		pTarget = UTIL_PlayerByIndex( 1 );
	else pTarget = UTIL_FindEntityByTargetname( NULL, STRING( pev->target ));
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
float CalculatePhysicsImpactDamage( int index, gamevcollisionevent_t *pEvent, const impactdamagetable_t &table, float energyScale, bool allowStaticDamage, int &damageType, bool bDamageFromHeldObjects )
{
	damageType = DMG_CRUSH;
	int otherIndex = !index;

	// UNDONE: Expose a flag for self-inflicted damage?  Can't think of a valid case so far.
	if ( pEvent->pEntities[0] == pEvent->pEntities[1] )
		return 0;

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_NO_NPC_IMPACT_DMG )
	{
		if( pEvent->pEntities[index]->IsNPC() || pEvent->pEntities[index]->IsPlayer() )
		{
			return 0;
		}
	}

	// use implicit velocities on ragdolls since they may have high constraint velocities that aren't actually executed, just pushed through contacts
	if (( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PART_OF_RAGDOLL) && pEvent->pEntities[index]->IsPlayer() )
	{
		pEvent->pObjects[otherIndex]->GetImplicitVelocity( &pEvent->preVelocity[otherIndex], &pEvent->preAngularVelocity[otherIndex] );
	}

	// Dissolving impact damage results in death always.
	if ( ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_DISSOLVE ) && 
			!pEvent->pEntities[index]->IsEFlagSet(EFL_NO_DISSOLVE) )
	{
		damageType |= DMG_DISSOLVE;
		return 1000;
	}

	if ( energyScale <= 0.0f )
		return 0;

	const int gameFlagsNoDamage = FVPHYSICS_CONSTRAINT_STATIC | FVPHYSICS_NO_IMPACT_DMG;

	// NOTE: Crushing damage is handled by stress calcs in vphysics update functions, this is ONLY impact damage
	// this is a non-moving object due to a constraint - no damage
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & gameFlagsNoDamage )
		return 0;

	// If it doesn't take damage from held objects and the object is being held - no damage
	if ( !bDamageFromHeldObjects && ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) )
	{
		// If it doesn't take damage from held objects - no damage
		if ( !bDamageFromHeldObjects )
			return 0;
	}

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY )
	{
		// UNDONE: Add up mass here for car wheels and prop_ragdoll pieces?
		IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
		int count = pEvent->pEntities[otherIndex]->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
		for ( int i = 0; i < count; i++ )
		{
			if ( pList[i]->GetGameFlags() & gameFlagsNoDamage )
				return 0;
		}
	}

	if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		// players can't damage held objects
		if ( pEvent->pEntities[otherIndex]->IsPlayer() )
			return 0;

		allowStaticDamage = false;
	}

#if 0
	{
		PhysGetDamageInflictorVelocityStartOfFrame( pEvent->pObjects[otherIndex], pEvent->preVelocity[otherIndex], pEvent->preAngularVelocity[otherIndex] );
	}
#endif

	float otherSpeedSqr = pEvent->preVelocity[otherIndex].LengthSqr();
	float otherAngSqr = 0;
	
	// factor in angular for sharp objects
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_SLICE )
	{
		otherAngSqr = pEvent->preAngularVelocity[otherIndex].LengthSqr();
	}

	float otherMass = pEvent->pObjects[otherIndex]->GetMass();

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		if ( gpGlobals->maxClients == 1 )
		{
			// if the player is holding the object, use it's real mass (player holding reduced the mass)
#ifdef C17
			CBasePlayer *pPlayer = NULL;

			if (1 == gpGlobals->maxClients)
			{
				pPlayer = UTIL_GetLocalPlayer();
			}
			else
			{
				// See which MP player is holding the physics object and then use that player to get the real mass of the object.
				// This is ugly but better than having linkage between an object and its "holding" player.
				for (int i = 1; i <= gpGlobals->maxClients; i++)
				{
					CBasePlayer *tempPlayer = UTIL_PlayerByIndex(i);
					if (tempPlayer && pEvent->pEntities[index] == tempPlayer->GetHeldObject())
					{
						pPlayer = tempPlayer;
						break;
					}
				}
			}
#else
			CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
			if ( pPlayer )
			{
				otherMass = pPlayer->GetHeldObjectMass( pEvent->pObjects[otherIndex] );
			}
#endif
		}
	}

	// NOTE: sum the mass of each object in this system for the purpose of damage
	if ( pEvent->pEntities[otherIndex] && (pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY) )
	{
		otherMass = PhysGetEntityMass( pEvent->pEntities[otherIndex] );
	}
	
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_HEAVY_OBJECT )
	{
		otherMass = table.largeMassMin;
		if ( energyScale < 2.0f )
		{
			energyScale = 2.0f;
		}
	}

	// UNDONE: allowStaticDamage is a hack - work out some method for 
	// breakable props to impact the world and break!!
	if ( !allowStaticDamage )
	{
		if ( otherMass < table.minMass )
			return 0;
		// check to see if the object is small
		if ( otherMass < table.smallMassMax && otherSpeedSqr < table.smallMassMinSpeedSqr )
			return 0;
		
		if ( otherSpeedSqr < table.minSpeedSqr && otherAngSqr < table.minRotSpeedSqr )
			return 0;
	}

	// Add extra oomph for floating objects
	if ( pEvent->pEntities[index]->IsFloating() && !pEvent->pEntities[otherIndex]->IsWorld() )
	{
		if ( energyScale < 3.0f )
		{
			energyScale = 3.0f;
		}
	}

	float damage = 0;
	bool bDebug = false;//(&table == &gDefaultPlayerImpactDamageTable);

	// don't ever take spin damage from slowly spinning objects
	if ( otherAngSqr > table.minRotSpeedSqr )
	{
		Vector otherInertia = pEvent->pObjects[otherIndex]->GetInertia();
		float angularMom = DotProductAbs( otherInertia, pEvent->preAngularVelocity[otherIndex] );
		damage = ReadDamageTable( table.angularTable, table.angularCount, angularMom * energyScale, bDebug );
		if ( damage > 0 )
		{
//			Msg("Spin : %.1f, Damage %.0f\n", FastSqrt(angularMom), damage );
			damageType |= DMG_SLASH;
		}
	}
	
	float deltaV = pEvent->preVelocity[index].Length() - pEvent->postVelocity[index].Length();
	float mass = pEvent->pObjects[index]->GetMass();

	// If I lost speed, and I lost less than min velocity, then filter out this energy
	if ( deltaV > 0 && deltaV < table.myMinVelocity )
	{
		deltaV = 0;
	}
	float eliminatedEnergy = deltaV * deltaV * mass;

	deltaV = pEvent->preVelocity[otherIndex].Length() - pEvent->postVelocity[otherIndex].Length();
	float otherEliminatedEnergy = deltaV * deltaV * otherMass;
	
	// exaggerate the effects of really large objects
	if ( otherMass >= table.largeMassMin )
	{
		otherEliminatedEnergy *= table.largeMassScale;
		float dz = pEvent->preVelocity[otherIndex].z - pEvent->postVelocity[otherIndex].z;

		if ( deltaV > 0 && dz < 0 && pEvent->preVelocity[otherIndex].z < 0 )
		{
			float factor = fabs(dz / deltaV);
			otherEliminatedEnergy *= (1 + factor * (table.largeMassFallingScale - 1.0f));
		}
	}

	eliminatedEnergy += otherEliminatedEnergy;

	// now in units of this character's speed squared
	float invMass = pEvent->pObjects[index]->GetInvMass();
	if ( !pEvent->pObjects[index]->IsMoveable() )
	{
		// inv mass is zero, but impact damage is enabled on this
		// prop, so recompute:
		invMass = 1.0f / pEvent->pObjects[index]->GetMass();
	}
	else if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		if ( gpGlobals->maxClients == 1 )
		{
			// if the player is holding the object, use it's real mass (player holding reduced the mass)
#ifdef C17
			CBasePlayer *pPlayer = NULL;
			if (1 == gpGlobals->maxClients)
			{
				pPlayer = UTIL_GetLocalPlayer();
			}
			else
			{
				// See which MP player is holding the physics object and then use that player to get the real mass of the object.
				// This is ugly but better than having linkage between an object and its "holding" player.
				for (int i = 1; i <= gpGlobals->maxClients; i++)
				{
					CBasePlayer *tempPlayer = UTIL_PlayerByIndex(i);
					if (tempPlayer && pEvent->pEntities[index] == tempPlayer->GetHeldObject())
					{
						pPlayer = tempPlayer;
						break;
					}
				}
			}
#else
			CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
			if ( pPlayer )
			{
				float mass = pPlayer->GetHeldObjectMass( pEvent->pObjects[index] );
				if ( mass > 0 )
				{
					invMass = 1.0f / mass;
				}
			}
#endif
		}
	}

	eliminatedEnergy *= invMass * energyScale;
	
	damage += ReadDamageTable( table.linearTable, table.linearCount, eliminatedEnergy, bDebug );

	if ( !pEvent->pObjects[otherIndex]->IsStatic() && otherMass < table.smallMassMax && table.smallMassCap > 0 )
	{
		damage = clamp( damage, 0.f, table.smallMassCap );
	}

	return damage;
}
Exemple #27
0
//=========================================================
//=========================================================
void CHalfLifeTeamplay::RecountTeams( bool bResendInfo )
{
	char	*pName;
	char	teamlist[TEAMPLAY_TEAMLISTLENGTH];

	// loop through all teams, recounting everything
	num_teams = 0;

	// Copy all of the teams from the teamlist
	// make a copy because strtok is destructive
	strcpy( teamlist, m_szTeamList );
	pName = teamlist;
	pName = strtok( pName, ";" );
	while ( pName != NULL && *pName )
	{
		if ( GetTeamIndex( pName ) < 0 )
		{
			strcpy( team_names[num_teams], pName );
			num_teams++;
		}
		pName = strtok( NULL, ";" );
	}

	if ( num_teams < 2 )
	{
		num_teams = 0;
		m_teamLimit = FALSE;
	}

	// Sanity check
	memset( team_scores, 0, sizeof(team_scores) );

	// loop through all clients
	for ( int i = 1; i <= gpGlobals->maxClients; i++ )
	{
		CBaseEntity *plr = UTIL_PlayerByIndex( i );

		if ( plr )
		{
			const char *pTeamName = plr->TeamID();
			// try add to existing team
			int tm = GetTeamIndex( pTeamName );
			
			if ( tm < 0 ) // no team match found
			{ 
				if ( !m_teamLimit )
				{
					// add to new team
					tm = num_teams;
					num_teams++;
					team_scores[tm] = 0;
					strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH );
				}
			}

			if ( tm >= 0 )
			{
				team_scores[tm] += plr->pev->frags;
			}

			if ( bResendInfo ) //Someone's info changed, let's send the team info again.
			{
				if ( plr && IsValidTeam( plr->TeamID() ) )
				{
					MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo, NULL );
						WRITE_BYTE( plr->entindex() );
						WRITE_STRING( plr->TeamID() );
					MESSAGE_END();
				}
			}
		}
	}
}
Exemple #28
0
// CONSIDER: if player in water state, autoset and underwater soundscape? 
void CEnvSoundscape::Update()
{
	bool bUpdated = UpdatePlayersInPVS();

	if ( !IsEnabled() )
		return;

	// Only update soundscapes in multiplayer when the PVS gets updated
	if ( g_pGameRules->IsMultiplayer() && !bUpdated && !soundscape_debug.GetBool() )
		return;

	bool bDebugThis = soundscape_debug.GetInt() == 1;

	for ( int i=0; i < m_hPlayersInPVS.Count(); i++ )
	{
		CBasePlayer *pPlayer = m_hPlayersInPVS[i];
		if ( !pPlayer )
			continue;

		if ( !InRangeOfPlayer( pPlayer ) )
			continue;

		// check to see if this is the sound entity that is 
		// currently affecting this player
		audioparams_t &audio = pPlayer->GetAudioParams();

		// if we got this far, we're looking at an entity that is contending
		// for current player sound. the closest entity to player wins.
		CEnvSoundscape *pCurrent = (CEnvSoundscape *)audio.ent.Get();
		if ( !pCurrent || 
			!pCurrent->IsEnabled() || 
			!pCurrent->InRangeOfPlayer( pPlayer ) ) 
		{
			// The old one is obscured or out of range.. take over.
			WriteAudioParamsTo( audio );
		}
		else if ( pCurrent && 
			EarPosition().DistTo( pPlayer->EarPosition() ) < pCurrent->EarPosition().DistTo( pPlayer->EarPosition() ) )
		{
			// new entity is closer to player, so it wins.
			WriteAudioParamsTo( audio );
		}

		if ( !bDebugThis )
		{
			bDebugThis = soundscape_debug.GetInt() == 2;
		}
	} 

	if ( bDebugThis )
	{

		// draw myself
		NDebugOverlay::Box(GetAbsOrigin(), Vector(-10,-10,-10), Vector(10,10,10),  255, 0, 255, 64, NDEBUG_PERSIST_TILL_NEXT_SERVER );

		// Don't use GetLocalPlayer(), because that prevents multiplayer games using this for testing with a single client in the game
		CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
 		if ( pPlayer )
		{
			audioparams_t &audio = pPlayer->GetAudioParams();
			if ( audio.ent.Get() != this )
			{
				if ( InRangeOfPlayer( pPlayer ) )
				{
					NDebugOverlay::Line( GetAbsOrigin(), pPlayer->WorldSpaceCenter(), 255, 255, 255, true, NDEBUG_PERSIST_TILL_NEXT_SERVER );
				}
				else
				{
					NDebugOverlay::Line( GetAbsOrigin(), pPlayer->WorldSpaceCenter(), 255, 0, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER  );
				}
			}
			else
			{
				if ( InRangeOfPlayer( pPlayer ) )
				{
					NDebugOverlay::Line( GetAbsOrigin(), pPlayer->WorldSpaceCenter(), 0, 255, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER  );
				}
  				else
				{
					NDebugOverlay::Line( GetAbsOrigin(), pPlayer->WorldSpaceCenter(), 255, 170, 0, true, NDEBUG_PERSIST_TILL_NEXT_SERVER  );
				}

				// also draw lines to each sound position.
				// we don't store the number of local sound positions, just a bitvector of which ones are on.
				unsigned int soundbits = audio.localBits.Get();
				float periodic = 2.0f * sin((fmod(gpGlobals->curtime,2.0f) - 1.0f) * M_PI); // = -4f .. 4f
				for (int ii = 0 ; ii < NUM_AUDIO_LOCAL_SOUNDS ; ++ii )
				{
					if ( soundbits & (1 << ii) )
					{
						const Vector &soundLoc = audio.localSound.Get(ii);
						NDebugOverlay::Line( GetAbsOrigin(), soundLoc, 0, 32 , 255 , false, NDEBUG_PERSIST_TILL_NEXT_SERVER );
						NDebugOverlay::Cross3D( soundLoc, 16.0f + periodic, 0, 0, 255, false, NDEBUG_PERSIST_TILL_NEXT_SERVER );
					}
				}
			}
		}

		NDebugOverlay::EntityTextAtPosition( GetAbsOrigin(), 0, STRING(m_soundscapeName), NDEBUG_PERSIST_TILL_NEXT_SERVER );
	}

}