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); } } }
//// 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; }
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; }
// 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); } }
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(); } } }
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; }
// 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; }
//========================================================= //========================================================= 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(); } } } } }
// 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 ); } }