|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#include "cbase.h"
#include "hud.h"
#include "clientmode_csnormal.h"
#include "cdll_client_int.h"
#include "iinput.h"
#include "vgui/ISurface.h"
#include "vgui/IPanel.h"
#include <vgui_controls/AnimationController.h>
#include "ivmodemanager.h"
#include "buymenu.h"
#include "filesystem.h"
#include "vgui/IVGui.h"
#include "hud_basechat.h"
#include "view_shared.h"
#include "view.h"
#include "ivrenderview.h"
#include "cstrikeclassmenu.h"
#include "model_types.h"
#include "iefx.h"
#include "dlight.h"
#include <imapoverview.h>
#include "c_playerresource.h"
#include "c_soundscape.h"
#include <KeyValues.h>
#include "text_message.h"
#include "panelmetaclassmgr.h"
#include "vguicenterprint.h"
#include "physpropclientside.h"
#include "c_weapon__stubs.h"
#include <engine/IEngineSound.h>
#include "c_cs_hostage.h"
#include "buy_presets/buy_presets.h"
#include "bitbuf.h"
#include "usermessages.h"
#include "prediction.h"
#include "datacache/imdlcache.h"
//=============================================================================
// HPE_BEGIN:
// [tj] Needed to retrieve achievement text
// [menglish] Need access to message macros
//=============================================================================
#include "achievementmgr.h"
#include "hud_macros.h"
#include "c_plantedc4.h"
#include "tier1/fmtstr.h"
#include "history_resource.h"
#include "cs_client_gamestats.h"
// [tj] We need to forward declare this, since the definition is all inside the implementation file
class CHudHintDisplay; //=============================================================================
// HPE_END
//=============================================================================
void __MsgFunc_MatchEndConditions( bf_read &msg );
class CHudChat;
ConVar default_fov( "default_fov", "90", FCVAR_CHEAT );
IClientMode *g_pClientMode = NULL;
// This is a temporary entity used to render the player's model while drawing the class selection menu.
CHandle<C_BaseAnimatingOverlay> g_ClassImagePlayer; // player
CHandle<C_BaseAnimating> g_ClassImageWeapon; // weapon
STUB_WEAPON_CLASS( cycler_weapon, WeaponCycler, C_BaseCombatWeapon ); STUB_WEAPON_CLASS( weapon_cubemap, WeaponCubemap, C_BaseCombatWeapon );
//-----------------------------------------------------------------------------
// HACK: the detail sway convars are archive, and default to 0. Existing CS:S players thus have no detail
// prop sway. We'll force them to DoD's default values for now. What we really need in the long run is
// a system to apply changes to archived convars' defaults to existing players.
extern ConVar cl_detail_max_sway; extern ConVar cl_detail_avoid_radius; extern ConVar cl_detail_avoid_force; extern ConVar cl_detail_avoid_recover_speed;
//-----------------------------------------------------------------------------
ConVar cl_autobuy( "cl_autobuy", "", FCVAR_USERINFO, "The order in which autobuy will attempt to purchase items" );
//-----------------------------------------------------------------------------
ConVar cl_rebuy( "cl_rebuy", "", FCVAR_USERINFO, "The order in which rebuy will attempt to repurchase items" );
//-----------------------------------------------------------------------------
void SetBuyData( const ConVar &buyVar, const char *filename ) { // if we already have autobuy data, don't bother re-parsing the text file
if ( *buyVar.GetString() ) return;
// First, look for a mapcycle file in the cfg directory, which is preferred
char szRecommendedName[ 256 ]; char szResolvedName[ 256 ]; V_sprintf_safe( szRecommendedName, "cfg/%s", filename ); V_strcpy_safe( szResolvedName, szRecommendedName ); if ( filesystem->FileExists( szResolvedName, "GAME" ) ) { Msg( "Loading '%s'.\n", szResolvedName ); } else { // Check the root
V_strcpy_safe( szResolvedName, filename ); if ( filesystem->FileExists( szResolvedName, "GAME" ) ) { Msg( "Loading '%s' ('%s' was not found.)\n", szResolvedName, szRecommendedName ); } else {
// Try cfg/xxx_default.txt
V_strcpy_safe( szResolvedName, szRecommendedName ); char *dotTxt = V_stristr( szResolvedName, ".txt" ); Assert( dotTxt ); if ( dotTxt ) { V_strcpy( dotTxt, "_default.txt" ); } if ( !filesystem->FileExists( szResolvedName, "GAME" ) ) { Warning( "Not loading buy data. Neither '%s' nor %s were found.\n", szResolvedName, szRecommendedName ); return; } Msg( "Loading '%s'\n", szResolvedName ); } }
CUtlBuffer buf; if ( !filesystem->ReadFile( szResolvedName, "GAME", buf ) ) { // WAT
Warning( "Failed to load '%s'.\n", szResolvedName ); return; } buf.PutChar('\0');
char token[256]; char buystring[256]; V_sprintf_safe( buystring, "setinfo %s \"", buyVar.GetName() );
const char *pfile = engine->ParseFile( (const char *)buf.Base(), token, sizeof(token) );
bool first = true;
while (pfile != NULL) { if (first) { first = false; } else { Q_strncat(buystring, " ", sizeof(buystring), COPY_ALL_CHARACTERS); }
Q_strncat(buystring, token, sizeof(buystring), COPY_ALL_CHARACTERS);
pfile = engine->ParseFile( pfile, token, sizeof(token) ); }
Q_strncat(buystring, "\"", sizeof(buystring), COPY_ALL_CHARACTERS);
engine->ClientCmd(buystring); }
void MsgFunc_KillCam(bf_read &msg) { C_CSPlayer *pPlayer = ToCSPlayer( C_BasePlayer::GetLocalPlayer() );
if ( !pPlayer ) return;
int newMode = msg.ReadByte();
if ( newMode != g_nKillCamMode ) { #if !defined( NO_ENTITY_PREDICTION )
if ( g_nKillCamMode == OBS_MODE_NONE ) { // kill cam is switch on, turn off prediction
g_bForceCLPredictOff = true; } else if ( newMode == OBS_MODE_NONE ) { // kill cam is switched off, restore old prediction setting is we switch back to normal mode
g_bForceCLPredictOff = false; } #endif
g_nKillCamMode = newMode; }
g_nKillCamTarget1 = msg.ReadByte(); g_nKillCamTarget2 = msg.ReadByte(); }
// --------------------------------------------------------------------------------- //
// CCSModeManager.
// --------------------------------------------------------------------------------- //
class CCSModeManager : public IVModeManager { public: virtual void Init(); virtual void SwitchMode( bool commander, bool force ) {} virtual void LevelInit( const char *newmap ); virtual void LevelShutdown( void ); virtual void ActivateMouse( bool isactive ) {} };
static CCSModeManager g_ModeManager; IVModeManager *modemanager = ( IVModeManager * )&g_ModeManager;
// --------------------------------------------------------------------------------- //
// CCSModeManager implementation.
// --------------------------------------------------------------------------------- //
#define SCREEN_FILE "scripts/vgui_screens.txt"
void CCSModeManager::Init() { g_pClientMode = GetClientModeNormal(); PanelMetaClassMgr()->LoadMetaClassDefinitionFile( SCREEN_FILE ); }
void CCSModeManager::LevelInit( const char *newmap ) { g_pClientMode->LevelInit( newmap );
SetBuyData( cl_autobuy, "autobuy.txt" ); SetBuyData( cl_rebuy, "rebuy.txt" );
#if !defined( NO_ENTITY_PREDICTION )
if ( g_nKillCamMode > OBS_MODE_NONE ) { g_bForceCLPredictOff = false; } #endif
g_nKillCamMode = OBS_MODE_NONE; g_nKillCamTarget1 = 0; g_nKillCamTarget2 = 0;
// HACK: the detail sway convars are archive, and default to 0. Existing CS:S players thus have no detail
// prop sway. We'll force them to DoD's default values for now.
if ( !cl_detail_max_sway.GetFloat() && !cl_detail_avoid_radius.GetFloat() && !cl_detail_avoid_force.GetFloat() && !cl_detail_avoid_recover_speed.GetFloat() ) { cl_detail_max_sway.SetValue( "5" ); cl_detail_avoid_radius.SetValue( "64" ); cl_detail_avoid_force.SetValue( "0.4" ); cl_detail_avoid_recover_speed.SetValue( "0.25" ); } }
void CCSModeManager::LevelShutdown( void ) { g_pClientMode->LevelShutdown(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
ClientModeCSNormal::ClientModeCSNormal() { HOOK_MESSAGE( MatchEndConditions ); }
void ClientModeCSNormal::Init() { BaseClass::Init();
ListenForGameEvent( "round_end" ); ListenForGameEvent( "round_start" ); ListenForGameEvent( "player_team" ); ListenForGameEvent( "player_death" ); ListenForGameEvent( "bomb_planted" ); ListenForGameEvent( "bomb_exploded" ); ListenForGameEvent( "bomb_defused" ); ListenForGameEvent( "hostage_killed" ); ListenForGameEvent( "hostage_hurt" );
usermessages->HookMessage( "KillCam", MsgFunc_KillCam );
//=============================================================================
// HPE_BEGIN:
// [tj] Add the shared HUD elements to the render groups responsible for hiding
// conflicting UI
//=============================================================================
CHudElement* hintBox = (CHudElement*)GET_HUDELEMENT( CHudHintDisplay ); if (hintBox) { hintBox->RegisterForRenderGroup("hide_for_scoreboard"); hintBox->RegisterForRenderGroup("hide_for_round_panel"); }
CHudElement* historyResource = (CHudElement*)GET_HUDELEMENT( CHudHistoryResource ); if (historyResource) { historyResource->RegisterForRenderGroup("hide_for_scoreboard"); } //=============================================================================
// HPE_END
//=============================================================================
}
void ClientModeCSNormal::InitViewport() { BaseClass::InitViewport();
m_pViewport = new CounterStrikeViewport(); m_pViewport->Start( gameuifuncs, gameeventmanager ); }
void ClientModeCSNormal::Update() { BaseClass::Update();
// Override the hud's visibility if this is a logo (like E3 demo) map.
if ( CSGameRules() && CSGameRules()->IsLogoMap() ) m_pViewport->SetVisible( false ); }
/*
void ClientModeCSNormal::UpdateSpectatorMode( void ) { C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer ) return;
IMapOverview * overviewmap = m_pViewport->GetMapOverviewInterface();
if ( !overviewmap ) return;
overviewmap->SetTime( gpGlobals->curtime );
int obs_mode = pPlayer->GetObserverMode();
if ( obs_mode < OBS_MODE_IN_EYE ) return;
Vector worldpos = pPlayer->GetLocalOrigin(); QAngle angles; engine->GetViewAngles( angles );
C_BaseEntity *target = pPlayer->GetObserverTarget();
if ( target && (obs_mode == OBS_MODE_IN_EYE || obs_mode == OBS_MODE_CHASE) ) { worldpos = target->GetAbsOrigin();
if ( obs_mode == OBS_MODE_IN_EYE ) { angles = target->GetAbsAngles(); } }
Vector2D mappos = overviewmap->WorldToMap( worldpos );
overviewmap->SetCenter( mappos ); overviewmap->SetAngle( angles.y ); for ( int i = 1; i<= MAX_PLAYERS; i++) { C_BaseEntity *ent = ClientEntityList().GetEnt( i );
if ( !ent || !ent->IsPlayer() ) continue;
C_BasePlayer *p = ToBasePlayer( ent );
// update position of active players in our PVS
Vector position = p->GetAbsOrigin(); QAngle angle = p->GetAbsAngles();
if ( p->IsDormant() ) { // if player is not in PVS, use PlayerResources data
position = g_PR->GetPosition( i ); angles[1] = g_PR->GetViewAngle( i ); } overviewmap->SetPlayerPositions( i-1, position, angles ); } } */
//-----------------------------------------------------------------------------
// Purpose: We've received a keypress from the engine. Return 1 if the engine is allowed to handle it.
//-----------------------------------------------------------------------------
int ClientModeCSNormal::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) { // don't process input in LogoMaps
if( CSGameRules() && CSGameRules()->IsLogoMap() ) return 1; return BaseClass::KeyInput( down, keynum, pszCurrentBinding ); }
IClientMode *GetClientModeNormal() { static ClientModeCSNormal g_ClientModeNormal; return &g_ClientModeNormal; }
ClientModeCSNormal* GetClientModeCSNormal() { Assert( dynamic_cast< ClientModeCSNormal* >( GetClientModeNormal() ) );
return static_cast< ClientModeCSNormal* >( GetClientModeNormal() ); }
float ClientModeCSNormal::GetViewModelFOV( void ) { return 74.0f; }
int ClientModeCSNormal::GetDeathMessageStartHeight( void ) { return m_pViewport->GetDeathMessageStartHeight(); }
void ClientModeCSNormal::FireGameEvent( IGameEvent *event ) { CBaseHudChat *pHudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat ); C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); CLocalPlayerFilter filter; if ( !pLocalPlayer || !pHudChat ) return;
const char *eventname = event->GetName();
if ( !eventname || !eventname[0] ) return;
if ( Q_strcmp( "round_start", eventname ) == 0 ) { // recreate all client side physics props
C_PhysPropClientside::RecreateAll();
// remove hostage ragdolls
for ( int i=0; i<g_HostageRagdolls.Count(); ++i ) { // double-check that the EHANDLE is still valid
if ( g_HostageRagdolls[i] ) { g_HostageRagdolls[i]->Release(); } } g_HostageRagdolls.RemoveAll();
// Just tell engine to clear decals
engine->ClientCmd( "r_cleardecals\n" );
//stop any looping sounds
enginesound->StopAllSounds( true );
Soundscape_OnStopAllSounds(); // Tell the soundscape system.
}
else if ( Q_strcmp( "round_end", eventname ) == 0 ) { int winningTeam = event->GetInt("winner"); int reason = event->GetInt("reason");
// play endround announcer sound
if ( winningTeam == TEAM_CT ) { if ( reason == Bomb_Defused ) { C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.BombDefused"); } else { C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.CTWin"); } } else if ( winningTeam == TEAM_TERRORIST ) { C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.TERWin"); } else { C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.RoundDraw"); } //=============================================================================
// HPE_BEGIN:
// [pfreese] Only show centerprint message for game commencing; the rest of
// these messages are handled by the end-of-round panel.
// [Forrest] Show all centerprint messages if the end-of-round panel is disabled.
//=============================================================================
static ConVarRef sv_nowinpanel( "sv_nowinpanel" ); static ConVarRef cl_nowinpanel( "cl_nowinpanel" ); if ( reason == Game_Commencing || sv_nowinpanel.GetBool() || cl_nowinpanel.GetBool() ) { internalCenterPrint->Print( hudtextmessage->LookupString( event->GetString("message") ) );
// we are starting a new round; clear the current match stats
g_CSClientGameStats.ResetMatchStats(); } //=============================================================================
// HPE_END
//=============================================================================
}
else if ( Q_strcmp( "player_team", eventname ) == 0 ) { CBaseHudChat *pHudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat ); C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") ); if ( !pPlayer ) return;
bool bDisconnected = event->GetBool("disconnect");
if ( bDisconnected ) return;
int iTeam = event->GetInt("team");
if ( pPlayer->IsLocalPlayer() ) { // that's me
pPlayer->TeamChange( iTeam ); }
if ( iTeam == TEAM_SPECTATOR ) pHudChat->Printf( CHAT_FILTER_NONE, hudtextmessage->LookupString( "#Game_join_spectators" ), pPlayer->GetPlayerName() ); else if ( iTeam == TEAM_TERRORIST ) pHudChat->Printf( CHAT_FILTER_NONE, hudtextmessage->LookupString( "#Game_join_terrorist" ), pPlayer->GetPlayerName() ); else if ( iTeam == TEAM_CT ) pHudChat->Printf( CHAT_FILTER_NONE, hudtextmessage->LookupString( "#Game_join_ct" ), pPlayer->GetPlayerName() ); }
else if ( Q_strcmp( "bomb_planted", eventname ) == 0 ) { //C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
// show centerprint message
internalCenterPrint->Print( "#Cstrike_TitlesTXT_Bomb_Planted" );
// play sound
C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.BombPlanted") ; }
else if ( Q_strcmp( "bomb_defused", eventname ) == 0 ) { // C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
} //=============================================================================
// HPE_BEGIN:
// [menglish] Tell the client side bomb that the bomb has exploding here creating the explosion particle effect
//=============================================================================
else if ( Q_strcmp( "bomb_exploded", eventname ) == 0 ) { if ( g_PlantedC4s.Count() > 0 ) { // bomb is planted
C_PlantedC4 *pC4 = g_PlantedC4s[0]; pC4->Explode(); } } //=============================================================================
// HPE_END
//=============================================================================
else if ( Q_strcmp( "hostage_killed", eventname ) == 0 ) { // play sound for spectators and CTs
if ( pLocalPlayer->IsObserver() || (pLocalPlayer->GetTeamNumber() == TEAM_CT) ) { C_BaseEntity::EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, "Event.HostageKilled") ; }
// Show warning to killer
if ( pLocalPlayer->GetUserID() == event->GetInt("userid") ) { internalCenterPrint->Print( "#Cstrike_TitlesTXT_Killed_Hostage" ); } }
else if ( Q_strcmp( "hostage_hurt", eventname ) == 0 ) { // Let the loacl player know he harmed a hostage
if ( pLocalPlayer->GetUserID() == event->GetInt("userid") ) { internalCenterPrint->Print( "#Cstrike_TitlesTXT_Injured_Hostage" ); } }
else if ( Q_strcmp( "player_death", eventname ) == 0 ) { C_BasePlayer *pPlayer = USERID2PLAYER( event->GetInt("userid") );
C_CSPlayer* csPlayer = ToCSPlayer(pPlayer); if (csPlayer) { csPlayer->ClearSoundEvents(); }
if ( pPlayer == C_BasePlayer::GetLocalPlayer() ) { // we just died, hide any buy panels
gViewPortInterface->ShowPanel( PANEL_BUY, false ); gViewPortInterface->ShowPanel( PANEL_BUY_CT, false ); gViewPortInterface->ShowPanel( PANEL_BUY_TER, false ); gViewPortInterface->ShowPanel( PANEL_BUY_EQUIP_CT, false ); gViewPortInterface->ShowPanel( PANEL_BUY_EQUIP_TER, false ); } }
else if ( Q_strcmp( "player_changename", eventname ) == 0 ) { return; // server sends a colorized text string for this
}
//=============================================================================
// HPE_BEGIN:
// [tj] We handle this here instead of in the base class
// The reason is that we don't use string tables to localize.
// Instead, we use the steam localization mechanism.
//
// [dwenger] Remove dependency on stats system for name of achievement.
//=============================================================================
else if ( Q_strcmp( "achievement_earned", eventname ) == 0 ) { CBaseHudChat *hudChat = (CBaseHudChat *)GET_HUDELEMENT( CHudChat ); int iPlayerIndex = event->GetInt( "player" ); C_BasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex ); int iAchievement = event->GetInt( "achievement" );
if ( !hudChat || !pPlayer ) return;
CAchievementMgr *pAchievementMgr = dynamic_cast<CAchievementMgr *>( engine->GetAchievementMgr() ); if ( !pAchievementMgr ) return;
IAchievement *pAchievement = pAchievementMgr->GetAchievementByID( iAchievement ); if ( pAchievement ) { if ( !pPlayer->IsDormant() && pPlayer->ShouldAnnounceAchievement() ) { pPlayer->SetNextAchievementAnnounceTime( gpGlobals->curtime + ACHIEVEMENT_ANNOUNCEMENT_MIN_TIME );
//Do something for the player - Actually we should probably do this client-side when the achievement is first earned.
if (pPlayer->IsLocalPlayer()) { } pPlayer->OnAchievementAchieved( iAchievement ); }
if ( g_PR ) { wchar_t wszPlayerName[MAX_PLAYER_NAME_LENGTH]; g_pVGuiLocalize->ConvertANSIToUnicode( g_PR->GetPlayerName( iPlayerIndex ), wszPlayerName, sizeof( wszPlayerName ) );
wchar_t achievementName[1024]; const wchar_t* constAchievementName = &achievementName[0];
constAchievementName = ACHIEVEMENT_LOCALIZED_NAME( pAchievement );
if (constAchievementName) { wchar_t wszLocalizedString[128]; g_pVGuiLocalize->ConstructString( wszLocalizedString, sizeof( wszLocalizedString ), g_pVGuiLocalize->Find( "#Achievement_Earned" ), 2, wszPlayerName, constAchievementName/*wszAchievementString*/ );
char szLocalized[128]; g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalizedString, szLocalized, sizeof( szLocalized ) );
hudChat->ChatPrintf( iPlayerIndex, CHAT_FILTER_ACHIEVEMENT, "%s", szLocalized );
/*
if (pPlayer->IsLocalPlayer()) { char achievementDescription[1024]; const char* constAchievementDescription = &achievementDescription[0];
constAchievementDescription = pUserStats->GetAchievementDisplayAttribute( pAchievement->GetName(), "desc" ); hudChat->ChatPrintf( iPlayerIndex, CHAT_FILTER_ACHIEVEMENT, "(%s)", constAchievementDescription ); } */ } } } } //=============================================================================
// HPE_END
//=============================================================================
else { BaseClass::FireGameEvent( event ); } }
void RemoveClassImageEntity() { C_BaseAnimating *pEnt = g_ClassImagePlayer.Get(); if ( pEnt ) { pEnt->Remove(); g_ClassImagePlayer = NULL; }
pEnt = g_ClassImageWeapon.Get(); if ( pEnt ) { pEnt->Remove(); g_ClassImagePlayer = NULL; } }
bool ShouldRecreateClassImageEntity( C_BaseAnimating *pEnt, const char *pNewModelName ) { if ( !pNewModelName || !pNewModelName[0] ) return false;
if ( !pEnt ) return true;
const model_t *pModel = pEnt->GetModel();
if ( !pModel ) return true;
const char *pName = modelinfo->GetModelName( pModel ); if ( !pName ) return true;
// reload only if names are different
const char *pNameNoPath = V_UnqualifiedFileName( pName ); const char *pNewModelNameNoPath = V_UnqualifiedFileName( pNewModelName ); return( Q_stricmp( pNameNoPath, pNewModelNameNoPath ) != 0 ); }
void UpdateClassImageEntity( const char *pModelName, int x, int y, int width, int height ) { C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); if ( !pLocalPlayer ) return;
MDLCACHE_CRITICAL_SECTION();
const char *pWeaponName = "models/weapons/w_rif_ak47.mdl"; const char *pWeaponSequence = "Walk_Upper_AK";
int i; for ( i=0; i<CTPlayerModels.Count(); ++i ) { if ( Q_strcasecmp( pModelName, CTPlayerModels[i] ) == 0 ) { // give CTs a M4
pWeaponName = "models/weapons/w_rif_m4a1.mdl"; pWeaponSequence = "Walk_Upper_M4"; break; } }
if ( pLocalPlayer->IsAlive() && pLocalPlayer->GetActiveWeapon() ) { C_WeaponCSBase *weapon = dynamic_cast< C_WeaponCSBase * >(pLocalPlayer->GetActiveWeapon()); if ( weapon ) { pWeaponName = weapon->GetWorldModel(); pWeaponSequence = VarArgs("Walk_Upper_%s", weapon->GetCSWpnData().m_szAnimExtension); } }
C_BaseAnimatingOverlay *pPlayerModel = g_ClassImagePlayer.Get();
// Does the entity even exist yet?
bool recreatePlayer = ShouldRecreateClassImageEntity( pPlayerModel, pModelName ); if ( recreatePlayer ) { if ( pPlayerModel ) pPlayerModel->Remove();
pPlayerModel = new C_BaseAnimatingOverlay; pPlayerModel->InitializeAsClientEntity( pModelName, RENDER_GROUP_OPAQUE_ENTITY ); pPlayerModel->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally
// let player walk ahead
pPlayerModel->SetSequence( pPlayerModel->LookupSequence( "walk_lower" ) ); pPlayerModel->SetPoseParameter( "move_yaw", 0.0f ); // move_yaw
pPlayerModel->SetPoseParameter( "body_pitch", 10.0f ); // body_pitch, look down a bit
pPlayerModel->SetPoseParameter( "body_yaw", 0.0f ); // body_yaw
pPlayerModel->SetPoseParameter( "move_y", 0.0f ); // move_y
pPlayerModel->SetPoseParameter( "move_x", 1.0f ); // move_x, walk forward
pPlayerModel->m_flAnimTime = gpGlobals->curtime;
g_ClassImagePlayer = pPlayerModel; }
C_BaseAnimating *pWeaponModel = g_ClassImageWeapon.Get();
// Does the entity even exist yet?
if ( recreatePlayer || ShouldRecreateClassImageEntity( pWeaponModel, pWeaponName ) ) { if ( pWeaponModel ) pWeaponModel->Remove();
pWeaponModel = new C_BaseAnimating; pWeaponModel->InitializeAsClientEntity( pWeaponName, RENDER_GROUP_OPAQUE_ENTITY ); pWeaponModel->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally
pWeaponModel->FollowEntity( pPlayerModel ); // attach to player model
pWeaponModel->m_flAnimTime = gpGlobals->curtime; g_ClassImageWeapon = pWeaponModel; }
Vector origin = pLocalPlayer->EyePosition(); Vector lightOrigin = origin;
// find a spot inside the world for the dlight's origin, or it won't illuminate the model
Vector testPos( origin.x - 100, origin.y, origin.z + 100 ); trace_t tr; UTIL_TraceLine( origin, testPos, MASK_OPAQUE, pLocalPlayer, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction == 1.0f ) { lightOrigin = tr.endpos; } else { // Now move the model away so we get the correct illumination
lightOrigin = tr.endpos + Vector( 1, 0, -1 ); // pull out from the solid
Vector start = lightOrigin; Vector end = lightOrigin + Vector( 100, 0, -100 ); UTIL_TraceLine( start, end, MASK_OPAQUE, pLocalPlayer, COLLISION_GROUP_NONE, &tr ); origin = tr.endpos; }
// move player model in front of our view
pPlayerModel->SetAbsOrigin( origin ); pPlayerModel->SetAbsAngles( QAngle( 0, 210, 0 ) );
// wacky hacky, set upper body animation
pPlayerModel->m_SequenceTransitioner.CheckForSequenceChange( pPlayerModel->GetModelPtr(), pPlayerModel->LookupSequence( "walk_lower" ), false, true ); pPlayerModel->m_SequenceTransitioner.UpdateCurrent( pPlayerModel->GetModelPtr(), pPlayerModel->LookupSequence( "walk_lower" ), pPlayerModel->GetCycle(), pPlayerModel->GetPlaybackRate(), gpGlobals->realtime );
// Now, blend the lower and upper (aim) anims together
pPlayerModel->SetNumAnimOverlays( 2 ); int numOverlays = pPlayerModel->GetNumAnimOverlays(); for ( i=0; i < numOverlays; ++i ) { C_AnimationLayer *layer = pPlayerModel->GetAnimOverlay( i );
layer->m_flCycle = pPlayerModel->GetCycle(); if ( i ) layer->m_nSequence = pPlayerModel->LookupSequence( pWeaponSequence ); else layer->m_nSequence = pPlayerModel->LookupSequence( "walk_lower" );
layer->m_flPlaybackRate = 1.0; layer->m_flWeight = 1.0f; layer->SetOrder( i ); }
pPlayerModel->FrameAdvance( gpGlobals->frametime );
// Now draw it.
CViewSetup view; view.x = x; view.y = y; view.width = width; view.height = height;
view.m_bOrtho = false; view.fov = 54;
view.origin = origin + Vector( -110, -5, -5 );
Vector vMins, vMaxs; pPlayerModel->C_BaseAnimating::GetRenderBounds( vMins, vMaxs ); view.origin.z += ( vMins.z + vMaxs.z ) * 0.55f;
view.angles.Init(); view.zNear = VIEW_NEARZ; view.zFar = 1000;
Frustum dummyFrustum; render->Push3DView( view, 0, NULL, dummyFrustum );
//=============================================================================
// HPE_BEGIN:
// [mhansen] We don't want to light the model in the world. We want it to
// always be lit normal like even if you are standing in a dark (or green) area
// in the world.
//=============================================================================
CMatRenderContextPtr pRenderContext( materials ); pRenderContext->SetLightingOrigin( vec3_origin ); pRenderContext->SetAmbientLight( 0.4, 0.4, 0.4 );
static Vector white[6] = { Vector( 0.4, 0.4, 0.4 ), Vector( 0.4, 0.4, 0.4 ), Vector( 0.4, 0.4, 0.4 ), Vector( 0.4, 0.4, 0.4 ), Vector( 0.4, 0.4, 0.4 ), Vector( 0.4, 0.4, 0.4 ), };
g_pStudioRender->SetAmbientLightColors( white ); g_pStudioRender->SetLocalLights( 0, NULL );
modelrender->SuppressEngineLighting( true ); float color[3] = { 1.0f, 1.0f, 1.0f }; render->SetColorModulation( color ); render->SetBlend( 1.0f ); pPlayerModel->DrawModel( STUDIO_RENDER );
if ( pWeaponModel ) { pWeaponModel->DrawModel( STUDIO_RENDER ); }
modelrender->SuppressEngineLighting( false ); //=============================================================================
// HPE_END
//=============================================================================
render->PopView( dummyFrustum ); }
bool WillPanelBeVisible( vgui::VPANEL hPanel ) { while ( hPanel ) { if ( !vgui::ipanel()->IsVisible( hPanel ) ) return false;
hPanel = vgui::ipanel()->GetParent( hPanel ); } return true; }
void ClientModeCSNormal::PostRenderVGui() { // If the team menu is up, then we will render the model of the character that is currently selected.
for ( int i=0; i < g_ClassImagePanels.Count(); i++ ) { CCSClassImagePanel *pPanel = g_ClassImagePanels[i]; if ( WillPanelBeVisible( pPanel->GetVPanel() ) ) { // Ok, we have a visible class image panel.
int x, y, w, h; pPanel->GetBounds( x, y, w, h ); pPanel->LocalToScreen( x, y );
// Allow for the border.
x += 3; y += 5; w -= 2; h -= 10;
UpdateClassImageEntity( g_ClassImagePanels[i]->m_ModelName, x, y, w, h ); return; } } }
bool ClientModeCSNormal::ShouldDrawViewModel( void ) { C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer(); if( pPlayer && pPlayer->GetFOV() != CSGameRules()->DefaultFOV() ) { CWeaponCSBase *pWpn = pPlayer->GetActiveCSWeapon();
if( pWpn && pWpn->HideViewModelWhenZoomed() ) { return false; } }
return BaseClass::ShouldDrawViewModel(); }
bool ClientModeCSNormal::CanRecordDemo( char *errorMsg, int length ) const { C_CSPlayer *player = C_CSPlayer::GetLocalCSPlayer(); if ( !player ) { return true; }
if ( !player->IsAlive() ) { return true; }
// don't start recording while flashed, as it would remove the flash
if ( player->m_flFlashBangTime > gpGlobals->curtime ) { Q_strncpy( errorMsg, "Cannot record demos while blind.", length ); return false; }
// don't start recording while smoke grenades are spewing smoke, as the existing smoke would be destroyed
C_BaseEntityIterator it; C_BaseEntity *ent; while ( (ent = it.Next()) != NULL ) { if ( Q_strcmp( ent->GetClassname(), "class C_ParticleSmokeGrenade" ) == 0 ) { Q_strncpy( errorMsg, "Cannot record demos while a smoke grenade is active.", length ); return false; } }
return true; }
//=============================================================================
// HPE_BEGIN:
// [menglish] Save server information shown to the client in a persistent place
//=============================================================================
void ClientModeCSNormal::SetServerName(wchar_t* name) { V_wcsncpy(m_pServerName, name, sizeof( m_pServerName ) ); }
void ClientModeCSNormal::SetMapName(wchar_t* name) { V_wcsncpy(m_pMapName, name, sizeof( m_pMapName ) ); }
//=============================================================================
// HPE_END
//=============================================================================
// Receive the PlayerIgnited user message and send out a clientside event for achievements to hook.
void __MsgFunc_MatchEndConditions( bf_read &msg ) { int iFragLimit = (int) msg.ReadLong(); int iMaxRounds = (int) msg.ReadLong(); int iWinRounds = (int) msg.ReadLong(); int iTimeLimit = (int) msg.ReadLong();
IGameEvent *event = gameeventmanager->CreateEvent( "match_end_conditions" ); if ( event ) { event->SetInt( "frags", iFragLimit ); event->SetInt( "max_rounds", iMaxRounds ); event->SetInt( "win_rounds", iWinRounds ); event->SetInt( "time", iTimeLimit ); gameeventmanager->FireEventClientSide( event ); } }
|