//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" #include "hud.h" #include "hudelement.h" #include "hud_element_helper.h" #include "iclientmode.h" #include "view.h" #include "vgui_controls/Controls.h" #include "vgui/ISurface.h" #include "ivrenderview.h" #include "scaleformui/scaleformui.h" #include "sfhudreticle.h" #include "vgui/ILocalize.h" #include "c_cs_hostage.h" #include "c_cs_player.h" #include "c_cs_playerresource.h" #include "engineinterface.h" #include "interfaces/interfaces.h" #include "matchmaking/imatchframework.h" #include "matchmaking/iplayermanager.h" #include "gameui_util.h" #include "c_plantedc4.h" #include "sfhudfreezepanel.h" #include "inputsystem/iinputsystem.h" #include "voice_status.h" #include "basepanel.h" #include "cs_shareddefs.h" #include "hltvcamera.h" #include "cs_hud_weaponselection.h" #include "HUD/sfhud_teamcounter.h" #include "hltvreplaysystem.h" #if !defined (NO_STEAM) #include "steam/steam_api.h" #endif #ifdef SIXENSE #include "sixense/in_sixense.h" #endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //ConVar sfcrosshair( "sfcrosshair", "1", FCVAR_ARCHIVE | FCVAR_SS ); ConVar crosshair( "crosshair", "1", FCVAR_ARCHIVE | FCVAR_SS ); ConVar cl_observercrosshair( "cl_observercrosshair", "1", FCVAR_ARCHIVE | FCVAR_SS ); ConVar cl_fixedcrosshairgap( "cl_fixedcrosshairgap", "3", FCVAR_ARCHIVE | FCVAR_SS, "How big to make the gap between the pips in the fixed crosshair" ); ConVar lockMoveControllerRet( "lockMoveControllerRet", "0", FCVAR_ARCHIVE ); static ConVar hud_showtargetid( "hud_showtargetid", "1", FCVAR_ARCHIVE | FCVAR_SS, "Enables display of target names" ); //extern ConVar cl_dynamiccrosshair; extern ConVar cl_teamid_overhead; extern ConVar cl_teamid_overhead_maxdist; extern ConVar cl_teamid_overhead_maxdist_spec; extern ConVar voice_icons_method; extern ConVar cl_crosshairstyle; extern ConVar spec_show_xray; extern ConVar cl_draw_only_deathnotices; extern ConVar mp_hostages_takedamage; static ConVar cl_teamid_overhead_name_alpha( "cl_teamid_overhead_name_alpha", "100", FCVAR_ARCHIVE | FCVAR_SS, "The max alpha the overhead ID names will draw as." ); static ConVar cl_teamid_overhead_name_fadetime( "cl_teamid_overhead_name_fadetime", "1.0", FCVAR_ARCHIVE | FCVAR_SS, "How long it takes for the overhad name to fade out once your crosshair has left the target." ); static ConVar mc_use_recoil_on_cursor( "mc_use_recoil_on_cursor", "0", 0 ); void fnTeamIDOverheadAlwaysCallback( IConVar *pConVar, const char *pOldValue, float flOldValue ) { ConVarRef var( pConVar ); ( GET_HUDELEMENT( SFHudReticle ) )->ToggleTeamEquipmentVisibility( var.GetInt() == 2 ); } static ConVar cl_teamid_overhead_always( "cl_teamid_overhead_always", "0", FCVAR_ARCHIVE | FCVAR_RELEASE,"Always show team id over teammates. 1 = pips; 2 = pips, name, and equipment", fnTeamIDOverheadAlwaysCallback ); #define MAX_PLAYER_NAME_ID_PANELS 16 enum ID_TEXT_INDEX { IDTEXT_NONE, IDTEXT_FOE, IDTEXT_FRIEND, IDTEXT_HOSTAGE }; DECLARE_HUDELEMENT( SFHudReticle ); void IN_ShowTeamEquipmentDown( const CCommand &args ) { ( GET_HUDELEMENT( SFHudReticle ) )->ToggleTeamEquipmentVisibility( true ); } void IN_ShowTeamEquipmentUp( const CCommand &args ) { ( GET_HUDELEMENT( SFHudReticle ) )->ToggleTeamEquipmentVisibility( false ); } static ConCommand ShowAllTargetIDs( "+cl_show_team_equipment", IN_ShowTeamEquipmentDown ); static ConCommand UnShowAllTargetIDs( "-cl_show_team_equipment", IN_ShowTeamEquipmentUp ); SFUI_BEGIN_GAME_API_DEF SFUI_DECL_METHOD_AS( OnSwapReticle, "SwapReticle" ), SFUI_END_GAME_API_DEF( SFHudReticle, Reticle ); SFHudReticle::SFHudReticle( const char *value ) : SFHudFlashInterface( value ), m_WeaponCrosshairHandle( NULL ), m_TopPip( NULL ), m_BottomPip( NULL ), m_LeftPip( NULL ), m_RightPip( NULL ), m_topCrosshairArc( NULL ), m_rightCrosshairArc( NULL ), m_leftCrosshairArc( NULL ), m_bottomCrosshairArc( NULL ), m_FriendCrosshair( NULL ), m_crosshairDot( NULL ), m_blackRing( NULL ), m_IDText( NULL ), m_IDMovie( NULL ), m_FlashedIcon( NULL ), m_fIDTimer( 0.0f ), m_bTextIDVisible( false ), m_iReticleMode( RETICLE_MODE_NONE ), m_bFriendlyCrosshairVisible( true ), m_bEnemyCrosshairVisible( false ), m_bFlashedIconFadingOut(true), m_iLastGap( -1 ), m_iLastSpread( -1 ), m_dotX( 0.0f ), m_dotY( 0.0f ), m_blackRingX( 0.0f ), m_blackRingY( 0.0f ), m_friendIndicatorX( 0.0f ), m_friendIndicatorY( 0.0f ), m_IDMovieX( 0.0f ), m_IDMovieY( 0.0f ), m_bCrosshairPositionsInitialized( false ) { // TODO Auto-generated constructor stub SetHiddenBits( HIDEHUD_PLAYERDEAD | HIDEHUD_CROSSHAIR ); m_wcIDString[0] = 0; m_bWantLateUpdate = true; } SFHudReticle::~SFHudReticle() { // TODO Auto-generated destructor stub } void SFHudReticle::ShowReticle( RETICLE_MODE mode, bool value ) { SFVALUE handle = 0; switch( mode ) { case RETICLE_MODE_WEAPON: handle = m_WeaponCrosshairHandle; break; case RETICLE_MODE_OBSERVER: handle = m_ObserverCrosshairHandle; break; default: break; } if ( handle ) { m_pScaleformUI->Value_SetVisible( handle, value ); } } void SFHudReticle::LockSlot( bool wantItLocked, bool& currentlyLocked ) { if ( currentlyLocked != wantItLocked ) { if ( wantItLocked ) LockScaleformSlot(); else UnlockScaleformSlot(); currentlyLocked = wantItLocked; } } extern ConVar weapon_debug_spread_show; void SFHudReticle::ProcessInput( void ) { if ( !FlashAPIIsValid() ) return; SF_SPLITSCREEN_PLAYER_GUARD(); bool bShowFriendlyCrosshair = false; RETICLE_MODE iDesiredReticleMode = RETICLE_MODE_NONE; wchar_t wcNewString[ TEXTFIELD_LENGTH ]; wcNewString[0] = 0; C_CSPlayer *pCSPlayer = GetHudPlayer(); C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer(); // do crosshair calculations first because they can affect the // display of the target id bool bWantWeaponShown = false; bool bHasWeapon = false; bool bPlayerInInputMode = false; bool bShowCrosshair = false; bool bShowFriendEnemyDesignation = false; bool bFriendlyCrosshairOkay = false; bool bShowDroppedWeaponNames = false; bool bCheckWeaponRange = false; bool bWantEnemyCrosshair = false; int iDesiredGap = -1; int iDesiredSpread = -1; float fDesiredFishtail = 0.0f; int iObsMode = OBS_MODE_NONE; /************************************ * the logic below is complicated, but here's what it means: * 1 - If we're not in spectator mode, then only show a crosshair if we're not in an input mode * and we have a weapon ( normally true ) and the weapon wants a crosshair. * 2 - If we're in spectator in eye mode, show a crosshair if the weapon wants it * but don't show the friendly target icon * 3 - If we're in spectator roaming mode, show the spectator crosshair * 4 - Otherwise show no crosshair */ if ( pLocalPlayer && crosshair.GetBool() ) { iObsMode = pLocalPlayer->GetObserverMode(); switch( iObsMode ) { case OBS_MODE_IN_EYE: case OBS_MODE_ROAMING: bShowCrosshair = true; break; case OBS_MODE_NONE: bFriendlyCrosshairOkay = true; bShowDroppedWeaponNames = true; bShowCrosshair = true; bShowFriendEnemyDesignation = true; break; default: bShowCrosshair = false; break; } #ifdef IRONSIGHT CWeaponCSBase *pCSWeapon = pLocalPlayer->GetActiveCSWeapon(); if ( pCSWeapon && pCSWeapon->GetIronSightController() && !weapon_debug_spread_show.GetBool() ) { bShowCrosshair = !pCSWeapon->GetIronSightController()->ShouldHideCrossHair(); } #endif //IRONSIGHT if ( bShowCrosshair && iObsMode != OBS_MODE_ROAMING ) { if ( pLocalPlayer->IsInVGuiInputMode() || pLocalPlayer->IsInViewModelVGuiInputMode() ) bPlayerInInputMode = true; else { CWeaponCSBase *pWeapon = ( CWeaponCSBase* )pCSPlayer->GetActiveWeapon(); if ( pWeapon ) { bHasWeapon = true; if ( pWeapon->WantReticleShown() ) { if ( pWeapon->GetCSWeaponID() == WEAPON_TASER ) { // When using the taser we don't want to change the reticle color until the // target is in range. bCheckWeaponRange = true; } bWantWeaponShown = true; iDesiredSpread = pWeapon->GetReticleWeaponSpread(); iDesiredGap = pWeapon->GetReticleCrosshairGap(); fDesiredFishtail = pWeapon->GetAccuracyFishtail(); } } } } // the reticle mode is defaulted to NONE above (outside this clause) so // we don't have to explicitly sent none if ( bShowCrosshair ) { if ( iObsMode == OBS_MODE_ROAMING ) { iDesiredReticleMode = RETICLE_MODE_OBSERVER; } else if ( pLocalPlayer && !bPlayerInInputMode && bHasWeapon && bWantWeaponShown ) { iDesiredReticleMode = RETICLE_MODE_WEAPON; } } } bool bShowBlankXHairID = false; bool bIsHostage = false; bool bLocalIsSpectatorViewer = CanSeeSpectatorOnlyTools(); bool bForceShowCenterID = false; bool displayingTargetID = false; bool bIsFullyBlinded = pCSPlayer && pCSPlayer->m_flFlashOverlayAlpha >= 180.0f; bool bIsFlashed = pCSPlayer && pCSPlayer->m_flFlashBangTime > ( gpGlobals->curtime+0.5 ); if ( m_FlashedIcon && !cl_draw_only_deathnotices.GetBool() ) { if ( pCSPlayer->m_flFlashOverlayAlpha > 0 && bLocalIsSpectatorViewer ) { float flFlashFrac = 1.0 - clamp( pCSPlayer->m_flFlashOverlayAlpha / 210, 0, 1 ); // show flashed WITH_SFVALUEARRAY_SLOT_LOCKED( args, 1 ) { m_pScaleformUI->ValueArray_SetElement( args, 0, flFlashFrac ); m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashedIcon, "FlashFade", args, 1 ); } m_bFlashedIconFadingOut = true; } else if ( m_bFlashedIconFadingOut ) { WITH_SLOT_LOCKED { m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashedIcon, "Hide", NULL, 0 ); } m_bFlashedIconFadingOut = false; } } if ( hud_showtargetid.GetBool() ) { // if we're still blinded, then leave everything just like it is if ( !bLocalIsSpectatorViewer && bIsFlashed ) return; // if we're spectating and the player we're observing is fully blind, say so in the target id if ( iObsMode == OBS_MODE_IN_EYE && bIsFullyBlinded && !cl_draw_only_deathnotices.GetBool() ) { displayingTargetID = true; g_pVGuiLocalize->ConstructString( wcNewString, sizeof( wcNewString ), g_pVGuiLocalize->Find( "#SFUIHUD_targetid_FLASHED" ), 0 ); } else if ( ( iDesiredReticleMode != RETICLE_MODE_NONE ) || ( pCSPlayer->GetFOV() != pCSPlayer->GetDefaultFOV() ) ) { // Get our target's ent index int iEntIndex = hud_showtargetid.GetBool() ? pCSPlayer->GetIDTarget() : 0; if ( iEntIndex ) { C_CSPlayer *pPlayer = static_cast( cl_entitylist->GetEnt( iEntIndex ) ); C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer(); const char *printFormatString = NULL; wchar_t wszClanTag[ MAX_PLAYER_NAME_LENGTH ]; wchar_t wszPlayerName[ MAX_DECORATED_PLAYER_NAME_LENGTH ]; wchar_t wszHealthText[ 10 ]; bool bShowHealth = false; bool bShowPlayerName = false; // Some entities we always want to check, cause the text may change // even while we're looking at it // Is it a player? if ( IsPlayerIndex( iEntIndex ) ) { // check player because they may have been endeadend if ( pPlayer ) { bShowPlayerName = true; if ( pPlayer->IsOtherSameTeam( pLocalPlayer->GetTeamNumber() ) && !pPlayer->IsOtherEnemy( pLocalPlayer->entindex() ) ) { printFormatString = ( bShowFriendEnemyDesignation ) ? "#SFUIHUD_playerid_sameteam" : "#SFUIHUD_playerid_specteam"; bShowFriendlyCrosshair = bFriendlyCrosshairOkay; bShowHealth = true; } else if ( pLocalPlayer->GetTeamNumber() != TEAM_CT && pLocalPlayer->GetTeamNumber() != TEAM_TERRORIST ) { printFormatString = "#SFUIHUD_playerid_noteam"; bShowFriendlyCrosshair = bFriendlyCrosshairOkay; bShowHealth = true; } else { printFormatString = ( bShowFriendEnemyDesignation ) ? "#SFUIHUD_playerid_diffteam" : "#SFUIHUD_playerid_specteam"; bShowFriendlyCrosshair = false; bWantEnemyCrosshair = bShowFriendEnemyDesignation; if ( bWantEnemyCrosshair && bCheckWeaponRange ) { CWeaponCSBase *pWeapon = ( CWeaponCSBase* )pCSPlayer->GetActiveWeapon(); if ( pWeapon ) { float flWeaponRange = pWeapon->GetCSWpnData().GetRange(); vec_t length = VectorLength( pPlayer->WorldSpaceCenter() - pLocalPlayer->Weapon_ShootPosition() ); bWantEnemyCrosshair = ( length <= flWeaponRange ); } } } // only get the name and health if necessary if ( !( cl_teamid_overhead.GetInt() && bShowFriendlyCrosshair ) ) { C_CS_PlayerResource *cs_PR = dynamic_cast( g_PR ); if ( cs_PR ) { cs_PR->GetDecoratedPlayerName( iEntIndex, wszPlayerName, sizeof( wszPlayerName ), k_EDecoratedPlayerNameFlag_AddBotToNameIfControllingBot ); } else { wszPlayerName[0] = L'\0'; } if ( bShowHealth ) { float flHealth = MAX( 0.0f, ( float )pPlayer->GetHealth() ); V_snwprintf( wszHealthText, ARRAYSIZE( wszHealthText ) - 1, L"%.0f%%", ( flHealth / ( float )pPlayer->GetMaxHealth() ) * 100 ); wszHealthText[ ARRAYSIZE( wszHealthText )-1 ] = '\0'; } } else { wszPlayerName[0] = L'\0'; } } } else { C_BaseEntity *pEnt = cl_entitylist->GetEnt( iEntIndex ); //Hostages! C_CHostage *pHostage = NULL; for( int i=0;iGetHealth() ); V_snwprintf( wszHealthText, ARRAYSIZE( wszHealthText ) - 1, L"%.0f%%", ( flHealth / ( float )pHostage->GetMaxHealth() ) * 100 ); wszHealthText[ ARRAYSIZE( wszHealthText )-1 ] = '\0'; bShowFriendlyCrosshair = bFriendlyCrosshairOkay; bShowHealth = mp_hostages_takedamage.GetBool(); bIsHostage = true; Vector forward, up; pLocalPlayer->EyeVectors( &forward, NULL, &up ); trace_t tr; // Search for objects in a sphere (tests for entities that are not solid, yet still useable) Vector searchCenter = pLocalPlayer->EyePosition(); int useableContents = MASK_NPCSOLID_BRUSHONLY | MASK_OPAQUE_AND_NPCS; UTIL_TraceLine( searchCenter, searchCenter + forward * 1024, useableContents, pLocalPlayer, COLLISION_GROUP_NONE, &tr ); if ( tr.m_pEnt ) { CConfigurationForHighPriorityUseEntity_t cfgUseHostageRule; bool bValidHostageRule = pLocalPlayer->GetUseConfigurationForHighPriorityUseEntity( pHostage, cfgUseHostageRule ); // if we're outside use range, we're a terrorist or the hostage has a leader and it's not the player... if ( !bValidHostageRule || !cfgUseHostageRule.UseByPlayerNow( pLocalPlayer, cfgUseHostageRule.k_EPlayerUseType_Start ) || pLocalPlayer->GetTeamNumber() == TEAM_TERRORIST || (pHostage->GetLeader() && pHostage->GetLeader() != pLocalPlayer) || (HOSTAGE_RULE_CAN_PICKUP && pLocalPlayer->m_hCarriedHostage != NULL) ) { if ( pHostage->GetLeader() && pHostage->GetLeader() != pLocalPlayer) { if ( !bShowHealth ) printFormatString = "#SFUIHUD_hostageid_nh_following"; else printFormatString = "#SFUIHUD_hostageid_following"; C_CS_PlayerResource *cs_PR = dynamic_cast( g_PR ); char szClan[MAX_PLAYER_NAME_LENGTH]; g_pVGuiLocalize->ConvertANSIToUnicode( szClan, wszClanTag, sizeof( wszClanTag ) ); if ( cs_PR ) { cs_PR->GetDecoratedPlayerName( pHostage->GetLeader()->entindex(), wszPlayerName, sizeof( wszPlayerName ), k_EDecoratedPlayerNameFlag_AddBotToNameIfControllingBot ); } else { wszPlayerName[0] = L'\0'; } bShowPlayerName = true; } else { if ( !bShowHealth ) { //SFUIHUD_hostagename_nh if ( CSGameRules()->IsPlayingCooperativeGametype() ) { bShowPlayerName = true; g_pVGuiLocalize->ConstructString( wszPlayerName, sizeof( wszPlayerName ), g_pVGuiLocalize->Find( pHostage->GetCustomHostageNameForMap( engine->GetLevelNameShort() ) ), 0 ); printFormatString = "#SFUIHUD_hostagename_nh"; } else printFormatString = "#SFUIHUD_hostageid_nh"; } else printFormatString = "#SFUIHUD_hostageid"; } } else { if ( pHostage->GetLeader() == pLocalPlayer ) { // if ( !bShowHealth ) // printFormatString = "#SFUIHUD_hostageid_nh_use_leave"; // else // printFormatString = "#SFUIHUD_hostageid_use_leave"; } else if ( !pHostage->GetLeader() ) { if ( !bShowHealth ) printFormatString = "#SFUIHUD_hostageid_nh_use_lead"; else printFormatString = "#SFUIHUD_hostageid_use_lead"; } } } } } if ( printFormatString ) { if ( cl_teamid_overhead.GetInt() && bShowFriendlyCrosshair && !bIsHostage ) { Vector vDelta = pPlayer->EyePosition() - pLocalPlayer->EyePosition(); float flDistance = vDelta.Length(); if ( pPlayer->IsOtherSameTeam( pLocalPlayer->GetTeamNumber() ) && !pPlayer->IsOtherEnemy( pLocalPlayer->entindex() ) && pPlayer->IsBot() && pPlayer->HasC4() && flDistance < PLAYER_USE_BOT_RADIUS ) { g_pVGuiLocalize->ConstructString( wcNewString, sizeof( wcNewString ), g_pVGuiLocalize->Find( "#SFUIHUD_botid_request_bomb" ), 0 ); bForceShowCenterID = true; } else { V_snwprintf( wcNewString, ARRAYSIZE( wcNewString ), L"" ); bShowBlankXHairID = true; } displayingTargetID = true; } else { displayingTargetID = true; if ( bShowPlayerName && bShowHealth ) { g_pVGuiLocalize->ConstructString( wcNewString, sizeof( wcNewString ), g_pVGuiLocalize->Find( printFormatString ), 2, wszPlayerName, wszHealthText ); } else if ( bShowPlayerName ) { g_pVGuiLocalize->ConstructString( wcNewString, sizeof( wcNewString ), g_pVGuiLocalize->Find( printFormatString ), 1, wszPlayerName ); } else if ( bShowHealth ) { g_pVGuiLocalize->ConstructString( wcNewString, sizeof( wcNewString ), g_pVGuiLocalize->Find( printFormatString ), 1, wszHealthText ); } else { g_pVGuiLocalize->ConstructString( wcNewString, sizeof( wcNewString ), g_pVGuiLocalize->Find( printFormatString ), 0 ); } } } } if ( !displayingTargetID && bShowDroppedWeaponNames ) { int weaponEntIndex = pCSPlayer->GetTargetedWeapon(); if ( weaponEntIndex > 0 ) //0 is a valid entity index, but will never be used for a weapon { C_BaseEntity *pEnt = cl_entitylist->GetEnt( weaponEntIndex ); C_PlantedC4 *pC4 = dynamic_cast( pEnt ); if ( !pC4 ) { CWeaponCSBase* weapon = static_cast( pEnt ); bool isWeaponAllowed = ( weapon && ( !weapon->IsA(WEAPON_TASER) /* || weapon->HasAnyAmmo()*/ ) ); // we allow players to pick up guns without ammo --mtw CEconItemView *pItem = weapon->GetEconItemView(); wchar_t wcTargetWeaponFormatted[128]; if ( pItem && pItem->IsValid() ) { const CEconItemRarityDefinition* pRarity = GetItemSchema()->GetRarityDefinition( pItem->GetRarity() ); const int kColorBufSize = 128; wchar_t rwchColor[kColorBufSize]; Q_UTF8ToUnicode( GetHexColorForAttribColor( pRarity->GetAttribColor() ), rwchColor, kColorBufSize ); // Update target name V_snwprintf( wcTargetWeaponFormatted, ARRAYSIZE( wcTargetWeaponFormatted ), L"" PRI_WS_FOR_WS L"", rwchColor, pItem->GetItemName( true ) ); } else { V_snwprintf( wcTargetWeaponFormatted, ARRAYSIZE( wcTargetWeaponFormatted ), PRI_WS_FOR_WS, g_pVGuiLocalize->Find( weapon->GetPrintName() ) ); } //const char* szWeaponPrintName = ( pItem ? pItem->GetItemDefinition()->GetItemBaseName() : weapon->GetPrintName() ); if ( isWeaponAllowed && wcTargetWeaponFormatted ) { displayingTargetID = true; CSWeaponType nType = weapon->GetWeaponType(); if ( pCSPlayer->IsPrimaryOrSecondaryWeapon( nType ) ) { // check to see if we are swapping weapons or if we are just filling in an empty weapon slot bool bSwap = false; if ( (nType == WEAPONTYPE_PISTOL && pCSPlayer->Weapon_GetSlot( WEAPON_SLOT_PISTOL )) || ( nType != WEAPONTYPE_PISTOL && pCSPlayer->Weapon_GetSlot( WEAPON_SLOT_RIFLE ) ) ) bSwap = true; if ( bSwap ) { //const wchar_t* wszWeaponText = g_pVGuiLocalize->Find( szWeaponPrintName ); g_pVGuiLocalize->ConstructString( wcNewString, sizeof( wcNewString ), g_pVGuiLocalize->Find( "#SFUIHUD_weaponid_pickup" ), 1, wcTargetWeaponFormatted ); } else { V_snwprintf( wcNewString, ARRAYSIZE( wcNewString ), PRI_WS_FOR_WS, wcTargetWeaponFormatted ); } } else { V_snwprintf( wcNewString, ARRAYSIZE( wcNewString ), PRI_WS_FOR_WS, wcTargetWeaponFormatted ); displayingTargetID = true; } } } } } } } // player ID FOR_EACH_VEC( m_playerIDs, i ) { m_playerIDs[i].bActive = false; } { MDLCACHE_CRITICAL_SECTION(); bool bIsPauseMenuActive = ( BasePanel() && BasePanel()->IsScaleformPauseMenuActive() ); bool bShowAllNamesForSpec = (bLocalIsSpectatorViewer && spec_show_xray.GetInt()); for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { if ( bIsPauseMenuActive ) break; //TODO: check whether they are an enemy as well CCSPlayer* pOtherPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) ); bool bTurnedOff = false; if ( cl_teamid_overhead.GetBool() == false || cl_draw_only_deathnotices.GetBool() == true ) bTurnedOff = true; if ( bTurnedOff || !pLocalPlayer || !pOtherPlayer || !pOtherPlayer->IsAlive( ) || !pOtherPlayer->IsVisible( ) || ( pOtherPlayer == pCSPlayer && !input->CAM_IsThirdPersonOverview( ) ) ) continue; if ( g_HltvReplaySystem.GetHltvReplayDelay() ) continue; // in replay, there's a clear indication of "You". People seem to not care about the other labels that add to visual noise. static ConVarRef sv_show_voip_indicator_for_enemies( "sv_show_voip_indicator_for_enemies" ); if ( bShowAllNamesForSpec || (pCSPlayer->IsOtherSameTeam( pOtherPlayer->GetTeamNumber() ) && !pCSPlayer->IsOtherEnemy( pOtherPlayer ) ) || ( sv_show_voip_indicator_for_enemies.GetBool() && pOtherPlayer->IsPlayerTalkingOverVOIP() ) ) { bool bSameTeam = pLocalPlayer->InSameTeam( pOtherPlayer ); bool bIsEnemy = pLocalPlayer->IsOtherEnemy( pOtherPlayer ); Vector vDelta = pOtherPlayer->EyePosition() - pCSPlayer->EyePosition(); float flDistance = vDelta.Length(); // get our spectator target int nTargetSpec = g_bEngineIsHLTV ? HLTVCamera()->GetCurrentOrLastTarget() : (pLocalPlayer->GetObserverTarget() ? pLocalPlayer->GetObserverTarget()->entindex() : -1); // max distance to draw the names is different depending on whether we are on team spectator or not float flMaxDrawDist = bShowAllNamesForSpec ? cl_teamid_overhead_maxdist_spec.GetInt() : cl_teamid_overhead_maxdist.GetInt(); // always show the name for the player who is our target when roaming if ( bShowAllNamesForSpec && nTargetSpec == pOtherPlayer->entindex() && (pLocalPlayer->GetObserverMode() == OBS_MODE_FIXED || pLocalPlayer->GetObserverMode() == OBS_MODE_ROAMING) ) flMaxDrawDist = 99999.9f; if ( flDistance <= flMaxDrawDist ) { Vector vecOtherPlayerEyes = pOtherPlayer->EyePosition() + Vector( 0, 0, 3 ); // other player is close enough, now make sure the local player is facing the other player. Vector vecOtherPlayerPos = pOtherPlayer->EyePosition(); Vector forward; AngleVectors(pCSPlayer->EyeAngles(), &forward, NULL, NULL); Vector toAimSpot = vecOtherPlayerEyes - pCSPlayer->EyePosition(); float rangeToEnemy = toAimSpot.NormalizeInPlace(); float flTargetIDCone = DotProduct( toAimSpot, forward ); const float flViewCone = 0.5f; bool bPlayerIsNotVisible = false; // trace against world for enemies or if client doesn't want team id everywhere+ { // if we can't trace to the player or if they are obscured by smoke, skip them CBasePlayer *lastPlayerHit = NULL; trace_t tr; if ( pCSPlayer->IsAlive( ) && ( flTargetIDCone > flViewCone ) && !bShowAllNamesForSpec ) { if ( LineGoesThroughSmoke( pCSPlayer->EyePosition(), vecOtherPlayerEyes, 1.0f ) ) { if ( !ShouldShowAllFriendlyTargetIDs() || pCSPlayer->IsOtherEnemy( pOtherPlayer ) ) { continue; } else { bPlayerIsNotVisible = true; } } UTIL_TraceLine( pCSPlayer->EyePosition(), vecOtherPlayerEyes, MASK_VISIBLE, pCSPlayer, COLLISION_GROUP_DEBRIS, &tr ); { CTraceFilterSkipTwoEntities filter( pCSPlayer, lastPlayerHit, COLLISION_GROUP_DEBRIS ); // Check for player hitboxes extending outside their collision bounds const float rayExtension = 40.0f; UTIL_ClipTraceToPlayers( pCSPlayer->EyePosition(), vecOtherPlayerEyes + forward * rayExtension, MASK_VISIBLE, &filter, &tr ); if ( tr.fraction < 1 ) { if ( !ShouldShowAllFriendlyTargetIDs() || pCSPlayer->IsOtherEnemy( pOtherPlayer ) ) { continue; } else { bPlayerIsNotVisible = true; } } } } } // aiming tolerance depends on how close the target is - closer targets subtend larger angles float aimTolerance = 0.6f; //(float)cos( atan( 256 / rangeToEnemy ) ); int index = 0; bool bExists = false; // let's do this! if ( bShowAllNamesForSpec || flTargetIDCone > flViewCone ) { FOR_EACH_VEC( m_playerIDs, j ) { if ( m_playerIDs[j].hPlayer.Get() == pOtherPlayer ) { index = j; bExists = true; m_playerIDs[j].bActive = true; break; } } int nIDIndex = pCSPlayer->GetIDTarget(); //Msg( "ID Index = %d\n", nIDIndex ); C_BaseEntity *pIDEnt = cl_entitylist->GetEnt( nIDIndex ); bool bShowIDName = CSGameRules()->IsFreezePeriod() || bShowAllNamesForSpec || ((pIDEnt == pOtherPlayer || !pCSPlayer->IsAlive()) && bSameTeam && !bIsEnemy); if ( !bExists ) { index = m_playerIDs.Count(); bExists = true; bool bFriend = false; C_CS_PlayerResource *cs_PR = dynamic_cast( g_PR ); if ( cs_PR ) { XUID nOtherXUID = cs_PR->GetXuid( pOtherPlayer->entindex() ); if ( g_pMatchFramework->GetMatchSystem()->GetPlayerManager()->GetFriendByXUID( nOtherXUID ) ) { bFriend = true; } } AddNewPlayerID( pOtherPlayer, bShowIDName, bFriend ); } if ( m_playerIDs.Count() > 0 && index < m_playerIDs.Count() ) { // update the team number m_playerIDs[index].nTeam = pOtherPlayer->GetTeamNumber(); bool bFlashedChanged = bLocalIsSpectatorViewer ? (m_playerIDs[index].bFlashedAmt != pOtherPlayer->m_flFlashOverlayAlpha) : false; bool bHealthChanged = (m_playerIDs[index].nHealth != pOtherPlayer->GetHealth()); bool bUpdateNow = (m_playerIDs[index].flUpdateAt != 0 && m_playerIDs[index].flUpdateAt <= gpGlobals->curtime ); if ( bExists && ( /*CSGameRules()->IsFreezePeriod() ||*/ bUpdateNow || bHealthChanged || bFlashedChanged || m_playerIDs[index].bShowName != bShowIDName) ) { if ( bShowIDName == false && m_playerIDs[index].bShowName == true ) { m_playerIDs[index].flLastHighlightTime = gpGlobals->curtime; } if ( CSGameRules()->IsFreezePeriod() ) // update again in a bit if we're still in freeze time m_playerIDs[index].flUpdateAt = gpGlobals->curtime + 0.5f; else m_playerIDs[index].flUpdateAt = 0; m_playerIDs[index].bShowName = bShowIDName; m_playerIDs[index].nHealth = pOtherPlayer->GetHealth(); UpdatePlayerID( pOtherPlayer, index, true ); } WITH_SLOT_LOCKED { float flScale = clamp( (float)atan( 512 / (rangeToEnemy*1.0) ), 0.6, 2 ); float flAlp = clamp( 1 - (rangeToEnemy / (flMaxDrawDist*0.75)), 0.25, 1 ); //Msg( "scale = %f, rangeToEnemy = %f\n", flScale, rangeToEnemy ); // adjust scale by the screen size flScale *= clamp( 1-(600.0f/(float)ScreenHeight()), 0.25, 1 ); float flFadeRangeClose = 160; if ( rangeToEnemy < flFadeRangeClose && !bShowIDName ) { flAlp *= MAX( 0.25, (rangeToEnemy-(flFadeRangeClose*0.35))/(flFadeRangeClose*0.55) ); } float flFadeEdge = (1-aimTolerance)*0.4; if ( flTargetIDCone < (aimTolerance+flFadeEdge) && !bShowAllNamesForSpec ) { float flFadeEdgeCur = flTargetIDCone - aimTolerance; flAlp *= MAX( 0.3, flFadeEdgeCur/flFadeEdge ); } if ( input->CAM_IsThirdPersonOverview() ) { flScale = 0.8f; flAlp = 1.0f; } // need to make sure that not only do we have a valid handle, but that the handle is of the correct type for GetType to handle it. Otherwise Scaleform just crashes..... if ( m_playerIDs[index].panel && m_pScaleformUI->Value_GetType( m_playerIDs[index].panel ) == IScaleformUI::VT_DisplayObject ) { // if the player is talking, hide the arrow and just show the talk icon if ( m_playerIDs[index].arrowA && m_playerIDs[index].arrowB && m_playerIDs[index].arrowF && m_playerIDs[index].voiceIcon && m_playerIDs[index].defuseIcon ) { bool bIsFriend = m_playerIDs[index].bFriend; bool bVoiceActive = !bPlayerIsNotVisible && ( pOtherPlayer->IsPlayerTalkingOverVOIP( ) && ( ( bSameTeam && !bIsEnemy ) || sv_show_voip_indicator_for_enemies.GetBool( ) ) && voice_icons_method.GetInt( ) == 2 ); bool bIsDefusing = !bPlayerIsNotVisible && pOtherPlayer->m_bIsDefusing; int flags = 0; flags |= bIsFriend ? 1<<0 : 0; flags |= bVoiceActive ? 1<<1 : 0; flags |= bIsDefusing ? 1<<2 : 0; if ( m_playerIDs[index].iconsFlag != flags ) { ScaleformDisplayInfo dinfoA; ScaleformDisplayInfo dinfoB; ScaleformDisplayInfo dinfoF; ScaleformDisplayInfo dinfoV; ScaleformDisplayInfo dinfoD; dinfoA.SetVisibility( !bVoiceActive && !bIsDefusing ); dinfoB.SetVisibility( !bVoiceActive && /*!bIsFriend &&*/ !bIsDefusing ); dinfoF.SetVisibility( !bVoiceActive && bIsFriend && !bIsDefusing ); dinfoV.SetVisibility( bVoiceActive ); dinfoD.SetVisibility( bIsDefusing && !bVoiceActive ); m_pScaleformUI->Value_SetDisplayInfo( m_playerIDs[index].arrowA, &dinfoA ); m_pScaleformUI->Value_SetDisplayInfo( m_playerIDs[index].arrowB, &dinfoB ); m_pScaleformUI->Value_SetDisplayInfo( m_playerIDs[index].arrowF, &dinfoF ); m_pScaleformUI->Value_SetDisplayInfo( m_playerIDs[index].voiceIcon, &dinfoV ); m_pScaleformUI->Value_SetDisplayInfo( m_playerIDs[index].defuseIcon, &dinfoD ); m_playerIDs[index].iconsFlag = flags; } } // put the indicator right over their head bool bHaveHeadBone = true; // Make sure he's all the way on screen so his bone is correct int iBIndex = -1; { iBIndex = pOtherPlayer->LookupBone( "ValveBiped.Bip01_Head" ); } if( ( iBIndex == -1 ) || !pOtherPlayer->GetBaseAnimating()->isBoneAvailableForRead( iBIndex ) ) { bHaveHeadBone = false; } Vector vecBone; if ( bHaveHeadBone ) { QAngle angBone; pOtherPlayer->GetBonePosition( iBIndex, vecBone, angBone ); } else { vecBone = (pOtherPlayer->EyePosition() - pOtherPlayer->GetAbsOrigin()) + Vector( 0.0f, 0.0f, 20 ); } int iX, iY; GetVectorInScreenSpace( vecBone + Vector( 0, 0, 9 ), iX, iY ); //GetTargetInScreenSpace( pFoundEnt, iX, iY ); ScaleformDisplayInfo dinfo; dinfo.SetVisibility( true ); dinfo.SetAlpha( 140 * flAlp ); dinfo.SetX( iX ); dinfo.SetY( iY ); dinfo.SetXScale( 240 * flScale ); dinfo.SetYScale( 240 * flScale ); m_pScaleformUI->Value_SetDisplayInfo( m_playerIDs[index].panel, &dinfo ); } } } } } } } } // End MDLCACHE_CRITICAL_SECTION() // Don't remove players at this point in order to void adding them again (causing spikes) FOR_EACH_VEC( m_playerIDs, k ) { if ( m_playerIDs[ k ].bActive == false ) { //RemoveID( k ); m_pScaleformUI->Value_SetVisible( m_playerIDs[ k ].panel, false ); } } if ( !ShouldShowAllFriendlyEquipment() ) { FOR_EACH_VEC( m_playerIDs, l ) { float flTimeToFadeOut = cl_teamid_overhead_name_fadetime.GetFloat(); float flExpireTime = m_playerIDs[l].flLastHighlightTime + flTimeToFadeOut; int nMaxAlpha = cl_teamid_overhead_name_alpha.GetInt(); if ( m_playerIDs[l].bActive && m_playerIDs[l].bShowName == false && m_playerIDs[l].flNameAlpha > 0 ) { float frac = ( flExpireTime - gpGlobals->curtime ) / flTimeToFadeOut; int alpha = frac * nMaxAlpha; SFVALUE animatedID = m_pScaleformUI->Value_GetMember( m_playerIDs[l].panel, "IDClip" ); SFVALUE textBG = m_pScaleformUI->Value_GetMember( m_playerIDs[l].panel, "IDTextBG" ); if ( animatedID /*&& animatedIDDrop*/ && textBG ) { SFVALUE textmovie = m_pScaleformUI->Value_GetMember( animatedID, "IDTextMovie" ); if ( textmovie /*&& textDrop*/ ) { ScaleformDisplayInfo dinfo; ScaleformDisplayInfo dinfo2; dinfo.SetAlpha( alpha ); dinfo2.SetAlpha( alpha/7 ); if ( alpha <= 0 || frac <= 0 ) { alpha = 0; dinfo.SetVisibility( false ); dinfo2.SetVisibility( false ); } m_playerIDs[l].flNameAlpha = MAX( 0, alpha ); m_pScaleformUI->Value_SetDisplayInfo( textmovie, &dinfo ); m_pScaleformUI->Value_SetDisplayInfo( textBG, &dinfo2 ); SafeReleaseSFVALUE( textmovie ); } SafeReleaseSFVALUE( animatedID ); SafeReleaseSFVALUE( textBG ); } } } } // now do all the stuff that might lock the slot //0 = default //1 = default static //2 = classic standard //3 = classic dynamic //4 = classic static if ( cl_crosshairstyle.GetInt() >= 2 ) //if ( !sfcrosshair.GetBool() ) { iDesiredReticleMode = RETICLE_MODE_NONE; } bool bSlotIsLocked = false; if ( displayingTargetID && (wcNewString[0] || bShowBlankXHairID) ) { // this updates the text if necessary if ( V_wcscmp( wcNewString, m_wcIDString ) ) { LockSlot( true, bSlotIsLocked ); m_pScaleformUI->Value_SetTextHTML( m_IDText, m_pScaleformUI->ReplaceGlyphKeywordsWithHTML( wcNewString ) ); V_wcsncpy( m_wcIDString, wcNewString, TEXTFIELD_LENGTH*sizeof( wchar_t ) ); } // this shows/hides the friendly crosshair if ( m_FriendCrosshair && ( bShowFriendlyCrosshair != m_bFriendlyCrosshairVisible ) ) { LockSlot( true, bSlotIsLocked ); m_pScaleformUI->Value_SetVisible( m_FriendCrosshair, bShowFriendlyCrosshair ); m_bFriendlyCrosshairVisible = bShowFriendlyCrosshair; } // update the timer ( which turns the text field off after quarter a second m_fIDTimer = gpGlobals->curtime + 0.25f; // call the text field's show animation if it isn't already visible if ( !m_bTextIDVisible && (bForceShowCenterID || cl_teamid_overhead.GetInt() == 0 || (cl_teamid_overhead.GetInt() > 0 && !bShowFriendlyCrosshair) || bIsHostage) ) { LockSlot( true, bSlotIsLocked ); m_pScaleformUI->Value_InvokeWithoutReturn( m_IDMovie, "Show", NULL, 0 ); m_bTextIDVisible = true; } } else { // hide the friendly crosshair since we're not looking at anything anymore if ( m_bFriendlyCrosshairVisible ) { LockSlot( true, bSlotIsLocked ); m_pScaleformUI->Value_SetVisible( m_FriendCrosshair, false ); m_bFriendlyCrosshairVisible = false; } // once our timer has run out, call the hide animation for the text if ( m_bTextIDVisible && gpGlobals->curtime >= m_fIDTimer ) { LockSlot( true, bSlotIsLocked ); m_pScaleformUI->Value_InvokeWithoutReturn( m_IDMovie, "Hide", NULL, 0 ); m_bTextIDVisible = false; } } if ( bWantEnemyCrosshair != m_bEnemyCrosshairVisible ) { m_bEnemyCrosshairVisible = bWantEnemyCrosshair; float colorIndex = 99; if ( !bWantEnemyCrosshair ) { ConVarRef convar( "cl_crosshaircolor" ); colorIndex = convar.GetFloat(); } WITH_SFVALUEARRAY_SLOT_LOCKED( args, 1 ) { m_pScaleformUI->ValueArray_SetElement( args, 0, colorIndex ); g_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "onUpdateColor", args, 1 ); } } if ( iDesiredReticleMode != m_iReticleMode ) { LockSlot( true, bSlotIsLocked ); ShowReticle( m_iReticleMode, false ); ShowReticle( iDesiredReticleMode, true ); m_iReticleMode = iDesiredReticleMode; } if ( m_iReticleMode == RETICLE_MODE_WEAPON ) { float x = 0.0f; float y = 0.0f; #ifdef SIXENSE if( g_pSixenseInput->IsEnabled() && C_BasePlayer::GetLocalPlayer() && ( C_BasePlayer::GetLocalPlayer()->GetObserverMode()==OBS_MODE_NONE ) && lockMoveControllerRet.GetBool() == false ) #else if ( inputsystem->MotionControllerActive() && C_BasePlayer::GetLocalPlayer() && ( C_BasePlayer::GetLocalPlayer()->GetObserverMode()==OBS_MODE_NONE ) && lockMoveControllerRet.GetBool() == false ) #endif { Vector aimDirection; if ( mc_use_recoil_on_cursor.GetBool()) { AngleVectors(pCSPlayer->GetFinalAimAngle(), &aimDirection); } else { aimDirection = pCSPlayer->GetAimDirection(); } Vector screen; Vector point; VectorAdd( CurrentViewOrigin(), aimDirection, point ); ScreenTransform( point, screen ); x = 0.5f * screen[0] * ScreenWidth() + 0.5f; y = -0.5f * screen[1] * ScreenHeight() + 0.5f; } //0 = default //1 = default static //2 = classic standard //3 = classic dynamic //4 = classic static if ( cl_crosshairstyle.GetInt() == 1 ) { fDesiredFishtail = 0; } SetReticlePosition( iDesiredSpread, iDesiredGap, x, y, ( fDesiredFishtail / 200.0f ) * ( ScreenWidth() * 0.5f ) ); } LockSlot( false, bSlotIsLocked ); } void SFHudReticle::ToggleTeamEquipmentVisibility( bool bShow ) { m_bForceShowAllTeammateTargetIDs = bShow; for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CCSPlayer* pCSPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) ); FOR_EACH_VEC( m_playerIDs, j ) { if ( m_playerIDs[ j ].hPlayer.Get( ) == pCSPlayer ) { UpdatePlayerID( pCSPlayer, j ); } } } } void SFHudReticle::AddNewPlayerID( CBaseEntity *player, bool bShowName, bool bFriend ) { if ( !FlashAPIIsValid() ) return; if ( !player || m_playerIDs.Count() >= MAX_PLAYER_NAME_ID_PANELS ) return; SFVALUE newPanelHandle = NULL; WITH_SLOT_LOCKED { //Create new panel newPanelHandle = m_pScaleformUI->Value_Invoke( m_FlashAPI, "AddNewPlayerID", NULL, 0 ); } if ( newPanelHandle ) { //Put the new panel in the list PlayerIDPanel newPanel; newPanel.hPlayer = player; newPanel.panel = newPanelHandle; newPanel.bActive = true; newPanel.bFriend = bFriend; newPanel.nHealth = player->GetHealth(); newPanel.nTeam = player->GetTeamNumber(); newPanel.flNameAlpha = 0; newPanel.flLastHighlightTime = 0; newPanel.bShowName = false; newPanel.flUpdateAt = 0; newPanel.iconsFlag = -1; newPanel.bFlashedAmt = -1;// we will hide the panel immediately if ( m_pScaleformUI->Value_GetType( newPanelHandle ) == IScaleformUI::VT_DisplayObject ) { newPanel.arrowA = m_pScaleformUI->Value_GetMember( newPanelHandle, "IDArrow" ); newPanel.arrowB = m_pScaleformUI->Value_GetMember( newPanelHandle, "IDArrowBorder" ); newPanel.arrowF = m_pScaleformUI->Value_GetMember( newPanelHandle, "IDArrowFriend" ); newPanel.voiceIcon = m_pScaleformUI->Value_GetMember( newPanelHandle, "iconChat" ); newPanel.defuseIcon = m_pScaleformUI->Value_GetMember( newPanelHandle, "DefuseKitIcon" ); } else { newPanel.arrowA = NULL; newPanel.arrowB = NULL; newPanel.arrowF = NULL; newPanel.voiceIcon = NULL; newPanel.defuseIcon = NULL; } m_playerIDs.AddToTail( newPanel ); UpdatePlayerID( player, m_playerIDs.Count()-1 ); } } void SFHudReticle::UpdatePlayerID( CBaseEntity *player, int slot, bool bHealthAndNameOnly ) { if ( !FlashAPIIsValid() ) return; C_CSPlayer *pCSPlayer = C_CSPlayer::GetLocalCSPlayer(); if ( !pCSPlayer || !player || m_playerIDs.Count() >= MAX_PLAYER_NAME_ID_PANELS || slot >= m_playerIDs.Count() ) return; bool bDidSetName = false; if ( !m_playerIDs[slot].panel ) { Warning( "AddNewPlayerID called and updated in sfhudreticle, but m_playerIDs[slot].panel is null!!\n" ); return; } C_CS_PlayerResource *cs_PR = dynamic_cast( g_PR ); if ( !bHealthAndNameOnly ) { int playerIndex = 0; for ( int i = 0; i <= MAX_PLAYERS; i++ ) { CBasePlayer* pCheckPlayer = UTIL_PlayerByIndex( i ); if ( pCheckPlayer && pCheckPlayer == player ) playerIndex = i; } int nColorID = -1; if ( cs_PR && pCSPlayer->ShouldShowTeamPlayerColors( player->GetTeamNumber() ) ) nColorID = cs_PR->GetCompTeammateColor( playerIndex ); // set the color of the icon, need to do it by calling the script WITH_SFVALUEARRAY_SLOT_LOCKED( args, 4 ) { m_pScaleformUI->ValueArray_SetElement( args, 0, m_playerIDs[slot].panel ); m_pScaleformUI->ValueArray_SetElement( args, 1, m_playerIDs[slot].nTeam ); m_pScaleformUI->ValueArray_SetElement( args, 2, m_playerIDs[slot].bFriend ); m_pScaleformUI->ValueArray_SetElement( args, 3, nColorID ); m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "setIDTeamColor", args, 4 ); } } if ( !cs_PR ) { Warning( "AddNewPlayerID called and updated in sfhudreticle, but C_CS_PlayerResource is null!!\n" ); return; } SFVALUE animatedID = m_pScaleformUI->Value_GetMember( m_playerIDs[slot].panel, "IDClip" ); SFVALUE textBG = m_pScaleformUI->Value_GetMember( m_playerIDs[slot].panel, "IDTextBG" ); if ( !animatedID /*&& animatedIDDrop*/ || !textBG ) { Warning( "AddNewPlayerID called and updated in sfhudreticle, but IDClip and IDTextBG objects are null!!\n" ); return; } SFVALUE textmovie = m_pScaleformUI->Value_GetMember( animatedID, "IDTextMovie" ); if ( !textmovie /*&& textDrop*/ ) { Warning( "AddNewPlayerID called and updated in sfhudreticle, but IDTextMovie object is null!!\n" ); return; } SFVALUE text = m_pScaleformUI->Value_GetMember( textmovie, "IDText" ); if ( !text /*&& textDrop*/ ) { Warning( "AddNewPlayerID called and updated in sfhudreticle, but IDText object is null!!\n" ); return; } //IDWeaponTextParent SFVALUE wepIconParent = m_pScaleformUI->Value_GetMember( textmovie, "IDWeaponTextParent" ); if ( !wepIconParent ) return; SFVALUE wepIcons = m_pScaleformUI->Value_GetMember( wepIconParent, "IDWeaponText" ); if ( !wepIcons ) { Warning( "AddNewPlayerID called and updated in sfhudreticle, but IDWeaponText object is null!!\n" ); return; } wchar_t wszHealthText[ 10 ]; float flHealth = 0.0f; C_CSPlayer *pTargetPlayer = static_cast( player ); bool bLocalIsSpectatorViewer = CanSeeSpectatorOnlyTools(); bool bShowMoneyInsteadOfHealth = CSGameRules( )->CanSpendMoneyInMap( ) && CSGameRules( )->IsFreezePeriod( ) && !bLocalIsSpectatorViewer; if ( bShowMoneyInsteadOfHealth ) // we show money in the place of health during freeze time flHealth = pTargetPlayer->GetAccount( ); else flHealth = ( MAX( 0.0f, ( float ) player->GetHealth( ) ) / ( float ) player->GetMaxHealth( ) ); // show the main equipped weapon, grenades and money during freezetime or if ShouldShowAllFriendlyEquipment if ( ( !bLocalIsSpectatorViewer && ( CSGameRules( )->IsFreezePeriod( ) ) || ShouldShowAllFriendlyEquipment() ) ) { CHudWeaponSelection *pHudSelection = (CHudWeaponSelection *)GET_HUDELEMENT( CHudWeaponSelection ); if ( !pHudSelection ) return; wchar_t wszWeaponIcons[ MAX_DECORATED_PLAYER_NAME_LENGTH ] = { L"" }; // weapons are only shown in freeze time. bool bShowWeapons = CSGameRules( )->IsFreezePeriod( ) || ShouldShowAllFriendlyEquipment(); bool bShowDefuser = ShouldShowAllFriendlyEquipment(); bool bShowC4 = ShouldShowAllFriendlyEquipment(); CSWeaponID nPrimaryWeaponID = WEAPON_KNIFE; if ( bShowWeapons ) { if ( pTargetPlayer && pTargetPlayer->GetActiveCSWeapon( ) ) { if ( !IsPrimaryWeapon( nPrimaryWeaponID )/* && CSGameRules()->IsFreezePeriod()*/ ) { // While in the freeze period we want to show their primary weapon if they have one for ( int i = 0; i < MAX_WEAPONS; i++ ) { C_WeaponCSBase *pWeapon = assert_cast< C_WeaponCSBase* >( pTargetPlayer->GetWeapon( i ) ); if ( !pWeapon ) continue; CSWeaponID nIDTemp = pWeapon->GetCSWeaponID( ); if ( IsPrimaryWeapon( nIDTemp ) ) { // Found a primary nPrimaryWeaponID = nIDTemp; break; } else if ( IsSecondaryWeapon( nIDTemp ) ) { // Fall back to secondary if non-primary and non-secondary is active nPrimaryWeaponID = nIDTemp; } } } } } // let's wait on showing armor and defuse kits // int nArmor = cs_PR->GetArmor( pTargetPlayer->entindex() ); // bool bHasHelmet = cs_PR->HasHelmet( pTargetPlayer->entindex() ); // // if ( nArmor > 0 ) // { // const char *szWeapon = "armor"; // if ( bHasHelmet ) // szWeapon = "armor_helmet"; // // wchar_t wszWeapon[64]; // V_UTF8ToUnicode( szWeapon, wszWeapon, sizeof( wszWeapon ) ); // wchar_t szWeaponHTML[64]; // GetIconHTML( wszWeapon, szWeaponHTML, ARRAYSIZE( szWeaponHTML ), true ); // Q_wcsncat( wszWeaponIcons, szWeaponHTML, sizeof( wszWeaponIcons ), COPY_ALL_CHARACTERS ); // } // if ( bShowDefuser ) { bool bHasDef = cs_PR->HasDefuser( pTargetPlayer->entindex( ) ); if ( bHasDef ) { wchar_t wszWeapon[ 64 ]; V_UTF8ToUnicode( "defuser", wszWeapon, sizeof( wszWeapon ) ); wchar_t szWeaponHTML[ 64 ]; GetIconHTML( wszWeapon, szWeaponHTML, ARRAYSIZE( szWeaponHTML ), true ); Q_wcsncat( wszWeaponIcons, szWeaponHTML, sizeof( wszWeaponIcons ), COPY_ALL_CHARACTERS ); } } if ( bShowC4 ) { bool bHasC4 = cs_PR->HasC4( pTargetPlayer->entindex( ) ); if ( bHasC4 ) { wchar_t wszWeapon[ 64 ]; V_UTF8ToUnicode( "bomb-holder", wszWeapon, sizeof( wszWeapon ) ); wchar_t szWeaponHTML[ 64 ]; GetIconHTML( wszWeapon, szWeaponHTML, ARRAYSIZE( szWeaponHTML ), true ); Q_wcsncat( wszWeaponIcons, szWeaponHTML, sizeof( wszWeaponIcons ), COPY_ALL_CHARACTERS ); } } for ( int slot = MAX_WEAPON_SLOTS; slot >= 0; slot-- ) { for ( int pos = MAX_WEAPON_POSITIONS; pos >= 0; pos-- ) { C_WeaponCSBase *pWeapon = assert_cast< C_WeaponCSBase* >( pHudSelection->GetWeaponInSlotForTarget( pTargetPlayer, slot, pos ) ); // if we dont have a weapon OR if the found weapon is our selected weapon, skip it if ( !pWeapon ) continue; // if we're not showing weapons ignore anything that isn't utility if ( !bShowWeapons && !pWeapon->IsKindOf( WEAPONTYPE_GRENADE ) ) { continue; } // if we are showing weapons then we're only showing primary or utility else if ( pWeapon->GetCSWeaponID( ) == nPrimaryWeaponID || pWeapon->IsKindOf( WEAPONTYPE_GRENADE ) ) { CEconItemView *pItem = pWeapon->GetEconItemView( ); const char *szWeapon = ( ( pItem && pItem->IsValid() && pItem->GetItemIndex() && pItem->GetItemDefinition() ) ? pItem->GetItemDefinition( )->GetDefinitionName( ) : pWeapon->GetClassname( ) ); if ( IsWeaponClassname( szWeapon ) ) { szWeapon += WEAPON_CLASSNAME_PREFIX_LENGTH; } if ( Q_strcmp( "knife", szWeapon ) == 0 ) { if ( pTargetPlayer && pTargetPlayer->GetTeamNumber( ) == TEAM_CT ) { szWeapon = "knife_default_ct"; } else { szWeapon = "knife_default_t"; } } wchar_t wszWeapon[ 64 ]; V_UTF8ToUnicode( szWeapon, wszWeapon, sizeof( wszWeapon ) ); wchar_t szWeaponHTML[ 64 ]; GetIconHTML( wszWeapon, szWeaponHTML, ARRAYSIZE( szWeaponHTML ), true ); int nCount = 1; if ( pWeapon->IsKindOf( WEAPONTYPE_GRENADE ) ) nCount = pWeapon->GetReserveAmmoCount( AMMO_POSITION_PRIMARY ); for ( int nGren = 0; nGren < nCount; nGren++ ) { Q_wcsncat( wszWeaponIcons, szWeaponHTML, sizeof( wszWeaponIcons ), COPY_ALL_CHARACTERS ); } } } } m_pScaleformUI->Value_SetTextHTML( wepIcons, wszWeaponIcons ); } else { m_pScaleformUI->Value_SetTextHTML( wepIcons, "" ); } // bool bIsFullyBlinded = pCSPlayer->m_flFlashOverlayAlpha >= 180.0f; // bool bIsFlashed = pCSPlayer->m_flFlashBangTime > ( gpGlobals->curtime + 0.5 ); if ( pTargetPlayer ) { float flFlashFrac = 1.0 - clamp( pTargetPlayer->m_flFlashOverlayAlpha / 150, 0, 1 ); if ( pTargetPlayer->m_flFlashOverlayAlpha > 0 ) m_playerIDs[ slot ].bFlashedAmt = pTargetPlayer->m_flFlashOverlayAlpha; if ( m_playerIDs[ slot ].bFlashedAmt != 0 ) { if ( pTargetPlayer->m_flFlashOverlayAlpha <= 0 || m_playerIDs[ slot ].bFlashedAmt == -1 ) { WITH_SFVALUEARRAY_SLOT_LOCKED( args, 1 ) { m_pScaleformUI->ValueArray_SetElement( args, 0, m_playerIDs[ slot ].panel ); m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "hideFlashIcon", args, 1 ); } m_playerIDs[ slot ].bFlashedAmt = 0; } else if ( CanSeeSpectatorOnlyTools( ) ) { // show flashed WITH_SFVALUEARRAY_SLOT_LOCKED( args, 2 ) { m_pScaleformUI->ValueArray_SetElement( args, 0, m_playerIDs[ slot ].panel ); m_pScaleformUI->ValueArray_SetElement( args, 1, flFlashFrac ); m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "setFlashIcon", args, 2 ); } } } } WITH_SLOT_LOCKED { wchar_t wcNewString[ TEXTFIELD_LENGTH ]; wchar_t wszPlayerName[ MAX_DECORATED_PLAYER_NAME_LENGTH ]; const char *printFormatString = "#SFUIHUD_playerid_specteam"; // if ( pCSPlayer->ShouldShowTeamPlayerColors( player->GetTeamNumber() ) ) // { // if ( bShowOverheadWeapons && CSGameRules()->CanSpendMoneyInMap() ) // printFormatString = "#SFUIHUD_playerid_overhead_money"; // else if ( flHealth < 0.25f ) // printFormatString = "#SFUIHUD_playerid_overhead_lowhealth"; // else // printFormatString = "#SFUIHUD_playerid_overhead"; // } // else if ( m_playerIDs[slot].nTeam == TEAM_CT ) if ( m_playerIDs[slot].nTeam == TEAM_CT ) { if ( bShowMoneyInsteadOfHealth ) printFormatString = "#SFUIHUD_playerid_overhead_ct_money"; else if ( flHealth < 0.25f ) printFormatString = "#SFUIHUD_playerid_overhead_ct_lowhealth"; else printFormatString = "#SFUIHUD_playerid_overhead_ct"; } else { if ( bShowMoneyInsteadOfHealth ) printFormatString = "#SFUIHUD_playerid_overhead_t_money"; else if ( flHealth < 0.25f ) printFormatString = "#SFUIHUD_playerid_overhead_t_lowhealth"; else printFormatString = "#SFUIHUD_playerid_overhead_t"; } if ( printFormatString ) { if ( bShowMoneyInsteadOfHealth ) { V_snwprintf( wszHealthText, ARRAYSIZE( wszHealthText ) - 1, L"$%d", (int)flHealth ); } else { V_snwprintf( wszHealthText, ARRAYSIZE( wszHealthText ) - 1, L"%.0f%%", flHealth * 100 ); } wszHealthText[ ARRAYSIZE( wszHealthText )-1 ] = '\0'; cs_PR->GetDecoratedPlayerName( player->entindex(), wszPlayerName, sizeof( wszPlayerName ), k_EDecoratedPlayerNameFlag_AddBotToNameIfControllingBot ); g_pVGuiLocalize->ConstructString( wcNewString, sizeof( wcNewString ), g_pVGuiLocalize->Find( printFormatString ), 2, wszPlayerName, wszHealthText ); } m_pScaleformUI->Value_SetTextHTML( text, wcNewString ); bool bSetVisible = ShouldShowAllFriendlyEquipment() || m_playerIDs[ slot ].bShowName || m_playerIDs[ slot ].flLastHighlightTime == 0; ScaleformDisplayInfo dinfo; ScaleformDisplayInfo dinfo2; m_pScaleformUI->Value_GetDisplayInfo( textmovie, &dinfo ); m_pScaleformUI->Value_GetDisplayInfo( textBG, &dinfo2 ); bool bShowAllNamesForSpec = ( bLocalIsSpectatorViewer && spec_show_xray.GetInt() ); float flMaxDrawDist = bShowAllNamesForSpec ? cl_teamid_overhead_maxdist_spec.GetInt() : cl_teamid_overhead_maxdist.GetInt(); Vector vecOtherPlayerEyes = pTargetPlayer->EyePosition() + Vector( 0, 0, 3 ); Vector toAimSpot = vecOtherPlayerEyes - pCSPlayer->EyePosition(); float rangeToEnemy = toAimSpot.NormalizeInPlace(); float flAlp = RemapValClamped( rangeToEnemy, 500.0f, flMaxDrawDist, 100.0f, 50.0f ); m_playerIDs[ slot ].flNameAlpha = bLocalIsSpectatorViewer ? cl_teamid_overhead_name_alpha.GetInt() : flAlp; dinfo.SetAlpha( m_playerIDs[slot].flNameAlpha ); dinfo2.SetAlpha( m_playerIDs[slot].flNameAlpha/7 ); dinfo.SetVisibility( bSetVisible ); dinfo2.SetVisibility( bSetVisible ); m_pScaleformUI->Value_SetDisplayInfo( textmovie, &dinfo ); m_pScaleformUI->Value_SetDisplayInfo( textBG, &dinfo2 ); bDidSetName = true; } WITH_SLOT_LOCKED { SafeReleaseSFVALUE( wepIconParent ); SafeReleaseSFVALUE( wepIcons ); SafeReleaseSFVALUE( textmovie ); SafeReleaseSFVALUE( text ); WITH_SFVALUEARRAY( args, 1 ) { m_pScaleformUI->ValueArray_SetElement( args, 0, m_playerIDs[slot].panel ); m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "UpdateBGSize", args, 1 ); } SafeReleaseSFVALUE( animatedID ); SafeReleaseSFVALUE( textBG ); } if ( !bDidSetName ) { Warning( "AddNewPlayerID called and updated in sfhudreticle, but no name was displayed!!!!\n" ); } } void SFHudReticle::GetIconHTML( const wchar_t * szIcon, wchar_t * szBuffer, int nBufferSize, bool bSelected ) { if ( bSelected ) V_snwprintf( szBuffer, nBufferSize, HUDRET_WEPICON_SELECTED_IMG_STRING, szIcon ); else V_snwprintf( szBuffer, nBufferSize, HUDRET_WEPICON_IMG_STRING, szIcon ); } bool SFHudReticle::ShouldShowAllFriendlyTargetIDs( void ) { extern ConVar sv_teamid_overhead_always_prohibit; if ( sv_teamid_overhead_always_prohibit.GetBool() ) return false; return ( m_bForceShowAllTeammateTargetIDs || cl_teamid_overhead_always.GetInt() >= 1 ); } bool SFHudReticle::ShouldShowAllFriendlyEquipment( void ) { extern ConVar sv_show_team_equipment_prohibit; if ( sv_show_team_equipment_prohibit.GetBool() ) return false; return ( m_bForceShowAllTeammateTargetIDs || cl_teamid_overhead_always.GetInt() == 2 ); } bool SFHudReticle::SetReticlePosition( int distance, int crosshairGap, int offsetX, int offsetY, int nDesiredFishtail ) { bool bMadeChanges = false; bool bSlotIsLocked = false; if ( m_WeaponCrosshairHandle ) { ScaleformDisplayInfo dinfo; LockSlot( true, bSlotIsLocked ); //0 = default //1 = default static //2 = classic standard //3 = classic dynamic //4 = classic static if ( cl_crosshairstyle.GetInt() == 0 ) //if ( cl_dynamiccrosshair.GetBool() ) { // setting this once here will make all of these become visible dinfo.SetVisibility( true ); if ( m_crosshairDot ) { ScaleformDisplayInfo dotDisplayInfo; dotDisplayInfo.SetX( offsetX + m_dotX - nDesiredFishtail ); dotDisplayInfo.SetY( offsetY + m_dotY - nDesiredFishtail ); m_pScaleformUI->Value_SetDisplayInfo( m_crosshairDot, &dotDisplayInfo ); } if ( m_blackRing ) { ScaleformDisplayInfo blackRingDisplayInfo; blackRingDisplayInfo.SetX( offsetX + m_blackRingX ); blackRingDisplayInfo.SetY( offsetY + m_blackRingY ); m_pScaleformUI->Value_SetDisplayInfo( m_blackRing, &blackRingDisplayInfo ); } if ( m_FriendCrosshair ) { ScaleformDisplayInfo friendlyCrossHairDisplayInfo; friendlyCrossHairDisplayInfo.SetX( offsetX + m_friendIndicatorX - nDesiredFishtail ); friendlyCrossHairDisplayInfo.SetY( offsetY + m_friendIndicatorY - nDesiredFishtail ); m_pScaleformUI->Value_SetDisplayInfo( m_FriendCrosshair, &friendlyCrossHairDisplayInfo ); } //Hide the arcs if we get the sentinel value as the desired distance if ( distance == -1 ) { ScaleformDisplayInfo hideArcsDisplayInfo; hideArcsDisplayInfo.SetVisibility( false ); m_pScaleformUI->Value_SetDisplayInfo( m_topCrosshairArc, &hideArcsDisplayInfo ); m_pScaleformUI->Value_SetDisplayInfo( m_bottomCrosshairArc, &hideArcsDisplayInfo ); m_pScaleformUI->Value_SetDisplayInfo( m_leftCrosshairArc, &hideArcsDisplayInfo ); m_pScaleformUI->Value_SetDisplayInfo( m_rightCrosshairArc, &hideArcsDisplayInfo ); } else { dinfo.SetX( offsetX - nDesiredFishtail ); dinfo.SetY( - distance + offsetY ); m_pScaleformUI->Value_SetDisplayInfo( m_topCrosshairArc, &dinfo ); dinfo.SetX( distance + offsetX - nDesiredFishtail ); dinfo.SetY( offsetY ); m_pScaleformUI->Value_SetDisplayInfo( m_rightCrosshairArc, &dinfo ); dinfo.SetX( - distance + offsetX - nDesiredFishtail ); dinfo.SetY( offsetY ); m_pScaleformUI->Value_SetDisplayInfo( m_leftCrosshairArc, &dinfo ); dinfo.SetX( offsetX - nDesiredFishtail ); dinfo.SetY( distance + offsetY ); m_pScaleformUI->Value_SetDisplayInfo( m_bottomCrosshairArc, &dinfo ); } if ( crosshairGap == -1 ) { ScaleformDisplayInfo hidePipsDisplayInfo; hidePipsDisplayInfo.SetVisibility( false ); m_pScaleformUI->Value_SetDisplayInfo( m_TopPip, &hidePipsDisplayInfo ); m_pScaleformUI->Value_SetDisplayInfo( m_BottomPip, &hidePipsDisplayInfo ); m_pScaleformUI->Value_SetDisplayInfo( m_LeftPip, &hidePipsDisplayInfo ); m_pScaleformUI->Value_SetDisplayInfo( m_RightPip, &hidePipsDisplayInfo ); } else { dinfo.SetX( offsetX - nDesiredFishtail ); dinfo.SetY( m_TopPipY - crosshairGap + offsetY); m_pScaleformUI->Value_SetDisplayInfo( m_TopPip, &dinfo ); dinfo.SetX( offsetX + 1 - nDesiredFishtail ); dinfo.SetY( m_BottomPipY + crosshairGap + offsetY+1); m_pScaleformUI->Value_SetDisplayInfo( m_BottomPip, &dinfo ); dinfo.SetY(offsetY+1); dinfo.SetX( m_LeftPipX - crosshairGap + offsetX - nDesiredFishtail ); m_pScaleformUI->Value_SetDisplayInfo( m_LeftPip, &dinfo ); dinfo.SetY(offsetY); dinfo.SetX( m_RightPipX + crosshairGap + offsetX + 1 - nDesiredFishtail ); m_pScaleformUI->Value_SetDisplayInfo( m_RightPip, &dinfo ); } } else { // make the arcs invisible dinfo.SetVisibility( false ); m_pScaleformUI->Value_SetDisplayInfo( m_topCrosshairArc, &dinfo ); m_pScaleformUI->Value_SetDisplayInfo( m_rightCrosshairArc, &dinfo ); m_pScaleformUI->Value_SetDisplayInfo( m_leftCrosshairArc, &dinfo ); m_pScaleformUI->Value_SetDisplayInfo( m_bottomCrosshairArc, &dinfo ); dinfo.SetVisibility( true ); float cg = cl_fixedcrosshairgap.GetFloat(); dinfo.SetX( offsetX - nDesiredFishtail ); dinfo.SetY( m_TopPipY - cg + offsetY); m_pScaleformUI->Value_SetDisplayInfo( m_TopPip, &dinfo ); dinfo.SetX( offsetX + 1 - nDesiredFishtail ); dinfo.SetY( m_BottomPipY + cg + offsetY+1); m_pScaleformUI->Value_SetDisplayInfo( m_BottomPip, &dinfo ); dinfo.SetY(offsetY+1); dinfo.SetX( m_LeftPipX - cg + offsetX - nDesiredFishtail ); m_pScaleformUI->Value_SetDisplayInfo( m_LeftPip, &dinfo ); dinfo.SetY(offsetY); dinfo.SetX( m_RightPipX + cg + offsetX + 1 - nDesiredFishtail ); m_pScaleformUI->Value_SetDisplayInfo( m_RightPip, &dinfo ); } m_iLastSpread = distance; m_iLastGap = crosshairGap; bMadeChanges = true; } // Update the position of the text. if ( m_bTextIDVisible && m_IDMovie && m_IDText ) { LockSlot( true, bSlotIsLocked ); // text movie ScaleformDisplayInfo displayInfo; displayInfo.SetX( offsetX + m_IDMovieX ); displayInfo.SetY( offsetY + m_IDMovieY ); m_pScaleformUI->Value_SetDisplayInfo( m_IDMovie, &displayInfo ); bMadeChanges = true; } LockSlot( false, bSlotIsLocked ); return bMadeChanges; } void SFHudReticle::FlashReady( void ) { m_ObserverCrosshairHandle = m_pScaleformUI->Value_GetMember( m_FlashAPI, "Observer" ); PerformSwapReticle( "Crosshair1" ); m_IDMovie = m_pScaleformUI->Value_GetMember( m_FlashAPI, "TargetID" ); if ( m_IDMovie ) { SFVALUE animatedID = m_pScaleformUI->Value_GetMember( m_IDMovie, "IDAnimated" ); if ( animatedID ) { m_IDText = m_pScaleformUI->Value_GetMember( animatedID, "TextBox" ); m_pScaleformUI->Value_SetTextHTML( m_IDText, " " ); SafeReleaseSFVALUE( animatedID ); } } m_FlashedIcon = m_pScaleformUI->Value_GetMember( m_FlashAPI, "FlashedBlind" ); // // Update the position of the text. // if ( m_FlashedIcon ) // { // LockSlot( true, bSlotIsLocked ); // // // text movie // ScaleformDisplayInfo displayInfo; // m_pScaleformUI->Value_GetDisplayInfo( m_FlashedIcon, &displayInfo ); // displayInfo.SetX( offsetX + m_IDMovieX ); // displayInfo.SetY( offsetY + m_IDMovieY ); // m_pScaleformUI->Value_SetDisplayInfo( m_IDMovie, &displayInfo ); // // bMadeChanges = true; // } ResetDisplay(); ListenForGameEvent( "item_pickup" ); ListenForGameEvent( "ammo_pickup" ); ListenForGameEvent( "player_death" ); ListenForGameEvent( "round_start" ); ListenForGameEvent( "round_end" ); ListenForGameEvent( "round_freeze_end" ); ListenForGameEvent( "bomb_planted" ); ListenForGameEvent( "defuser_pickup" ); ListenForGameEvent( "bomb_dropped" ); ListenForGameEvent( "bomb_pickup" ); ListenForGameEvent( "grenade_thrown" ); } bool SFHudReticle::PreUnloadFlash( void ) { SafeReleaseSFVALUE( m_WeaponCrosshairHandle ); SafeReleaseSFVALUE( m_ObserverCrosshairHandle ); SafeReleaseSFVALUE( m_TopPip ); SafeReleaseSFVALUE( m_BottomPip ); SafeReleaseSFVALUE( m_LeftPip ); SafeReleaseSFVALUE( m_RightPip ); SafeReleaseSFVALUE( m_topCrosshairArc ); SafeReleaseSFVALUE( m_rightCrosshairArc ); SafeReleaseSFVALUE( m_leftCrosshairArc ); SafeReleaseSFVALUE( m_bottomCrosshairArc ); SafeReleaseSFVALUE( m_FriendCrosshair ); SafeReleaseSFVALUE( m_crosshairDot ); SafeReleaseSFVALUE( m_blackRing ); SafeReleaseSFVALUE( m_IDMovie ); SafeReleaseSFVALUE( m_IDText ); SafeReleaseSFVALUE( m_FlashedIcon ); RemoveAllIDs(); return true; } void SFHudReticle::ResetDisplay( void ) { // hide everything we don't want / need; WITH_SLOT_LOCKED { if ( m_IDMovie ) { m_pScaleformUI->Value_InvokeWithoutReturn( m_IDMovie, "HideNow", NULL, 0 ); } if ( m_FlashedIcon ) { m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashedIcon, "Hide", NULL, 0 ); m_bFlashedIconFadingOut = false; } if ( m_FriendCrosshair ) { m_pScaleformUI->Value_SetVisible( m_FriendCrosshair, false ); } ShowReticle( RETICLE_MODE_WEAPON, false ); ShowReticle( RETICLE_MODE_OBSERVER, false ); } m_fIDTimer = 0; m_bTextIDVisible = false; m_bFriendlyCrosshairVisible = false; m_iReticleMode = RETICLE_MODE_NONE; RemoveAllIDs(); } void SFHudReticle::LevelInit( void ) { if ( !FlashAPIIsValid() ) { SFUI_REQUEST_ELEMENT( SF_SS_SLOT( GET_ACTIVE_SPLITSCREEN_SLOT() ), g_pScaleformUI, SFHudReticle, this, Reticle ); } else { ResetDisplay(); } } void SFHudReticle::LevelShutdown( void ) { if ( FlashAPIIsValid() ) { RemoveFlashElement(); } } bool SFHudReticle::ShouldDraw( void ) { if ( IsTakingAFreezecamScreenshot() ) return false; C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pPlayer ) return false; if ( pPlayer->GetObserverInterpState() == C_CSPlayer::OBSERVER_INTERP_TRAVELING ) return false; bool bNeedsDraw = false; if ( (pPlayer->GetObserverMode() == OBS_MODE_ROAMING) || (pPlayer->GetObserverMode() == OBS_MODE_FIXED) ) bNeedsDraw = true; return cl_drawhud.GetBool() && (bNeedsDraw || CHudElement::ShouldDraw()); } void SFHudReticle::SetActive( bool bActive ) { if ( !FlashAPIIsValid() ) return; SF_SPLITSCREEN_PLAYER_GUARD(); if ( !bActive && m_bActive ) { ResetDisplay(); } else if ( bActive && !m_bActive ) { SplitScreenSlottedConVarRef convar( GET_ACTIVE_SPLITSCREEN_SLOT(), "cl_crosshaircolor" ); WITH_SFVALUEARRAY_SLOT_LOCKED( args, 1 ) { g_pScaleformUI->ValueArray_SetElement( args, 0, convar.GetFloat() ); g_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "onUpdateColor", args, 1 ); } } CHudElement::SetActive( bActive ); } void SFHudReticle::OnSwapReticle( SCALEFORM_CALLBACK_ARGS_DECL ) { SF_SPLITSCREEN_PLAYER_GUARD(); PerformSwapReticle( m_pScaleformUI->Params_GetArgAsString( obj, 0 ) ); } void SFHudReticle::PerformSwapReticle( const char * szReticleName ) { SafeReleaseSFVALUE( m_WeaponCrosshairHandle ); SafeReleaseSFVALUE( m_FriendCrosshair ); SafeReleaseSFVALUE( m_crosshairDot ); SafeReleaseSFVALUE( m_blackRing ); SafeReleaseSFVALUE( m_TopPip ); SafeReleaseSFVALUE( m_BottomPip ); SafeReleaseSFVALUE( m_LeftPip ); SafeReleaseSFVALUE( m_RightPip ); SafeReleaseSFVALUE( m_topCrosshairArc ); SafeReleaseSFVALUE( m_rightCrosshairArc ); SafeReleaseSFVALUE( m_leftCrosshairArc ); SafeReleaseSFVALUE( m_bottomCrosshairArc ); m_WeaponCrosshairHandle = m_pScaleformUI->Value_GetMember( m_FlashAPI, szReticleName ); if ( m_WeaponCrosshairHandle ) { ScaleformDisplayInfo dinfo; m_FriendCrosshair = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "FriendCrosshair" ); m_crosshairDot = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "Dot" ); m_blackRing = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "BlackRing" ); if ( !m_bCrosshairPositionsInitialized ) { m_bCrosshairPositionsInitialized = true; if ( m_FriendCrosshair ) { m_pScaleformUI->Value_GetDisplayInfo( m_FriendCrosshair, &dinfo ); m_friendIndicatorX = dinfo.GetX(); m_friendIndicatorY = dinfo.GetY(); } if ( m_crosshairDot ) { m_pScaleformUI->Value_GetDisplayInfo( m_crosshairDot, &dinfo ); m_dotX = dinfo.GetX(); m_dotY = dinfo.GetY(); } if ( m_blackRing ) { m_pScaleformUI->Value_GetDisplayInfo( m_blackRing, &dinfo ); m_blackRingX = dinfo.GetX(); m_blackRingY = dinfo.GetY(); } } m_TopPip = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "TopPip" ); if ( m_TopPip ) { m_TopPipY = 0; } m_BottomPip = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "BottomPip" ); if ( m_BottomPip ) { m_BottomPipY = 0; } m_LeftPip = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "LeftPip" ); if ( m_LeftPip ) { m_LeftPipX = 0; } m_RightPip = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "RightPip" ); if ( m_RightPip ) { m_RightPipX = 0; } m_topCrosshairArc = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "TopArc" ); m_rightCrosshairArc = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "RightArc" ); m_leftCrosshairArc = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "LeftArc" ); m_bottomCrosshairArc = m_pScaleformUI->Value_GetMember( m_WeaponCrosshairHandle, "BottomArc" ); } if ( m_FriendCrosshair ) { m_pScaleformUI->Value_SetVisible( m_FriendCrosshair, false ); } if ( m_IDMovie ) { ScaleformDisplayInfo dinfo; m_pScaleformUI->Value_GetDisplayInfo( m_IDMovie, &dinfo ); m_IDMovieX = dinfo.GetX(); m_IDMovieY = dinfo.GetY(); } // set these here because the flash code makes them invisible m_bFriendlyCrosshairVisible = false; m_iReticleMode = RETICLE_MODE_NONE; m_iLastSpread = -1; m_iLastGap = -1; } void SFHudReticle::RemoveID( int index ) { SFVALUE panel = m_playerIDs[ index ].panel; SafeReleaseSFVALUE( m_playerIDs[ index ].arrowA ); SafeReleaseSFVALUE( m_playerIDs[ index ].arrowB ); SafeReleaseSFVALUE( m_playerIDs[ index ].arrowF ); SafeReleaseSFVALUE( m_playerIDs[ index ].voiceIcon ); SafeReleaseSFVALUE( m_playerIDs[ index ].defuseIcon ); m_playerIDs.Remove( index ); WITH_SFVALUEARRAY_SLOT_LOCKED( data, 1 ) { m_pScaleformUI->ValueArray_SetElement( data, 0, panel ); m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "RemovePlayerID", data, 1 ); } SafeReleaseSFVALUE( panel ); } void SFHudReticle::RemoveAllIDs( void ) { if ( m_pScaleformUI ) { WITH_SLOT_LOCKED { //Remove all items before we exit while( m_playerIDs.Count() > 0 ) { RemoveID( 0 ); } } } } void SFHudReticle::FireGameEvent( IGameEvent *event ) { const char *type = event->GetName(); int nUserId = event->GetInt( "userid" ); C_BasePlayer *pPlayer = UTIL_PlayerByUserId( nUserId ); C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer(); if ( !V_strcmp( type, "player_death" ) ) { // if we were the one that died or the player we are spectating, remove all the stuff! if ( pPlayer && (pPlayer->entindex() == pLocalPlayer->entindex() || (pLocalPlayer->GetObserverTarget() && pPlayer == pLocalPlayer->GetObserverTarget())) ) { RemoveAllIDs(); if ( m_IDMovie ) { WITH_SLOT_LOCKED { m_pScaleformUI->Value_InvokeWithoutReturn( m_IDMovie, "HideNow", NULL, 0 ); } } if ( m_FlashedIcon ) { WITH_SLOT_LOCKED { m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashedIcon, "Hide", NULL, 0 ); m_bFlashedIconFadingOut = false; } } } } else if ( !V_strcmp( type, "round_end" ) ) { RemoveAllIDs(); } else if ( !V_strcmp( type, "round_start" ) ) { RemoveAllIDs(); if ( m_IDMovie && FlashAPIIsValid() ) { WITH_SLOT_LOCKED { m_pScaleformUI->Value_InvokeWithoutReturn( m_IDMovie, "HideNow", NULL, 0 ); } } if ( m_FlashedIcon ) { WITH_SLOT_LOCKED { m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashedIcon, "Hide", NULL, 0 ); m_bFlashedIconFadingOut = false; } } } else if ( !V_strcmp( type, "item_pickup" ) || !V_strcmp( type, "ammo_pickup" ) || !V_strcmp( type, "bomb_planted" ) || !V_strcmp( type, "defuser_pickup" ) || !V_strcmp( type, "bomb_dropped" ) || !V_strcmp( type, "bomb_pickup" ) || !V_strcmp( type, "grenade_thrown" ) ) { if ( pLocalPlayer ) { FOR_EACH_VEC( m_playerIDs, j ) { if ( m_playerIDs[j].hPlayer.Get() == pPlayer ) { m_playerIDs[j].flUpdateAt = (gpGlobals->curtime + 0.1f); break; } } } } else if ( !V_strcmp( type, "round_freeze_end" ) ) { if ( pLocalPlayer ) { FOR_EACH_VEC( m_playerIDs, j ) { m_playerIDs[j].flUpdateAt = (gpGlobals->curtime + 0.1f); } } } }