source-engine/game/server/portal/prop_portal_stats_display.cpp
2022-04-16 12:05:19 +03:00

478 lines
13 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements the big scary boom-boom machine Antlions fear.
//
//=============================================================================//
#include "cbase.h"
#include "baseanimating.h"
#include "portal_player.h"
#include "EnvMessage.h"
#include "fmtstr.h"
#include "vguiscreen.h"
#include "point_bonusmaps_accessor.h"
#include "portal_shareddefs.h"
#define PORTAL_STATS_DISPLAY_MODEL_NAME "models/props/Round_elevator_body.mdl"
class CPropPortalStatsDisplay : public CBaseAnimating
{
public:
DECLARE_CLASS( CPropPortalStatsDisplay, CBaseAnimating );
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
virtual ~CPropPortalStatsDisplay();
virtual int UpdateTransmitState();
virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
virtual void Spawn( void );
virtual void Precache( void );
virtual void OnRestore( void );
void ScreenVisible( bool bVisible );
void Disable( void );
void Enable( void );
void InputDisable( inputdata_t &inputdata );
void InputEnable( inputdata_t &inputdata );
void InputUpdateStats( inputdata_t &inputdata );
void InputResetPlayerStats( inputdata_t &inputdata );
private:
CNetworkVar( bool, m_bEnabled );
CNetworkVar( int, m_iNumPortalsPlaced );
CNetworkVar( int, m_iNumStepsTaken );
CNetworkVar( float, m_fNumSecondsTaken );
CNetworkVar( int, m_iBronzeObjective );
CNetworkVar( int, m_iSilverObjective );
CNetworkVar( int, m_iGoldObjective );
CNetworkString( szChallengeFileName, 128 );
CNetworkString( szChallengeMapName, 32 );
CNetworkString( szChallengeName, 32 );
CNetworkVar( int, m_iDisplayObjective );
COutputEvent m_OnMetBronzeObjective;
COutputEvent m_OnMetSilverObjective;
COutputEvent m_OnMetGoldObjective;
COutputEvent m_OnFailedAllObjectives;
private:
// Control panel
void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName );
void GetControlPanelClassName( int nPanelIndex, const char *&pPanelName );
void SpawnControlPanels( void );
void RestoreControlPanels( void );
typedef CHandle<CVGuiScreen> ScreenHandle_t;
CUtlVector<ScreenHandle_t> m_hScreens;
};
LINK_ENTITY_TO_CLASS( prop_portal_stats_display, CPropPortalStatsDisplay );
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CPropPortalStatsDisplay )
DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ),
DEFINE_FIELD( m_iNumPortalsPlaced, FIELD_INTEGER ),
DEFINE_FIELD( m_iNumStepsTaken, FIELD_INTEGER ),
DEFINE_FIELD( m_fNumSecondsTaken, FIELD_FLOAT ),
DEFINE_FIELD( m_iBronzeObjective, FIELD_INTEGER ),
DEFINE_FIELD( m_iSilverObjective, FIELD_INTEGER ),
DEFINE_FIELD( m_iGoldObjective, FIELD_INTEGER ),
DEFINE_AUTO_ARRAY( szChallengeFileName, FIELD_CHARACTER ),
DEFINE_AUTO_ARRAY( szChallengeMapName, FIELD_CHARACTER ),
DEFINE_AUTO_ARRAY( szChallengeName, FIELD_CHARACTER ),
DEFINE_FIELD( m_iDisplayObjective, FIELD_INTEGER ),
//DEFINE_UTLVECTOR( m_hScreens, FIELD_EHANDLE ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "UpdateStats", InputUpdateStats ),
DEFINE_INPUTFUNC( FIELD_VOID, "ResetPlayerStats", InputResetPlayerStats ),
DEFINE_OUTPUT ( m_OnMetBronzeObjective, "OnMetBronzeObjective" ),
DEFINE_OUTPUT ( m_OnMetSilverObjective, "OnMetSilverObjective" ),
DEFINE_OUTPUT ( m_OnMetGoldObjective, "OnMetGoldObjective" ),
DEFINE_OUTPUT ( m_OnFailedAllObjectives, "OnFailedAllObjectives" ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CPropPortalStatsDisplay, DT_PropPortalStatsDisplay )
SendPropBool( SENDINFO(m_bEnabled) ),
SendPropInt( SENDINFO(m_iNumPortalsPlaced) ),
SendPropInt( SENDINFO(m_iNumStepsTaken) ),
SendPropFloat( SENDINFO(m_fNumSecondsTaken) ),
SendPropInt( SENDINFO(m_iBronzeObjective) ),
SendPropInt( SENDINFO(m_iSilverObjective) ),
SendPropInt( SENDINFO(m_iGoldObjective) ),
SendPropString( SENDINFO( szChallengeFileName ) ),
SendPropString( SENDINFO( szChallengeMapName ) ),
SendPropString( SENDINFO( szChallengeName ) ),
SendPropInt( SENDINFO(m_iDisplayObjective) ),
END_SEND_TABLE()
CPropPortalStatsDisplay::~CPropPortalStatsDisplay()
{
int i;
// Kill the control panels
for ( i = m_hScreens.Count(); --i >= 0; )
{
DestroyVGuiScreen( m_hScreens[i].Get() );
}
m_hScreens.RemoveAll();
}
int CPropPortalStatsDisplay::UpdateTransmitState()
{
return SetTransmitState( FL_EDICT_FULLCHECK );
}
void CPropPortalStatsDisplay::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
{
// Are we already marked for transmission?
if ( pInfo->m_pTransmitEdict->Get( entindex() ) )
return;
BaseClass::SetTransmit( pInfo, bAlways );
// Force our screens to be sent too.
for ( int i=0; i < m_hScreens.Count(); i++ )
{
CVGuiScreen *pScreen = m_hScreens[i].Get();
pScreen->SetTransmit( pInfo, bAlways );
}
}
void CPropPortalStatsDisplay::Spawn( void )
{
char *szModel = (char *)STRING( GetModelName() );
if (!szModel || !*szModel)
{
szModel = PORTAL_STATS_DISPLAY_MODEL_NAME;
SetModelName( AllocPooledString(szModel) );
}
Precache();
SetModel( szModel );
SetSolid( SOLID_VPHYSICS );
VPhysicsInitStatic();
BaseClass::Spawn();
int iBronze, iSilver, iGold;
BonusMapChallengeObjectives( iBronze, iSilver, iGold );
m_iBronzeObjective = iBronze;
m_iSilverObjective = iSilver;
m_iGoldObjective = iGold;
BonusMapChallengeNames( szChallengeFileName.GetForModify(), szChallengeMapName.GetForModify(), szChallengeName.GetForModify() );
m_bEnabled = false;
int iSequence = SelectHeaviestSequence ( ACT_IDLE );
if ( iSequence != ACT_INVALID )
{
SetSequence( iSequence );
ResetSequenceInfo();
//Do this so we get the nice ramp-up effect.
m_flPlaybackRate = random->RandomFloat( 0.0f, 1.0f );
}
SpawnControlPanels();
ScreenVisible( m_bEnabled );
}
void CPropPortalStatsDisplay::Precache( void )
{
BaseClass::Precache();
PrecacheModel( STRING( GetModelName() ) );
PrecacheVGuiScreen( "portal_stats_display_screen" );
}
void CPropPortalStatsDisplay::OnRestore( void )
{
BaseClass::OnRestore();
RestoreControlPanels();
ScreenVisible( m_bEnabled );
}
void CPropPortalStatsDisplay::ScreenVisible( bool bVisible )
{
for ( int iScreen = 0; iScreen < m_hScreens.Count(); ++iScreen )
{
CVGuiScreen *pScreen = m_hScreens[ iScreen ].Get();
if ( bVisible )
pScreen->RemoveEffects( EF_NODRAW );
else
pScreen->AddEffects( EF_NODRAW );
}
}
void CPropPortalStatsDisplay::Disable( void )
{
if ( !m_bEnabled )
return;
m_bEnabled = false;
ScreenVisible( false );
}
void CPropPortalStatsDisplay::Enable( void )
{
if ( m_bEnabled )
return;
// Don't show stats display in non challenge mode!
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
if ( pPlayer && pPlayer->GetBonusChallenge() == 0 )
return;
m_bEnabled = true;
m_iDisplayObjective = pPlayer->GetBonusChallenge() - 1;
// Check if they beat objectives
if ( pPlayer->GetBonusProgress() <= m_iBronzeObjective )
m_OnMetBronzeObjective.FireOutput( this, this );
else if ( pPlayer->GetBonusProgress() <= m_iSilverObjective )
m_OnMetSilverObjective.FireOutput( this, this );
else if ( pPlayer->GetBonusProgress() <= m_iGoldObjective )
m_OnMetGoldObjective.FireOutput( this, this );
else
m_OnFailedAllObjectives.FireOutput( this, this );
ScreenVisible( true );
}
void CPropPortalStatsDisplay::InputDisable( inputdata_t &inputdata )
{
Disable();
}
void CPropPortalStatsDisplay::InputEnable( inputdata_t &inputdata )
{
Enable();
}
void CPropPortalStatsDisplay::InputUpdateStats( inputdata_t &inputdata )
{
CPortal_Player *pPlayer = (CPortal_Player *)UTIL_GetCommandClient();
if( pPlayer == NULL )
pPlayer = GetPortalPlayer( 1 ); //last ditch effort
if( pPlayer )
{
m_iNumPortalsPlaced = pPlayer->NumPortalsPlaced();
m_iNumStepsTaken = pPlayer->NumStepsTaken();
m_fNumSecondsTaken = pPlayer->NumSecondsTaken();
// Now that we've recorded it, don't let it change
pPlayer->PauseBonusProgress();
}
}
void CPropPortalStatsDisplay::InputResetPlayerStats( inputdata_t &inputdata )
{
CPortal_Player *pPlayer = (CPortal_Player *)UTIL_GetCommandClient();
if( pPlayer == NULL )
pPlayer = GetPortalPlayer( 1 ); //last ditch effort
if( pPlayer )
{
pPlayer->ResetThisLevelStats();
}
}
void CPropPortalStatsDisplay::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
{
pPanelName = "portal_stats_display_screen";
}
void CPropPortalStatsDisplay::GetControlPanelClassName( int nPanelIndex, const char *&pPanelName )
{
pPanelName = "vgui_screen";
}
//-----------------------------------------------------------------------------
// This is called by the base object when it's time to spawn the control panels
//-----------------------------------------------------------------------------
void CPropPortalStatsDisplay::SpawnControlPanels()
{
char buf[64];
// FIXME: Deal with dynamically resizing control panels?
// If we're attached to an entity, spawn control panels on it instead of use
CBaseAnimating *pEntityToSpawnOn = this;
char *pOrgLL = "statPanel%d_bl";
char *pOrgUR = "statPanel%d_tr";
char *pAttachmentNameLL = pOrgLL;
char *pAttachmentNameUR = pOrgUR;
Assert( pEntityToSpawnOn );
// Lookup the attachment point...
int nPanel;
for ( nPanel = 0; true; ++nPanel )
{
Q_snprintf( buf, sizeof( buf ), pAttachmentNameLL, nPanel );
int nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
if (nLLAttachmentIndex <= 0)
{
// Try and use my panels then
pEntityToSpawnOn = this;
Q_snprintf( buf, sizeof( buf ), pOrgLL, nPanel );
nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
if (nLLAttachmentIndex <= 0)
return;
}
Q_snprintf( buf, sizeof( buf ), pAttachmentNameUR, nPanel );
int nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
if (nURAttachmentIndex <= 0)
{
// Try and use my panels then
Q_snprintf( buf, sizeof( buf ), pOrgUR, nPanel );
nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
if (nURAttachmentIndex <= 0)
return;
}
const char *pScreenName;
GetControlPanelInfo( nPanel, pScreenName );
if (!pScreenName)
continue;
const char *pScreenClassname;
GetControlPanelClassName( nPanel, pScreenClassname );
if ( !pScreenClassname )
continue;
// Compute the screen size from the attachment points...
matrix3x4_t panelToWorld;
pEntityToSpawnOn->GetAttachment( nLLAttachmentIndex, panelToWorld );
matrix3x4_t worldToPanel;
MatrixInvert( panelToWorld, worldToPanel );
// Now get the lower right position + transform into panel space
Vector lr, lrlocal;
pEntityToSpawnOn->GetAttachment( nURAttachmentIndex, panelToWorld );
MatrixGetColumn( panelToWorld, 3, lr );
VectorTransform( lr, worldToPanel, lrlocal );
float flWidth = lrlocal.x;
float flHeight = lrlocal.y;
CVGuiScreen *pScreen = CreateVGuiScreen( pScreenClassname, pScreenName, pEntityToSpawnOn, this, nLLAttachmentIndex );
pScreen->ChangeTeam( GetTeamNumber() );
pScreen->SetActualSize( flWidth, flHeight );
pScreen->SetActive( true );
pScreen->MakeVisibleOnlyToTeammates( false );
pScreen->SetTransparency( true );
int nScreen = m_hScreens.AddToTail( );
m_hScreens[nScreen].Set( pScreen );
}
}
void CPropPortalStatsDisplay::RestoreControlPanels( void )
{
char buf[64];
// FIXME: Deal with dynamically resizing control panels?
// If we're attached to an entity, spawn control panels on it instead of use
CBaseAnimating *pEntityToSpawnOn = this;
char *pOrgLL = "statPanel%d_bl";
char *pOrgUR = "statPanel%d_tr";
char *pAttachmentNameLL = pOrgLL;
char *pAttachmentNameUR = pOrgUR;
Assert( pEntityToSpawnOn );
// Lookup the attachment point...
int nPanel;
for ( nPanel = 0; true; ++nPanel )
{
Q_snprintf( buf, sizeof( buf ), pAttachmentNameLL, nPanel );
int nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
if (nLLAttachmentIndex <= 0)
{
// Try and use my panels then
pEntityToSpawnOn = this;
Q_snprintf( buf, sizeof( buf ), pOrgLL, nPanel );
nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
if (nLLAttachmentIndex <= 0)
return;
}
Q_snprintf( buf, sizeof( buf ), pAttachmentNameUR, nPanel );
int nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
if (nURAttachmentIndex <= 0)
{
// Try and use my panels then
Q_snprintf( buf, sizeof( buf ), pOrgUR, nPanel );
nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
if (nURAttachmentIndex <= 0)
return;
}
const char *pScreenName;
GetControlPanelInfo( nPanel, pScreenName );
if (!pScreenName)
continue;
const char *pScreenClassname;
GetControlPanelClassName( nPanel, pScreenClassname );
if ( !pScreenClassname )
continue;
CVGuiScreen *pScreen = (CVGuiScreen *)gEntList.FindEntityByClassname( NULL, pScreenClassname );
while ( pScreen && pScreen->GetOwnerEntity() != this && Q_strcmp( pScreen->GetPanelName(), pScreenName ) == 0 )
{
pScreen = (CVGuiScreen *)gEntList.FindEntityByClassname( pScreen, pScreenClassname );
}
if ( pScreen )
{
int nScreen = m_hScreens.AddToTail( );
m_hScreens[nScreen].Set( pScreen );
}
}
}