Init comit

This commit is contained in:
Gigaslav
2025-05-21 21:20:08 +03:00
parent c59edfa1ce
commit 9a283535e7
5961 changed files with 2343666 additions and 0 deletions

31
game/client/vgui_int.h Normal file
View File

@@ -0,0 +1,31 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#if !defined( VGUI_INT_H )
#define VGUI_INT_H
#ifdef _WIN32
#pragma once
#endif
#include "interface.h"
#include <vgui/VGUI.h>
namespace vgui
{
class Panel;
}
bool VGui_Startup( CreateInterfaceFn appSystemFactory );
void VGui_Shutdown( void );
void VGui_CreateGlobalPanels( void );
vgui::VPANEL VGui_GetClientDLLRootPanel( void );
void VGUI_CreateClientDLLRootPanel( void );
void VGUI_DestroyClientDLLRootPanel( void );
void VGui_PreRender();
void VGui_PostRender();
#endif // VGUI_INT_H

View File

@@ -0,0 +1,176 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "iloadingdisc.h"
#include "vgui_controls/Frame.h"
#include "vgui_controls/Label.h"
#include "hud_numericdisplay.h"
#include "vgui/ISurface.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Displays the loading plaque
//-----------------------------------------------------------------------------
class CLoadingDiscPanel : public vgui::EditablePanel
{
typedef vgui::EditablePanel BaseClass;
public:
CLoadingDiscPanel( vgui::VPANEL parent );
~CLoadingDiscPanel();
virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
int w, h;
w = ScreenWidth();
h = ScreenHeight();
if ( w != m_ScreenSize[ 0 ] ||
h != m_ScreenSize[ 1 ] )
{
m_ScreenSize[ 0 ] = w;
m_ScreenSize[ 1 ] = h;
// Re-perform the layout if the screen size changed
LoadControlSettings( "resource/LoadingDiscPanel.res" );
}
// center the dialog
int wide, tall;
GetSize( wide, tall );
SetPos( ( w - wide ) / 2, ( h - tall ) / 2 );
}
virtual void PaintBackground()
{
SetBgColor( Color(0, 0, 0, 128) );
SetPaintBackgroundType( 2 );
BaseClass::PaintBackground();
}
virtual void SetText( const char *text )
{
m_pLoadingLabel->SetText( text );
}
private:
vgui::Label *m_pLoadingLabel;
int m_ScreenSize[ 2 ];
};
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CLoadingDiscPanel::CLoadingDiscPanel( vgui::VPANEL parent ) : BaseClass( NULL, "CLoadingDiscPanel" )
{
int w, h;
w = ScreenWidth();
h = ScreenHeight();
SetParent( parent );
SetProportional( true );
SetScheme( "ClientScheme" );
SetVisible( false );
SetCursor( NULL );
m_pLoadingLabel = vgui::SETUP_PANEL(new vgui::Label( this, "LoadingLabel", "" ));
m_pLoadingLabel->SetPaintBackgroundEnabled( false );
LoadControlSettings( "resource/LoadingDiscPanel.res" );
// center the dialog
int wide, tall;
GetSize( wide, tall );
SetPos( ( w - wide ) / 2, ( h - tall ) / 2 );
m_ScreenSize[ 0 ] = w;
m_ScreenSize[ 1 ] = h;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CLoadingDiscPanel::~CLoadingDiscPanel()
{
}
class CLoadingDisc : public ILoadingDisc
{
private:
CLoadingDiscPanel *loadingDiscPanel;
CLoadingDiscPanel *m_pPauseDiscPanel;
vgui::VPANEL m_hParent;
public:
CLoadingDisc( void )
{
loadingDiscPanel = NULL;
m_pPauseDiscPanel = NULL;
}
void Create( vgui::VPANEL parent )
{
// don't create now, only when it's needed
m_hParent = parent;
}
void Destroy( void )
{
if ( loadingDiscPanel )
{
loadingDiscPanel->SetParent( (vgui::Panel *)NULL );
delete loadingDiscPanel;
loadingDiscPanel = NULL;
}
if ( m_pPauseDiscPanel )
{
m_pPauseDiscPanel->SetParent( (vgui::Panel *)NULL );
delete m_pPauseDiscPanel;
m_pPauseDiscPanel = NULL;
}
m_hParent = NULL;
}
void SetLoadingVisible( bool bVisible )
{
// demand-create the dialog
if ( bVisible && !loadingDiscPanel )
{
loadingDiscPanel = vgui::SETUP_PANEL(new CLoadingDiscPanel( m_hParent ) );
}
if ( loadingDiscPanel )
{
loadingDiscPanel->SetVisible( bVisible );
}
}
void SetPausedVisible( bool bVisible )
{
if ( bVisible && !m_pPauseDiscPanel )
{
m_pPauseDiscPanel = vgui::SETUP_PANEL(new CLoadingDiscPanel( m_hParent ) );
m_pPauseDiscPanel->SetText( "#gameui_paused" );
}
if ( m_pPauseDiscPanel )
{
m_pPauseDiscPanel->SetVisible( bVisible );
}
}
};
static CLoadingDisc g_LoadingDisc;
ILoadingDisc *loadingdisc = ( ILoadingDisc * )&g_LoadingDisc;

View File

@@ -0,0 +1,467 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include <stdarg.h>
#include "imessagechars.h"
#include <vgui/IVGui.h>
#include "VGuiMatSurface/IMatSystemSurface.h"
#include <vgui_controls/Panel.h>
#include <vgui_controls/Controls.h>
#include <vgui/IScheme.h>
#include <vgui/ISurface.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Simultaneous message limit
#define MAX_MESSAGECHARS_MESSAGES 1024
#define MAX_MESSAGECHARSPANEL_LEN 1024
//-----------------------------------------------------------------------------
// Purpose: Panel for displaying console characters at specified locations
//-----------------------------------------------------------------------------
class CMessageCharsPanel : public vgui::Panel
{
typedef vgui::Panel BaseClass;
public:
// Internal pool of such messages
typedef struct message_s
{
struct message_s *next;
int x, y;
byte r, g, b, a;
char *text;
vgui::HFont hCustomFont;
float fTTL;
int messageID;
} message_t;
// Construct/destruct
CMessageCharsPanel( vgui::VPANEL parent );
virtual ~CMessageCharsPanel( void );
// Add block of text to list
virtual int AddText(
float flTime,
vgui::HFont hCustomFont,
int x,
int y,
int r,
int g,
int b,
int a,
char *fmt,
int messageID,
... );
// Determine text side and height
virtual void GetTextExtents( vgui::HFont hCustomFont, int *wide, int *tall, const char *string );
virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
virtual void Paint();
virtual void OnTick( void );
virtual bool ShouldDraw( void );
void RemoveStringsByID( int messageID );
void Clear( void );
private:
// Allocate a new message
message_t *AllocMessage( void );
// Clear out all messages
void Reset( void );
vgui::HFont m_hFont;
// Pool of messages
message_t m_Messages[ MAX_MESSAGECHARS_MESSAGES ];
message_t *m_pActive;
message_t *m_pFree;
};
//-----------------------------------------------------------------------------
// Purpose:
// Input : *parent -
// Output :
//-----------------------------------------------------------------------------
CMessageCharsPanel::CMessageCharsPanel( vgui::VPANEL parent ) :
BaseClass( NULL, "CMessageCharsPanel" )
{
SetParent( parent );
SetSize( ScreenWidth(), ScreenHeight() );
SetPos( 0, 0 );
SetVisible( true );
SetCursor( null );
SetKeyBoardInputEnabled( false );
SetMouseInputEnabled( false );
m_hFont = vgui::INVALID_FONT;
SetFgColor( Color( 0, 0, 0, 255 ) );
SetPaintBackgroundEnabled( false );
Q_memset( m_Messages, 0, sizeof( m_Messages ) );
Reset();
vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output :
//-----------------------------------------------------------------------------
CMessageCharsPanel::~CMessageCharsPanel( void )
{
}
void CMessageCharsPanel::ApplySchemeSettings(vgui::IScheme *pScheme)
{
BaseClass::ApplySchemeSettings(pScheme);
m_hFont = pScheme->GetFont( "Default" );
Assert( m_hFont != vgui::INVALID_FONT );
SetSize( ScreenWidth(), ScreenHeight() );
SetPos( 0, 0 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMessageCharsPanel::Clear( void )
{
Reset();
}
//-----------------------------------------------------------------------------
// Purpose: Reset all messages
//-----------------------------------------------------------------------------
void CMessageCharsPanel::Reset( void )
{
m_pActive = NULL;
int i;
for( i = 0; i < MAX_MESSAGECHARS_MESSAGES-1; i++ )
{
if ( m_Messages[ i ].text )
{
delete[] m_Messages[ i ].text;
m_Messages[ i ].text = NULL;
}
m_Messages[ i ].next = &m_Messages[ i + 1 ];
}
m_Messages[ i ].next = NULL;
m_pFree = &m_Messages[ 0 ];
SetVisible( false );
}
//-----------------------------------------------------------------------------
// Purpose: Allocate a message if possible
// Output : CMessageCharsPanel::message_t
//-----------------------------------------------------------------------------
CMessageCharsPanel::message_t *CMessageCharsPanel::AllocMessage( void )
{
CMessageCharsPanel::message_t *msg;
if ( !m_pFree )
return NULL;
msg = m_pFree;
m_pFree = m_pFree->next;
msg->next = m_pActive;
m_pActive = msg;
msg->x = 0;
msg->y = 0;
msg->text = NULL;
msg->hCustomFont = NULL;
return msg;
}
//-----------------------------------------------------------------------------
// Purpose: Allocate message and fill in data
// Input : x -
// y -
// *fmt -
// ... -
// Output : int
//-----------------------------------------------------------------------------
int CMessageCharsPanel::AddText(
float flTime,
vgui::HFont hCustomFont,
int x,
int y,
int r,
int g,
int b,
int a,
char *fmt,
int messageID,
... )
{
va_list argptr;
char data[ MAX_MESSAGECHARSPANEL_LEN ];
int len;
va_start(argptr, messageID);
len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
va_end(argptr);
data[ MAX_MESSAGECHARSPANEL_LEN - 1 ] = 0;
CMessageCharsPanel::message_t *msg = AllocMessage();
if ( !msg )
return x;
msg->x = x;
msg->y = y;
msg->r = r;
msg->g = g;
msg->b = b;
msg->a = a;
msg->messageID = messageID;
Assert( !msg->text );
int textLength = Q_strlen( data ) + 1;
msg->text = new char[ textLength ];
Assert( msg->text );
Q_strncpy( msg->text, data, textLength );
if ( flTime )
msg->fTTL = gpGlobals->curtime + flTime;
else
msg->fTTL = 0;
SetVisible( true );
if ( hCustomFont )
msg->hCustomFont = hCustomFont;
else
msg->hCustomFont = m_hFont;
// Return new cursor position
return x + g_pMatSystemSurface->DrawTextLen( msg->hCustomFont, data );
}
//-----------------------------------------------------------------------------
// Purpose: Determine text size ahead of time
// Input : *wide -
// *tall -
// *string -
//-----------------------------------------------------------------------------
void CMessageCharsPanel::GetTextExtents( vgui::HFont hCustomFont, int *wide, int *tall, const char *string )
{
if ( !hCustomFont )
{
// Make sure we actually have the font...
vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
hCustomFont = pScheme->GetFont( "Default" );
}
Assert( hCustomFont );
*wide = g_pMatSystemSurface->DrawTextLen( hCustomFont, (char *)string );
*tall = vgui::surface()->GetFontTall( hCustomFont );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMessageCharsPanel::OnTick( void )
{
bool bVisible = ShouldDraw();
if ( IsVisible() != bVisible )
{
SetVisible( bVisible );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CMessageCharsPanel::ShouldDraw( void )
{
if ( !m_pActive )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
//-----------------------------------------------------------------------------
void CMessageCharsPanel::Paint()
{
CMessageCharsPanel::message_t *msg = m_pActive;
while ( msg )
{
g_pMatSystemSurface->DrawColoredText( msg->hCustomFont, msg->x, msg->y, msg->r, msg->g, msg->b, msg->a, msg->text );
msg = msg->next;
}
// Clear our dead messages
message_t *pPrev = NULL;
message_t *pCurrent = m_pActive;
while ( pCurrent )
{
if ( pCurrent->fTTL <= gpGlobals->curtime )
{
// Move it to the free list
if ( !pPrev )
{
m_pActive = pCurrent->next;
}
else
{
pPrev->next = pCurrent->next;
}
// Store off next one, because we're about to move the current
message_t *pNext = pCurrent->next;
delete[] pCurrent->text;
pCurrent->text = NULL;
pCurrent->next = m_pFree;
m_pFree = pCurrent;
// Don't advance pPrev
pCurrent = pNext;
continue;
}
pPrev = pCurrent;
pCurrent = pCurrent->next;
}
}
void CMessageCharsPanel::RemoveStringsByID( int messageID )
{
for ( message_t *pCurrent = m_pActive; pCurrent; pCurrent = pCurrent->next )
{
if ( pCurrent->messageID == messageID )
pCurrent->fTTL = gpGlobals->curtime - 1000;
}
}
class CMessageChars : public IMessageChars
{
private:
CMessageCharsPanel *messageCharsPanel;
public:
CMessageChars( void )
{
messageCharsPanel = NULL;
}
void Create( vgui::VPANEL parent )
{
messageCharsPanel = new CMessageCharsPanel( parent );
}
void Destroy( void )
{
if ( messageCharsPanel )
{
messageCharsPanel->SetParent( (vgui::Panel *)NULL );
delete messageCharsPanel;
messageCharsPanel = NULL;
}
}
int DrawStringForTime( float flTime, vgui::HFont hCustomFont, int x, int y, int r, int g, int b, int a, const char *fmt, int messageID, ... )
{
va_list argptr;
char data[ MAX_MESSAGECHARSPANEL_LEN ];
int len;
va_start(argptr, messageID);
len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
va_end(argptr);
data[ MAX_MESSAGECHARSPANEL_LEN - 1 ] = 0;
if ( !messageCharsPanel )
return x;
return messageCharsPanel->AddText( flTime, hCustomFont, x, y, r, g, b, a, data, messageID );
}
int DrawStringForTime( float flTime, vgui::HFont hCustomFont, int x, int y, const char *fmt, int messageID, ... )
{
int r = 192, g = 192, b = 192;
va_list argptr;
va_start(argptr, messageID);
int result = DrawString( hCustomFont, x, y, r, g, b, 255, fmt, messageID, argptr );
va_end( argptr );
return result;
}
virtual void RemoveStringsByID( int messageID )
{
messageCharsPanel->RemoveStringsByID( messageID );
}
int DrawString( vgui::HFont hCustomFont, int x, int y, int r, int g, int b, int a, const char *fmt, int messageID, ... )
{
va_list argptr;
va_start(argptr, messageID);
int result = DrawStringForTime( 0, hCustomFont, x, y, r, g, b, a, fmt, messageID, argptr );
va_end( argptr );
return result;
}
int DrawString( vgui::HFont hCustomFont, int x, int y, const char *fmt, int messageID, ... )
{
va_list argptr;
va_start(argptr, messageID);
int result = DrawStringForTime( 0, hCustomFont, x, y, fmt, messageID, argptr );
va_end( argptr );
return result;
}
void GetStringLength( vgui::HFont hCustomFont, int *width, int *height, const char *fmt, ... )
{
if ( !messageCharsPanel )
{
return;
}
va_list argptr;
char data[ MAX_MESSAGECHARSPANEL_LEN ];
int len;
va_start(argptr, fmt);
len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
va_end(argptr);
data[ MAX_MESSAGECHARSPANEL_LEN - 1 ] = 0;
messageCharsPanel->GetTextExtents( hCustomFont, width, height, data );
}
void Clear( void )
{
if ( !messageCharsPanel )
return;
messageCharsPanel->Clear();
}
};
static CMessageChars g_MessageChars;
IMessageChars *messagechars = ( IMessageChars * )&g_MessageChars;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,291 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//=======================================================================================//
#include "cbase.h"
#include "vgui_schemevisualizer.h"
#include "vgui/IBorder.h"
#include "vgui/ISurface.h"
#include "vgui/IVGui.h"
#include "vgui_controls/Label.h"
#include "vgui_controls/ComboBox.h"
#include "KeyValues.h"
#include "fmtstr.h"
//----------------------------------------------------------------------------------------
using namespace vgui;
//----------------------------------------------------------------------------------------
class CBorderVisualizerPanel : public Panel
{
DECLARE_CLASS_SIMPLE( CBorderVisualizerPanel, Panel );
public:
CBorderVisualizerPanel( Panel *pParent, const char *pName, IBorder *pBorder );
private:
virtual void Paint();
IBorder *m_pBorder;
};
//----------------------------------------------------------------------------------------
CBorderVisualizerPanel::CBorderVisualizerPanel( Panel *pParent, const char *pName, IBorder *pBorder )
: Panel( pParent, pName ),
m_pBorder( pBorder )
{
SetBgColor( Color( 255, 0, 0, 255 ) );
}
void CBorderVisualizerPanel::Paint()
{
BaseClass::Paint();
surface()->PushMakeCurrent( GetVPanel(), false );
m_pBorder->Paint( GetVPanel() );
surface()->PopMakeCurrent( GetVPanel() );
}
//----------------------------------------------------------------------------------------
class CColorVisualizerPanel : public Panel
{
DECLARE_CLASS_SIMPLE( CColorVisualizerPanel, Panel );
public:
CColorVisualizerPanel( Panel *pParent, const char *pName, const Color &color );
private:
virtual void Paint();
Color m_Color;
};
//----------------------------------------------------------------------------------------
CColorVisualizerPanel::CColorVisualizerPanel( Panel *pParent, const char *pName, const Color &color )
: Panel( pParent, pName ),
m_Color( color )
{
}
void CColorVisualizerPanel::Paint()
{
BaseClass::Paint();
int nHorzBuffer = XRES( 2 );
int nVertBuffer = YRES( 2 );
surface()->DrawSetColor( m_Color );
surface()->DrawFilledRect( nHorzBuffer, nVertBuffer, GetWide() - 2 * nHorzBuffer, GetTall() - 2 * nVertBuffer );
}
//----------------------------------------------------------------------------------------
CSchemeVisualizer::CSchemeVisualizer( vgui::Panel *pParent, IScheme *pViewScheme, const char *pSchemeName )
: vgui::Frame( pParent, "SchemeVisualizer" ),
m_pViewScheme( pViewScheme ),
m_pList( NULL ),
m_nListDataType( LISTDATATYPE_INVALID )
{
CFmtStr fmtTitle( "Scheme Visualizer - scheme: \"%s\"", pSchemeName );
SetTitle( fmtTitle.Access(), true );
SetTitleBarVisible( true );
SetMoveable( true );
SetCloseButtonVisible( true );
SetMinimizeButtonVisible( false );
SetMaximizeButtonVisible( false );
m_pListDataTypeCombo = new ComboBox( this, "DataTypeCombo", 3, false );
m_aComboDataTypeToItemIDMap[ LISTDATATYPE_BORDERS ] = m_pListDataTypeCombo->AddItem( "Borders", NULL );
m_aComboDataTypeToItemIDMap[ LISTDATATYPE_FONTS ] = m_pListDataTypeCombo->AddItem( "Fonts", NULL );
m_aComboDataTypeToItemIDMap[ LISTDATATYPE_COLORS ] = m_pListDataTypeCombo->AddItem( "Colors", NULL );
m_pListDataTypeCombo->SilentActivateItemByRow( 0 );
m_pListDataTypeCombo->AddActionSignalTarget( this );
m_nSelectedComboItem = m_aComboDataTypeToItemIDMap[ LISTDATATYPE_BORDERS ];
UpdateList( LISTDATATYPE_BORDERS );
ivgui()->AddTickSignal( GetVPanel(), 100 );
}
CSchemeVisualizer::~CSchemeVisualizer()
{
ivgui()->RemoveTickSignal( GetVPanel() );
}
void CSchemeVisualizer::PerformLayout()
{
BaseClass::PerformLayout();
const int nComboWidth = XRES( 50 );
m_pListDataTypeCombo->SetBounds(
GetWide() - nComboWidth - XRES( 10 ),
YRES( 2 ),
nComboWidth,
YRES( 8 )
);
const int nHorzBuffer = XRES( 2 );
const int nVertBuffer = YRES( 10 );
m_pList->SetBounds( nHorzBuffer, nVertBuffer, GetWide() - 2 * nHorzBuffer, GetTall() - 1.5f * nVertBuffer );
}
void CSchemeVisualizer::UpdateList( ListDataType_t nType )
{
Assert( nType != m_nListDataType );
// Cache off type
m_nListDataType = nType;
// Clear the list
if ( m_pList )
{
m_pList->MarkForDeletion();
}
m_pList = new PanelListPanel( this, "ListPanel" );
m_pList->SetBgColor( Color( 0, 255, 0, 255 ) );
m_pList->SetPaintBackgroundEnabled( true );
InvalidateLayout( true, false );
// Set default column width - may be changed depending on type
m_pList->SetFirstColumnWidth( XRES( 50 ) );
switch( nType )
{
case LISTDATATYPE_BORDERS: AddBordersToList(); break;
case LISTDATATYPE_FONTS: AddFontsToList(); break;
case LISTDATATYPE_COLORS: AddColorsToList(); break;
}
}
void CSchemeVisualizer::AddBordersToList()
{
const int nBorderCount = m_pViewScheme->GetBorderCount();
for ( int i = 0; i < nBorderCount; ++i )
{
IBorder *pCurBorder = m_pViewScheme->GetBorderAtIndex( i );
CFmtStr fmtName( "BorderPanel_%s", pCurBorder->GetName() );
CBorderVisualizerPanel *pNewBorderPanel = new CBorderVisualizerPanel( m_pList, fmtName.Access(), pCurBorder );
pNewBorderPanel->SetSize( m_pList->GetWide(), YRES( 45 ) );
m_pList->AddItem( new Label( NULL, "Label", pCurBorder->GetName() ), pNewBorderPanel );
}
}
void CSchemeVisualizer::AddFontsToList()
{
#ifdef POSIX
const char strOAccent[] = { 0xc3, 0x93, 0x00 }; // UTF-8 for U+00D3 (LATIN CAPITAL LETTER O WITH ACUTE)
#else
const uint8 strOAccent[] = { 0xd3, 0x00 };
#endif
// Stick an intl character in here to test accents (O')
CFmtStr fmtText( "ABCDEFGHIJKLMN%sPQRSTUVWXYZabcdefhijklmnopqrstuvwxyz0123456789!@#$%%^&*()-_=+", strOAccent );
const int nFontCount = m_pViewScheme->GetFontCount();
for ( int i = 0; i < nFontCount; ++i )
{
HFont hCurFont = m_pViewScheme->GetFontAtIndex( i );
const char *pCurFontName = m_pViewScheme->GetFontName( hCurFont );
CFmtStr fmtName( "FontPanel_%s", pCurFontName );
Label *pNewFontLabel = new Label( m_pList, fmtName.Access(), fmtText.Access() );
pNewFontLabel->SetFont( hCurFont );
pNewFontLabel->SizeToContents();
pNewFontLabel->SetWide( m_pList->GetWide() );
m_pList->AddItem( new Label( NULL, "Label", pCurFontName ), pNewFontLabel );
}
}
void CSchemeVisualizer::AddColorsToList()
{
KeyValues *pColorData = (KeyValues *)m_pViewScheme->GetColorData();
FOR_EACH_SUBKEY( pColorData, pCurColor )
{
const char *pCurColorName = pCurColor->GetName();
CFmtStr fmtName( "ColorPanel_%s", pCurColorName );
int r = 0, g = 0, b = 0, a = 0;
const char *pCurColorRGBA = pCurColor->GetString();
if ( sscanf( pCurColorRGBA, "%d %d %d %d", &r, &g, &b, &a) < 3 )
{
Warning( "Skipping color \"%s\"\n", pCurColorRGBA );
continue;
}
CColorVisualizerPanel *pNewColorPanel = new CColorVisualizerPanel( m_pList, fmtName.Access(), Color(r,g,b,a) );
pNewColorPanel->SetSize( m_pList->GetWide(), YRES( 25 ) );
m_pList->AddItem( new Label( NULL, "Label", pCurColorName ), pNewColorPanel );
}
}
//----------------------------------------------------------------------------------------
static CSchemeVisualizer *g_pSchemeVisualizer = NULL;
//----------------------------------------------------------------------------------------
CON_COMMAND( showschemevisualizer, "Show borders, fonts and colors for a particular scheme. The default is ClientScheme.res" )
{
if ( g_pSchemeVisualizer )
{
g_pSchemeVisualizer->MarkForDeletion();
g_pSchemeVisualizer = NULL;
}
// Load a scheme - defaults to "ClientScheme"
const char *pSchemeName = "ClientScheme";
if ( args.ArgC() == 2 )
{
pSchemeName = args.Arg( 1 );
}
IScheme *pScheme = scheme()->GetIScheme( scheme()->GetScheme( pSchemeName ) );
Msg( "Using scheme %s...\n", pSchemeName );
g_pSchemeVisualizer = vgui::SETUP_PANEL( new CSchemeVisualizer( NULL, pScheme, pSchemeName ) );
g_pSchemeVisualizer->InvalidateLayout( false, true );
engine->ClientCmd_Unrestricted( "gameui_activate" );
const int nWidth = XRES( 300 );
const int nHeight = YRES( 300 );
g_pSchemeVisualizer->SetBounds(
( ScreenWidth() - nWidth ) / 2,
( ScreenHeight() - nHeight ) / 2,
nWidth,
nHeight
);
g_pSchemeVisualizer->Activate();
}
void CSchemeVisualizer::OnTick()
{
const int nItemID = m_pListDataTypeCombo->GetActiveItem();
if ( m_nSelectedComboItem == nItemID )
return;
// Cache
m_nSelectedComboItem = nItemID;
// Figure out which type was selected
ListDataType_t nType = LISTDATATYPE_INVALID;
for ( int i = 0; i < (int)NUM_TYPES; ++i )
{
if ( nItemID == m_aComboDataTypeToItemIDMap[ i ] )
{
nType = (ListDataType_t)i;
break;
}
}
AssertMsg( nType != LISTDATATYPE_INVALID, "Couldn't find item ID in list - this should never happen." );
// Update the list now
UpdateList( nType );
}

View File

@@ -0,0 +1,55 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//=======================================================================================//
#ifndef VGUI_CLIENTSCHEMEVISUALIZER_H
#define VGUI_CLIENTSCHEMEVISUALIZER_H
//----------------------------------------------------------------------------------------
#include "vgui_controls/Frame.h"
#include "vgui_controls/PanelListPanel.h"
//----------------------------------------------------------------------------------------
class CSchemeVisualizer : public vgui::Frame
{
DECLARE_CLASS_SIMPLE( CSchemeVisualizer, vgui::Frame );
public:
CSchemeVisualizer( vgui::Panel *pParent, vgui::IScheme *pViewScheme, const char *pSchemeName );
virtual ~CSchemeVisualizer();
private:
virtual void PerformLayout();
private:
virtual void OnTick();
enum ListDataType_t
{
LISTDATATYPE_INVALID = -1,
LISTDATATYPE_BORDERS,
LISTDATATYPE_FONTS,
LISTDATATYPE_COLORS,
NUM_TYPES
};
int m_aComboDataTypeToItemIDMap[NUM_TYPES]; // [ data type ] = < item id >
void UpdateList( ListDataType_t nType );
void AddBordersToList();
void AddFontsToList();
void AddColorsToList();
vgui::PanelListPanel *m_pList;
ListDataType_t m_nListDataType; // Currently selected data type
int m_nSelectedComboItem;
vgui::IScheme *m_pViewScheme; // The scheme we're visualizing
vgui::ComboBox *m_pListDataTypeCombo;
};
//----------------------------------------------------------------------------------------
#endif // VGUI_CLIENTSCHEMEVISUALIZER_H

View File

@@ -0,0 +1,174 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "c_vguiscreen.h"
#include "vgui_controls/Label.h"
#include "vgui_bitmappanel.h"
#include <vgui/IVGui.h>
#include "c_slideshow_display.h"
#include "ienginevgui.h"
#include "fmtstr.h"
#include "vgui_controls/ImagePanel.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// Control screen
//-----------------------------------------------------------------------------
class CSlideshowDisplayScreen : public CVGuiScreenPanel
{
DECLARE_CLASS( CSlideshowDisplayScreen, CVGuiScreenPanel );
public:
CSlideshowDisplayScreen( vgui::Panel *parent, const char *panelName );
virtual void ApplySchemeSettings( IScheme *pScheme );
virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
virtual void OnTick();
private:
void Update( C_SlideshowDisplay *pSlideshowDisplay );
private:
vgui::Label *m_pDisplayTextLabel;
CUtlVector<ImagePanel*> m_pSlideshowImages;
int iLastSlideIndex;
Color m_cDefault;
Color m_cInvisible;
bool bIsAlreadyVisible;
};
DECLARE_VGUI_SCREEN_FACTORY( CSlideshowDisplayScreen, "slideshow_display_screen" );
//-----------------------------------------------------------------------------
// Constructor:
//-----------------------------------------------------------------------------
CSlideshowDisplayScreen::CSlideshowDisplayScreen( vgui::Panel *parent, const char *panelName )
: BaseClass( parent, "CSlideshowDisplayScreen", vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/SlideshowDisplayScreen.res", "SlideshowDisplayScreen" ) )
{
m_pDisplayTextLabel = new vgui::Label( this, "NumberDisplay", "x" );
iLastSlideIndex = 0;
}
void CSlideshowDisplayScreen::ApplySchemeSettings( IScheme *pScheme )
{
assert( pScheme );
m_cDefault = pScheme->GetColor( "CSlideshowDisplayScreen_Default", GetFgColor() );
m_cInvisible = Color( 0, 0, 0, 0 );
m_pDisplayTextLabel->SetFgColor( m_cDefault );
}
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
bool CSlideshowDisplayScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
{
// Make sure we get ticked...
vgui::ivgui()->AddTickSignal( GetVPanel() );
if (!BaseClass::Init(pKeyValues, pInitData))
return false;
return true;
}
//-----------------------------------------------------------------------------
// Update the display string
//-----------------------------------------------------------------------------
void CSlideshowDisplayScreen::OnTick()
{
BaseClass::OnTick();
if ( g_SlideshowDisplays.Count() <= 0 )
return;
C_SlideshowDisplay *pSlideshowDisplay = NULL;
for ( int iDisplayScreens = 0; iDisplayScreens < g_SlideshowDisplays.Count(); ++iDisplayScreens )
{
C_SlideshowDisplay *pSlideshowDisplayTemp = g_SlideshowDisplays[ iDisplayScreens ];
if ( pSlideshowDisplayTemp && pSlideshowDisplayTemp->IsEnabled() )
{
pSlideshowDisplay = pSlideshowDisplayTemp;
break;
}
}
if( !pSlideshowDisplay )
{
// All display screens are disabled
if ( bIsAlreadyVisible )
{
SetVisible( false );
bIsAlreadyVisible = false;
}
return;
}
if ( !bIsAlreadyVisible )
{
SetVisible( true );
bIsAlreadyVisible = true;
}
Update( pSlideshowDisplay );
}
void CSlideshowDisplayScreen::Update( C_SlideshowDisplay *pSlideshowDisplay )
{
char szBuff[ 256 ];
pSlideshowDisplay->GetDisplayText( szBuff );
m_pDisplayTextLabel->SetText( szBuff );
if ( m_pSlideshowImages.Count() == 0 )
{
// Build the list of image panels!
for ( int iSlide = 0; iSlide < pSlideshowDisplay->NumMaterials(); ++iSlide )
{
m_pSlideshowImages.AddToTail( SETUP_PANEL( new ImagePanel( this, "SlideshowImage" ) ) );
int iMatIndex = pSlideshowDisplay->GetMaterialIndex( iSlide );
if ( iMatIndex > 0 )
{
const char *pMaterialName = GetMaterialNameFromIndex( iMatIndex );
if ( pMaterialName )
{
pMaterialName = Q_strnchr( pMaterialName, '/', Q_strlen( pMaterialName ) );
if ( pMaterialName )
{
pMaterialName = pMaterialName + 1;
m_pSlideshowImages[ iSlide ]->SetImage( pMaterialName );
m_pSlideshowImages[ iSlide ]->SetVisible( false );
m_pSlideshowImages[ iSlide ]->SetZPos( -3 );
m_pSlideshowImages[ iSlide ]->SetWide( GetWide() );
m_pSlideshowImages[ iSlide ]->SetTall( GetTall() );
}
}
}
}
}
int iCurrentSlideIndex = pSlideshowDisplay->CurrentSlideIndex();
if ( iCurrentSlideIndex != iLastSlideIndex )
{
m_pSlideshowImages[ iLastSlideIndex ]->SetVisible( false );
m_pSlideshowImages[ iCurrentSlideIndex ]->SetVisible( true );
iLastSlideIndex = iCurrentSlideIndex;
}
}

View File

@@ -0,0 +1,414 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "itextmessage.h"
#include <vgui_controls/Panel.h>
#include <vgui/IVGui.h>
#include <vgui/ILocalize.h>
#include "VGuiMatSurface/IMatSystemSurface.h"
#include <vgui_controls/Controls.h>
#include <vgui/ISurface.h>
#include "hud.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Simultaneous message limit
#define MAX_TEXTMESSAGE_CHARS 2048
//-----------------------------------------------------------------------------
// Purpose: For rendering the Titles.txt characters to the screen from the HUD
//-----------------------------------------------------------------------------
class CTextMessagePanel : public vgui::Panel
{
typedef vgui::Panel BaseClass;
public:
enum
{
TYPE_UNKNOWN = 0,
TYPE_POSITION,
TYPE_CHARACTER,
TYPE_FONT,
};
struct message_t
{
vgui::HFont font;
short x, y;
wchar_t ch;
byte type;
byte r, g, b, a;
};
CTextMessagePanel( vgui::VPANEL parent );
virtual ~CTextMessagePanel( void );
virtual void SetPosition( int x, int y );
virtual void AddChar( int r, int g, int b, int a, wchar_t ch );
virtual void GetTextExtents( int *wide, int *tall, const char *string );
virtual void SetFont( vgui::HFont hCustomFont );
virtual void SetDefaultFont( void );
virtual void OnTick( void );
virtual void Paint();
virtual bool ShouldDraw( void );
// Get character data for textmessage text
virtual int GetFontInfo( FONTABC *pABCs, vgui::HFont hFont );
virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
SetSize( ScreenWidth(), ScreenHeight() );
SetPos( 0, 0 );
}
private:
message_t *AllocMessage( void );
void Reset( void );
vgui::HFont m_hFont;
vgui::HFont m_hDefaultFont;
CUtlVector< message_t > m_Messages;
};
//-----------------------------------------------------------------------------
// Purpose: Constructor
// Input : *parent -
//-----------------------------------------------------------------------------
CTextMessagePanel::CTextMessagePanel( vgui::VPANEL parent )
: BaseClass( NULL, "CTextMessagePanel" )
{
SetParent( parent );
SetSize( ScreenWidth(), ScreenHeight() );
SetPos( 0, 0 );
SetVisible( false );
SetCursor( null );
SetKeyBoardInputEnabled( false );
SetMouseInputEnabled( false );
m_hFont = g_hFontTrebuchet24;
m_hDefaultFont = m_hFont;
SetFgColor( Color( 0, 0, 0, 255 ) );
SetPaintBackgroundEnabled( false );
// Clear memory out
Reset();
vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTextMessagePanel::~CTextMessagePanel( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Get font sizes
// Input : *pWidth -
// Output : int
//-----------------------------------------------------------------------------
int CTextMessagePanel::GetFontInfo( FONTABC *pABCs, vgui::HFont hFont )
{
int i;
if ( !hFont )
{
hFont = m_hFont;
}
if ( !hFont )
return 0;
if ( pABCs )
{
for ( i =0; i < 256; i++ )
{
int a, b, c;
vgui::surface()->GetCharABCwide( hFont, (char)i, a, b, c );
pABCs[i].abcA = a;
pABCs[i].abcB = b;
pABCs[i].abcC = c;
pABCs[i].total = a+b+c;
}
}
return vgui::surface()->GetFontTall( hFont );
}
//-----------------------------------------------------------------------------
// Purpose: Clear all messages out of active list, etc.
//-----------------------------------------------------------------------------
void CTextMessagePanel::Reset( void )
{
m_Messages.Purge();
SetVisible( false );
}
//-----------------------------------------------------------------------------
// Purpose: Grab next free message, if any
// Output : CTextMessagePanel::message_t
//-----------------------------------------------------------------------------
CTextMessagePanel::message_t *CTextMessagePanel::AllocMessage( void )
{
CTextMessagePanel::message_t *msg;
if ( m_Messages.Count() >= MAX_TEXTMESSAGE_CHARS )
return NULL;
msg = &m_Messages[ m_Messages.AddToTail() ];
msg->type = TYPE_UNKNOWN;
msg->x = 0;
msg->y = 0;
msg->ch = 0;
msg->r = 0;
msg->g = 0;
msg->b = 0;
msg->a = 0;
SetVisible( true );
return msg;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : x -
// y -
//-----------------------------------------------------------------------------
void CTextMessagePanel::SetPosition( int x, int y )
{
CTextMessagePanel::message_t *msg = AllocMessage();
if ( !msg )
return;
msg->type = TYPE_POSITION;
// Used fields
msg->x = x;
msg->y = y;
}
//-----------------------------------------------------------------------------
// Purpose: Adds a character to the active list, if possible
// Input : x -
// y -
// r -
// g -
// b -
// a -
// ch -
// Output : int
//-----------------------------------------------------------------------------
void CTextMessagePanel::AddChar( int r, int g, int b, int a, wchar_t ch )
{
CTextMessagePanel::message_t *msg = AllocMessage();
if ( !msg )
return;
msg->type = TYPE_CHARACTER;
// Used fields
msg->r = r;
msg->g = g;
msg->b = b;
msg->a = a;
msg->ch = ch;
}
//-----------------------------------------------------------------------------
// Purpose: Determine width and height of specified string
// Input : *wide -
// *tall -
// *string -
//-----------------------------------------------------------------------------
void CTextMessagePanel::GetTextExtents( int *wide, int *tall, const char *string )
{
*wide = g_pMatSystemSurface->DrawTextLen( m_hFont, (char *)string );
*tall = vgui::surface()->GetFontTall( m_hFont );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTextMessagePanel::SetFont( vgui::HFont hCustomFont )
{
m_hFont = hCustomFont;
CTextMessagePanel::message_t *msg = AllocMessage();
if ( !msg )
return;
msg->type = TYPE_FONT;
// Used fields
msg->font = m_hFont;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTextMessagePanel::SetDefaultFont( void )
{
SetFont( m_hDefaultFont );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTextMessagePanel::OnTick( void )
{
SetVisible( ShouldDraw() );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CTextMessagePanel::ShouldDraw( void )
{
if ( !m_Messages.Count() )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Draw current text items
//-----------------------------------------------------------------------------
void CTextMessagePanel::Paint()
{
CTextMessagePanel::message_t *msg;
int xpos = 0, ypos = 0;
vgui::surface()->DrawSetTextFont( m_hFont );
int messageCount = m_Messages.Count();
for ( int i = 0 ; i < messageCount; ++i )
{
msg = &m_Messages[ i ];
switch ( msg->type )
{
default:
case TYPE_UNKNOWN:
Assert( 0 );
break;
case TYPE_POSITION:
xpos = msg->x;
ypos = msg->y;
break;
case TYPE_FONT:
m_hFont = msg->font;
vgui::surface()->DrawSetTextFont( m_hFont );
break;
case TYPE_CHARACTER:
if ( m_hFont )
{
int a, b, c;
vgui::surface()->GetCharABCwide( m_hFont, msg->ch, a, b, c );
if ( msg->ch > 32 )
{
vgui::surface()->DrawSetTextColor( msg->r, msg->g, msg->b, msg->a );
vgui::surface()->DrawSetTextPos( xpos, ypos );
vgui::surface()->DrawUnicodeChar( msg->ch );
}
xpos += a + b + c;
}
break;
}
}
Reset();
}
class CTextMessage : public ITextMessage
{
private:
CTextMessagePanel *textMessagePanel;
public:
CTextMessage( void )
{
textMessagePanel = NULL;
}
void Create( vgui::VPANEL parent )
{
textMessagePanel = new CTextMessagePanel( parent );
}
void Destroy( void )
{
if ( textMessagePanel )
{
textMessagePanel->SetParent( (vgui::Panel *)NULL );
delete textMessagePanel;
}
}
void SetPosition( int x, int y )
{
if ( !textMessagePanel )
return;
textMessagePanel->SetPosition( x, y );
}
void AddChar( int r, int g, int b, int a, wchar_t ch )
{
if ( !textMessagePanel )
return;
textMessagePanel->AddChar( r, g, b, a, ch );
}
void GetLength( int *wide, int *tall, const char *string )
{
if ( !textMessagePanel )
{
*wide = *tall = 0;
return;
}
textMessagePanel->GetTextExtents( wide, tall, string );
}
int GetFontInfo( FONTABC *pABCs, vgui::HFont hFont )
{
return textMessagePanel ? textMessagePanel->GetFontInfo( pABCs, hFont ) : 0;
}
void SetFont( vgui::HFont hCustomFont )
{
if ( !textMessagePanel )
return;
textMessagePanel->SetFont( hCustomFont );
}
void SetDefaultFont( void )
{
if ( !textMessagePanel )
return;
textMessagePanel->SetDefaultFont();
}
};
static CTextMessage g_TextMessage;
ITextMessage *textmessage = &g_TextMessage;

423
game/client/vgui_video.cpp Normal file
View File

@@ -0,0 +1,423 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: VGUI panel which can play back video, in-engine
//
//=============================================================================
#include "cbase.h"
#include <vgui/IVGui.h>
#include "vgui/IInput.h"
#include <vgui/ISurface.h>
#include "ienginevgui.h"
#include "iclientmode.h"
#include "vgui_video.h"
#include "engine/IEngineSound.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
VideoPanel::VideoPanel( unsigned int nXPos, unsigned int nYPos, unsigned int nHeight, unsigned int nWidth, bool allowAlternateMedia ) :
BaseClass( NULL, "VideoPanel" ),
m_VideoMaterial( NULL ),
m_nPlaybackWidth( 0 ),
m_nPlaybackHeight( 0 ),
m_bAllowAlternateMedia( allowAlternateMedia )
{
vgui::VPANEL pParent = enginevgui->GetPanel( PANEL_GAMEUIDLL );
SetParent( pParent );
SetVisible( false );
// Must be passed in, off by default
m_szExitCommand[0] = '\0';
m_bBlackBackground = true;
SetKeyBoardInputEnabled( true );
SetMouseInputEnabled( false );
SetProportional( false );
SetVisible( true );
SetPaintBackgroundEnabled( false );
SetPaintBorderEnabled( false );
// Set us up
SetTall( nHeight );
SetWide( nWidth );
SetPos( nXPos, nYPos );
SetScheme(vgui::scheme()->LoadSchemeFromFile( "resource/VideoPanelScheme.res", "VideoPanelScheme"));
LoadControlSettings("resource/UI/VideoPanel.res");
}
//-----------------------------------------------------------------------------
// Properly shutdown out materials
//-----------------------------------------------------------------------------
VideoPanel::~VideoPanel( void )
{
SetParent( (vgui::Panel *) NULL );
// Shut down this video, destroy the video material
if ( g_pVideo != NULL && m_VideoMaterial != NULL )
{
g_pVideo->DestroyVideoMaterial( m_VideoMaterial );
m_VideoMaterial = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose: Begins playback of a movie
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool VideoPanel::BeginPlayback( const char *pFilename )
{
// Who the heck hacked this in?
#ifdef _X360
XVIDEO_MODE videoMode;
XGetVideoMode( &videoMode );
// for 50Hz PAL, load a 25Hz version of the ep1_recap movie.
if( ( videoMode.RefreshRate < 59.0f ) && ( Q_stricmp( pFilename, "media/ep1_recap.bik" ) == 0 ) )
{
pFilename = "media/ep1_recap_25fps.bik";
}
#endif
// need working video services
if ( g_pVideo == NULL )
return false;
// Create a new video material
if ( m_VideoMaterial != NULL )
{
g_pVideo->DestroyVideoMaterial( m_VideoMaterial );
m_VideoMaterial = NULL;
}
m_VideoMaterial = g_pVideo->CreateVideoMaterial( "VideoMaterial", pFilename, "GAME",
VideoPlaybackFlags::DEFAULT_MATERIAL_OPTIONS,
VideoSystem::DETERMINE_FROM_FILE_EXTENSION, m_bAllowAlternateMedia );
if ( m_VideoMaterial == NULL )
return false;
// We want to be the sole audio source
// FIXME: This may not always be true!
enginesound->NotifyBeginMoviePlayback();
int nWidth, nHeight;
m_VideoMaterial->GetVideoImageSize( &nWidth, &nHeight );
m_VideoMaterial->GetVideoTexCoordRange( &m_flU, &m_flV );
m_pMaterial = m_VideoMaterial->GetMaterial();
float flFrameRatio = ( (float) GetWide() / (float) GetTall() );
float flVideoRatio = ( (float) nWidth / (float) nHeight );
if ( flVideoRatio > flFrameRatio )
{
m_nPlaybackWidth = GetWide();
m_nPlaybackHeight = ( GetWide() / flVideoRatio );
}
else if ( flVideoRatio < flFrameRatio )
{
m_nPlaybackWidth = ( GetTall() * flVideoRatio );
m_nPlaybackHeight = GetTall();
}
else
{
m_nPlaybackWidth = GetWide();
m_nPlaybackHeight = GetTall();
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void VideoPanel::Activate( void )
{
MoveToFront();
RequestFocus();
SetVisible( true );
SetEnabled( true );
vgui::surface()->SetMinimized( GetVPanel(), false );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void VideoPanel::DoModal( void )
{
MakePopup();
Activate();
vgui::input()->SetAppModalSurface( GetVPanel() );
vgui::surface()->RestrictPaintToSinglePanel( GetVPanel() );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void VideoPanel::OnKeyCodeTyped( vgui::KeyCode code )
{
if ( code == KEY_ESCAPE )
{
OnClose();
}
else
{
BaseClass::OnKeyCodeTyped( code );
}
}
//-----------------------------------------------------------------------------
// Purpose: Handle keys that should cause us to close
//-----------------------------------------------------------------------------
void VideoPanel::OnKeyCodePressed( vgui::KeyCode code )
{
// These keys cause the panel to shutdown
if ( code == KEY_ESCAPE ||
code == KEY_BACKQUOTE ||
code == KEY_SPACE ||
code == KEY_ENTER ||
code == KEY_XBUTTON_A ||
code == KEY_XBUTTON_B ||
code == KEY_XBUTTON_X ||
code == KEY_XBUTTON_Y ||
code == KEY_XBUTTON_START ||
code == KEY_XBUTTON_BACK )
{
OnClose();
}
else
{
BaseClass::OnKeyCodePressed( code );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void VideoPanel::OnClose( void )
{
enginesound->NotifyEndMoviePlayback();
BaseClass::OnClose();
if ( vgui::input()->GetAppModalSurface() == GetVPanel() )
{
vgui::input()->ReleaseAppModalSurface();
}
vgui::surface()->RestrictPaintToSinglePanel( NULL );
// Fire an exit command if we're asked to do so
if ( m_szExitCommand[0] )
{
engine->ClientCmd( m_szExitCommand );
}
SetVisible( false );
MarkForDeletion();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void VideoPanel::GetPanelPos( int &xpos, int &ypos )
{
xpos = ( (float) ( GetWide() - m_nPlaybackWidth ) / 2 );
ypos = ( (float) ( GetTall() - m_nPlaybackHeight ) / 2 );
}
//-----------------------------------------------------------------------------
// Purpose: Update and draw the frame
//-----------------------------------------------------------------------------
void VideoPanel::Paint( void )
{
BaseClass::Paint();
if ( m_VideoMaterial == NULL )
return;
if ( m_VideoMaterial->Update() == false )
{
// Issue a close command
OnVideoOver();
OnClose();
}
// Sit in the "center"
int xpos, ypos;
GetPanelPos( xpos, ypos );
// Black out the background (we could omit drawing under the video surface, but this is straight-forward)
if ( m_bBlackBackground )
{
vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
vgui::surface()->DrawFilledRect( 0, 0, GetWide(), GetTall() );
}
// Draw the polys to draw this out
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
pRenderContext->Bind( m_pMaterial, NULL );
CMeshBuilder meshBuilder;
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
float flLeftX = xpos;
float flRightX = xpos + (m_nPlaybackWidth-1);
float flTopY = ypos;
float flBottomY = ypos + (m_nPlaybackHeight-1);
// Map our UVs to cut out just the portion of the video we're interested in
float flLeftU = 0.0f;
float flTopV = 0.0f;
// We need to subtract off a pixel to make sure we don't bleed
float flRightU = m_flU - ( 1.0f / (float) m_nPlaybackWidth );
float flBottomV = m_flV - ( 1.0f / (float) m_nPlaybackHeight );
// Get the current viewport size
int vx, vy, vw, vh;
pRenderContext->GetViewport( vx, vy, vw, vh );
// map from screen pixel coords to -1..1
flRightX = FLerp( -1, 1, 0, vw, flRightX );
flLeftX = FLerp( -1, 1, 0, vw, flLeftX );
flTopY = FLerp( 1, -1, 0, vh ,flTopY );
flBottomY = FLerp( 1, -1, 0, vh, flBottomY );
float alpha = ((float)GetFgColor()[3]/255.0f);
for ( int corner=0; corner<4; corner++ )
{
bool bLeft = (corner==0) || (corner==3);
meshBuilder.Position3f( (bLeft) ? flLeftX : flRightX, (corner & 2) ? flBottomY : flTopY, 0.0f );
meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
meshBuilder.TexCoord2f( 0, (bLeft) ? flLeftU : flRightU, (corner & 2) ? flBottomV : flTopV );
meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, alpha );
meshBuilder.AdvanceVertex();
}
meshBuilder.End();
pMesh->Draw();
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PopMatrix();
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PopMatrix();
}
//-----------------------------------------------------------------------------
// Purpose: Create and playback a video in a panel
// Input : nWidth - Width of panel (in pixels)
// nHeight - Height of panel
// *pVideoFilename - Name of the file to play
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool VideoPanel_Create( unsigned int nXPos, unsigned int nYPos,
unsigned int nWidth, unsigned int nHeight,
const char *pVideoFilename,
const char *pExitCommand /*= NULL*/)
{
// Create the base video panel
VideoPanel *pVideoPanel = new VideoPanel( nXPos, nYPos, nHeight, nWidth, false );
if ( pVideoPanel == NULL )
return false;
// Set the command we'll call (if any) when the video is interrupted or completes
pVideoPanel->SetExitCommand( pExitCommand );
// Start it going
if ( pVideoPanel->BeginPlayback( pVideoFilename ) == false )
{
delete pVideoPanel;
return false;
}
// Take control
pVideoPanel->DoModal();
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Used to launch a video playback (Debug) -
// user must include file extension
//-----------------------------------------------------------------------------
CON_COMMAND( playvideo, "Plays a video: <filename> [width height]" )
{
if ( args.ArgC() < 2 )
return;
unsigned int nScreenWidth = Q_atoi( args[2] );
unsigned int nScreenHeight = Q_atoi( args[3] );
char strFullpath[MAX_PATH];
Q_strncpy( strFullpath, "media/", MAX_PATH ); // Assume we must play out of the media directory
char strFilename[MAX_PATH];
Q_StripExtension( args[1], strFilename, MAX_PATH );
Q_strncat( strFullpath, args[1], MAX_PATH );
if ( nScreenWidth == 0 )
{
nScreenWidth = ScreenWidth();
}
if ( nScreenHeight == 0 )
{
nScreenHeight = ScreenHeight();
}
// Create the panel and go!
if ( VideoPanel_Create( 0, 0, nScreenWidth, nScreenHeight, strFullpath ) == false )
{
Warning( "Unable to play video: %s\n", strFullpath );
}
}
//-----------------------------------------------------------------------------
// Purpose: Used to launch a video playback and fire a command on completion
//-----------------------------------------------------------------------------
CON_COMMAND( playvideo_exitcommand, "Plays a video and fires and exit command when it is stopped or finishes: <filename> <exit command>" )
{
if ( args.ArgC() < 2 )
return;
unsigned int nScreenWidth = ScreenWidth();
unsigned int nScreenHeight = ScreenHeight();
char strFullpath[MAX_PATH];
Q_strncpy( strFullpath, "media/", MAX_PATH ); // Assume we must play out of the media directory
char strFilename[MAX_PATH];
Q_StripExtension( args[1], strFilename, MAX_PATH );
Q_strncat( strFullpath, args[1], MAX_PATH );
char *pExitCommand = Q_strstr( args.GetCommandString(), args[2] );
// Create the panel and go!
if ( VideoPanel_Create( 0, 0, nScreenWidth, nScreenHeight, strFullpath, pExitCommand ) == false )
{
Warning( "Unable to play video: %s\n", strFullpath );
engine->ClientCmd( pExitCommand );
}
}

79
game/client/vgui_video.h Normal file
View File

@@ -0,0 +1,79 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: VGUI panel which can play back video, in-engine
//
//=============================================================================
#ifndef VGUI_VIDEO_H
#define VGUI_VIDEO_H
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/Panel.h>
#include <vgui_controls/EditablePanel.h>
//#define QUICKTIME_VIDEO
//#define BINK_VIDEO
#include "video/ivideoservices.h"
class VideoPanel : public vgui::EditablePanel
{
DECLARE_CLASS_SIMPLE( VideoPanel, vgui::EditablePanel );
public:
VideoPanel( unsigned int nXPos, unsigned int nYPos, unsigned int nHeight, unsigned int nWidth, bool allowAlternateMedia = true );
virtual ~VideoPanel( void );
virtual void Activate( void );
virtual void Paint( void );
virtual void DoModal( void );
virtual void OnKeyCodeTyped( vgui::KeyCode code );
virtual void OnKeyCodePressed( vgui::KeyCode code );
virtual void OnClose( void );
virtual void GetPanelPos( int &xpos, int &ypos );
void SetExitCommand( const char *pExitCommand )
{
if ( pExitCommand && pExitCommand[0] )
{
Q_strncpy( m_szExitCommand, pExitCommand, MAX_PATH );
}
}
bool BeginPlayback( const char *pFilename );
void SetBlackBackground( bool bBlack ){ m_bBlackBackground = bBlack; }
protected:
virtual void OnTick( void ) { BaseClass::OnTick(); }
virtual void OnCommand( const char *pcCommand ) { BaseClass::OnCommand( pcCommand ); }
virtual void OnVideoOver(){}
protected:
IVideoMaterial *m_VideoMaterial;
IMaterial *m_pMaterial;
int m_nPlaybackHeight; // Calculated to address ratio changes
int m_nPlaybackWidth;
char m_szExitCommand[MAX_PATH]; // This call is fired at the engine when the video finishes or is interrupted
float m_flU; // U,V ranges for video on its sheet
float m_flV;
bool m_bBlackBackground;
bool m_bAllowAlternateMedia;
};
// Creates a VGUI panel which plays a video and executes a client command at its finish (if specified)
extern bool VideoPanel_Create( unsigned int nXPos, unsigned int nYPos,
unsigned int nWidth, unsigned int nHeight,
const char *pVideoFilename,
const char *pExitCommand = NULL );
#endif // VGUI_VIDEO_H

View File

@@ -0,0 +1,457 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: VGUI panel which can play back video, in-engine
//
//=============================================================================
#include "cbase.h"
#include <vgui/IVGui.h>
#include "vgui/IInput.h"
#include <vgui/ISurface.h>
#include "ienginevgui.h"
#include "iclientmode.h"
#include "vgui_video_player.h"
#include "engine/IEngineSound.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
VideoPlayerPanel::VideoPlayerPanel( vgui::Panel *parent, const char *panelName, int nXpos, int nYpos, int nWidth, int nHeight, const char *pVideoFile ) :
BaseClass( parent, panelName ),
m_VideoMaterial( NULL ),
m_VideoFileName( NULL ),
m_VideoLoaded( false ),
m_VideoPlaying( false )
{
Assert( g_pVideo != NULL );
// init all the video realted member vars
ClearVideo();
SetVisible( false );
SetKeyBoardInputEnabled( false );
SetMouseInputEnabled( false );
SetProportional( false );
SetPaintBackgroundEnabled( false );
SetPaintBorderEnabled( false );
// Set us up
SetTall( nHeight );
SetWide( nWidth );
SetPos( nXpos, nYpos );
// use defaults for scheme and control settings for now
// SetScheme( vgui::scheme()->LoadSchemeFromFile( "resource/VideoPlayerPanelScheme.res", "VideoPlayerPanelScheme"));
//LoadControlSettings("resource/UI/VideoPlayerPanel.res");
// Assign video file if supplied
SetVideo( pVideoFile );
SetVisible( true );
}
//-----------------------------------------------------------------------------
// Properly shutdown out materials
//-----------------------------------------------------------------------------
VideoPlayerPanel::~VideoPlayerPanel( void )
{
SetParent( (vgui::Panel *) NULL );
StopVideo();
ClearVideo();
}
bool VideoPlayerPanel::SetVideo( const char *pVideoFile )
{
ClearVideo();
// clearing the video?
if ( pVideoFile == NULL || pVideoFile[0] == 0x00 )
{
return true;
}
// create the material
m_VideoMaterial = g_pVideo->CreateVideoMaterial( "VideoPlayerMaterial", pVideoFile, "GAME",
VideoPlaybackFlags::DEFAULT_MATERIAL_OPTIONS,
VideoSystem::DETERMINE_FROM_FILE_EXTENSION, true );
if ( m_VideoMaterial == NULL )
{
return false;
}
// save filename
int sLen = V_strlen( pVideoFile ) + 1;
m_VideoFileName = new char[ sLen ];
V_strncpy( m_VideoFileName, pVideoFile, sLen );
// compute Playback dimensions
int nWidth, nHeight;
m_VideoMaterial->GetVideoImageSize( &nWidth, &nHeight );
m_VideoMaterial->GetVideoTexCoordRange( &m_flU, &m_flV );
float flFrameRatio = ( (float) GetWide() / (float) GetTall() );
float flVideoRatio = ( (float) nWidth / (float) nHeight );
if ( flVideoRatio > flFrameRatio )
{
m_nPlaybackWidth = GetWide();
m_nPlaybackHeight = ( GetWide() / flVideoRatio );
m_letterBox = 1;
}
else if ( flVideoRatio < flFrameRatio )
{
m_nPlaybackWidth = ( GetTall() * flVideoRatio );
m_nPlaybackHeight = GetTall();
m_letterBox = 2;
}
else
{
m_nPlaybackWidth = GetWide();
m_nPlaybackHeight = GetTall();
m_letterBox = 0;
}
m_pMaterial = m_VideoMaterial->GetMaterial();
m_VideoDuration = m_VideoMaterial->GetVideoDuration();
m_VideoLoaded = true;
return true;
}
void VideoPlayerPanel::ClearVideo()
{
if ( m_VideoPlaying )
{
StopVideo();
}
// Shut down this video, destroy the video material
if ( g_pVideo != NULL && m_VideoMaterial != NULL )
{
g_pVideo->DestroyVideoMaterial( m_VideoMaterial );
m_VideoMaterial = NULL;
}
if ( m_VideoFileName != NULL )
{
delete[] m_VideoFileName;
m_VideoFileName = NULL;
}
m_pMaterial = NULL;
m_VideoLoaded = false;
m_VideoPlaying = false;
m_VideoPaused = false;
m_nPlaybackHeight = 0;
m_nPlaybackWidth = 0;
m_letterBox = 0;
m_flU = 0.0f;
m_flV = 0.0f;
m_VideoDuration = 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void VideoPlayerPanel::Activate( void )
{
MoveToFront();
RequestFocus();
SetVisible( true );
SetEnabled( true );
vgui::surface()->SetMinimized( GetVPanel(), false );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void VideoPlayerPanel::OnClose( void )
{
StopVideo();
// enginesound->NotifyEndMoviePlayback();
vgui::surface()->RestrictPaintToSinglePanel( NULL );
SetVisible( false );
MarkForDeletion();
}
//-----------------------------------------------------------------------------
// Purpose: Update and draw the frame
//-----------------------------------------------------------------------------
void VideoPlayerPanel::Paint( void )
{
BaseClass::Paint();
// Get our dimensions
int xpos = 0;
int ypos = 0;
vgui::ipanel()->GetAbsPos( GetVPanel(), xpos, ypos );
// GetPanelPos( xpos, ypos );
int width = GetWide();
int height = GetTall();
// Are we playing the video? Do we even have a video?
if ( !m_VideoLoaded || !m_VideoPlaying )
{
vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
vgui::surface()->DrawFilledRect( 0, 0, width, height );
return;
}
if ( m_VideoMaterial == NULL )
return;
if ( m_VideoMaterial->Update() == false )
{
StopVideo();
return;
}
// Black out the letterbox ares if we have them
if ( m_letterBox != 0 )
{
vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
if ( m_letterBox == 1 ) // bars on top, bottom
{
int excess = ( height - m_nPlaybackHeight );
int top = excess /2;
int bot = excess - top;
vgui::surface()->DrawFilledRect( 0, 0, width, top );
vgui::surface()->DrawFilledRect( 0, height - bot, width, height );
}
if ( m_letterBox == 2 ) // bars on left, right
{
int excess = ( width - m_nPlaybackWidth );
int left = excess /2;
int right = excess - left;
vgui::surface()->DrawFilledRect( 0, 0, left, height );
vgui::surface()->DrawFilledRect( width-right, 0, width, height );
}
}
// Draw the polys to draw this out
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PushMatrix();
pRenderContext->LoadIdentity();
pRenderContext->Bind( m_pMaterial, NULL );
CMeshBuilder meshBuilder;
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
float flLeftX = xpos;
float flRightX = xpos + ( m_nPlaybackWidth-1 );
float flTopY = ypos;
float flBottomY = ypos + ( m_nPlaybackHeight-1 );
// Map our UVs to cut out just the portion of the video we're interested in
float flLeftU = 0.0f;
float flTopV = 0.0f;
// We need to subtract off a pixel to make sure we don't bleed
float flRightU = m_flU - ( 1.0f / (float) m_nPlaybackWidth );
float flBottomV = m_flV - ( 1.0f / (float) m_nPlaybackHeight );
// Get the current viewport size
int vx, vy, vw, vh;
pRenderContext->GetViewport( vx, vy, vw, vh );
// map from screen pixel coords to -1..1
flRightX = FLerp( -1, 1, 0, vw, flRightX );
flLeftX = FLerp( -1, 1, 0, vw, flLeftX );
flTopY = FLerp( 1, -1, 0, vh ,flTopY );
flBottomY = FLerp( 1, -1, 0, vh, flBottomY );
float alpha = ((float)GetFgColor()[3]/255.0f);
for ( int corner=0; corner<4; corner++ )
{
bool bLeft = (corner==0) || (corner==3);
meshBuilder.Position3f( (bLeft) ? flLeftX : flRightX, (corner & 2) ? flBottomY : flTopY, 0.0f );
meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
meshBuilder.TexCoord2f( 0, (bLeft) ? flLeftU : flRightU, (corner & 2) ? flBottomV : flTopV );
meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, alpha );
meshBuilder.AdvanceVertex();
}
meshBuilder.End();
pMesh->Draw();
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->PopMatrix();
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->PopMatrix();
}
bool VideoPlayerPanel::StartVideo()
{
if ( !m_VideoLoaded )
return false;
// already playing?
if ( m_VideoPlaying )
{
// paused?
if ( m_VideoPaused )
{
return UnpauseVideo();
}
return true;
}
m_VideoPlaying = m_VideoMaterial->StartVideo();
return m_VideoPlaying;
}
bool VideoPlayerPanel::StopVideo()
{
if ( !m_VideoLoaded || !m_VideoPlaying )
return false;
m_VideoMaterial->StopVideo();
m_VideoPlaying = false;
return true;
}
bool VideoPlayerPanel::PauseVideo()
{
if ( !m_VideoLoaded || !m_VideoPlaying )
return false;
if ( !m_VideoPaused )
{
m_VideoMaterial->SetPaused( true );
m_VideoPaused = true;
}
return true;
}
bool VideoPlayerPanel::UnpauseVideo()
{
if ( !m_VideoLoaded || !m_VideoPlaying )
return false;
if ( m_VideoPaused )
{
m_VideoMaterial->SetPaused( false );
m_VideoPaused = false;
}
return true;
}
float VideoPlayerPanel::GetCurrentPlaybackTime()
{
if ( !m_VideoLoaded )
{
return 0.0f;
}
return m_VideoMaterial->GetCurrentVideoTime();
}
bool VideoPlayerPanel::SetCurrentPlaybackTime( float newTime )
{
if ( !m_VideoLoaded )
return false;
if ( newTime < 0.0f || newTime > m_VideoDuration )
return false;
return m_VideoMaterial->SetTime( newTime );
}
bool VideoPlayerPanel::HasAudio()
{
if ( !m_VideoLoaded )
return false;
return m_VideoMaterial->HasAudio();
}
bool VideoPlayerPanel::IsMuted()
{
if ( !m_VideoLoaded )
return false;
return m_VideoMaterial->IsMuted();
}
bool VideoPlayerPanel::SetMute( bool muted )
{
if ( !m_VideoLoaded )
return false;
m_VideoMaterial->SetMuted( muted );
return true;
}
float VideoPlayerPanel::GetVolume()
{
if ( !m_VideoLoaded )
return 0.0f;
return m_VideoMaterial->GetVolume();
}
bool VideoPlayerPanel::SetVolume( float newVolume )
{
if ( !m_VideoLoaded )
return false;
return m_VideoMaterial->SetVolume( newVolume );
}

View File

@@ -0,0 +1,88 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// VGUI_VIDEO_PLAYER
//
// Creates a VGUI Panel that can play a video in engine with "media player like"
// functionality. vgui_video.h has a basic player panel, but this allows for
// much greater control over playback, etc
//
//=============================================================================
#ifndef VGUI_VIDEO_PLAYER
#define VGUI_VIDEO_PLAYER
#ifdef _WIN32
#pragma once
#endif
#include <vgui_controls/Panel.h>
#include "video/ivideoservices.h"
class VideoPlayerPanel : public vgui::Panel // Should this be EditablePanel ?
{
public:
DECLARE_CLASS_SIMPLE( VideoPlayerPanel, vgui::Panel );
VideoPlayerPanel( vgui::Panel *parent, const char *panelName, int nXpos, int nYpos, int nWidth, int nHeight, const char *pVideoFile = NULL );
virtual ~VideoPlayerPanel();
virtual void Activate( void );
virtual void Paint( void );
virtual void OnClose( void );
bool SetVideo( const char *pVideoFile );
void ClearVideo();
bool IsReady() { return m_VideoLoaded; }
bool StartVideo();
bool StopVideo();
bool PauseVideo();
bool UnpauseVideo();
bool IsPlaying() { return m_VideoPlaying; }
bool IsPaused() { return m_VideoPaused; }
float GetCurrentPlaybackTime();
bool SetCurrentPlaybackTime( float newTime );
float GetVideoDuration() { return m_VideoDuration; }
bool HasAudio();
bool IsMuted();
bool SetMute( bool muted );
float GetVolume();
bool SetVolume( float newVolume );
protected:
virtual void OnTick( void ) { BaseClass::OnTick(); }
virtual void OnCommand( const char *pcCommand ) { BaseClass::OnCommand( pcCommand ); }
private:
IVideoMaterial *m_VideoMaterial;
IMaterial *m_pMaterial;
bool m_VideoLoaded;
bool m_VideoPlaying;
bool m_VideoPaused;
int m_nPlaybackHeight; // Calculated to address ratio changes
int m_nPlaybackWidth;
int m_letterBox;
float m_flU, m_flV;
char *m_VideoFileName;
float m_VideoDuration;
};
#endif

View File

@@ -0,0 +1,48 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#if !defined( VGUICENTERPRINT_H )
#define VGUICENTERPRINT_H
#ifdef _WIN32
#pragma once
#endif
#include "ivguicenterprint.h"
#include <vgui/VGUI.h>
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
namespace vgui
{
class Panel;
}
class CCenterStringLabel;
class CCenterPrint : public ICenterPrint
{
private:
CCenterStringLabel *vguiCenterString;
public:
CCenterPrint( void );
virtual void Create( vgui::VPANEL parent );
virtual void Destroy( void );
virtual void SetTextColor( int r, int g, int b, int a );
virtual void Print( char *text );
virtual void Print( wchar_t *text );
virtual void ColorPrint( int r, int g, int b, int a, char *text );
virtual void ColorPrint( int r, int g, int b, int a, wchar_t *text );
virtual void Clear( void );
};
extern CCenterPrint *internalCenterPrint;
#endif // VGUICENTERPRINT_H

1412
game/client/view.cpp Normal file

File diff suppressed because it is too large Load Diff

98
game/client/view.h Normal file
View File

@@ -0,0 +1,98 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#if !defined( VIEW_H )
#define VIEW_H
#ifdef _WIN32
#pragma once
#endif
#if _DEBUG
extern bool g_bRenderingCameraView; // For debugging (frustum fix for cameras)...
#endif
class VMatrix;
class Vector;
class QAngle;
class VPlane;
// near and far Z it uses to render the world.
#ifndef HL1_CLIENT_DLL
#define VIEW_NEARZ 3//7
#else
#define VIEW_NEARZ 3//3
#endif
//#define VIEW_FARZ 28400
//-----------------------------------------------------------------------------
// There's a difference between the 'current view' and the 'main view'
// The 'main view' is where the player is sitting. Current view is just
// what's currently being rendered, which, owing to monitors or water,
// could be just about anywhere.
//-----------------------------------------------------------------------------
const Vector &MainViewOrigin();
const QAngle &MainViewAngles();
const Vector &PrevMainViewOrigin();
const QAngle &PrevMainViewAngles();
const VMatrix &MainWorldToViewMatrix();
const Vector &MainViewForward();
const Vector &MainViewRight();
const Vector &MainViewUp();
const Vector &CurrentViewOrigin();
const QAngle &CurrentViewAngles();
const VMatrix &CurrentWorldToViewMatrix();
const Vector &CurrentViewForward();
const Vector &CurrentViewRight();
const Vector &CurrentViewUp();
void AllowCurrentViewAccess( bool allow );
bool IsCurrentViewAccessAllowed();
// Returns true of the sphere is outside the frustum defined by pPlanes.
// (planes point inwards).
bool R_CullSphere( const VPlane *pPlanes, int nPlanes, const Vector *pCenter, float radius );
float ScaleFOVByWidthRatio( float fovDegrees, float ratio );
extern ConVar mat_wireframe;
extern const ConVar *sv_cheats;
static inline int WireFrameMode( void )
{
if ( !sv_cheats )
{
sv_cheats = cvar->FindVar( "sv_cheats" );
}
if ( sv_cheats && sv_cheats->GetBool() )
return mat_wireframe.GetInt();
else
return 0;
}
static inline bool ShouldDrawInWireFrameMode( void )
{
if ( !sv_cheats )
{
sv_cheats = cvar->FindVar( "sv_cheats" );
}
if ( sv_cheats && sv_cheats->GetBool() )
return ( mat_wireframe.GetInt() != 0 );
else
return false;
}
void ComputeCameraVariables( const Vector &vecOrigin, const QAngle &vecAngles, Vector *pVecForward, Vector *pVecRight, Vector *pVecUp, VMatrix *pMatCamInverse );
#endif // VIEW_H

2354
game/client/view_beams.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,795 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ivieweffects.h"
#include "shake.h"
#include "hud_macros.h"
#include "isaverestore.h"
#include "view_shared.h"
#include "iviewrender.h"
#include "viewrender.h"
#include "con_nprint.h"
#include "saverestoretypes.h"
#include "c_rumble.h"
// NVNT haptics interface system
#include "haptics/ihaptics.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern IntroData_t *g_pIntroData;
// Arbitrary limit so that bad entity logic on the server can't consume tons of memory on the client.
#define MAX_SHAKES 32
//-----------------------------------------------------------------------------
// Purpose: Screen fade variables
//-----------------------------------------------------------------------------
struct screenfade_t
{
float Speed; // How fast to fade (tics / second) (+ fade in, - fade out)
float End; // When the fading hits maximum
float Reset; // When to reset to not fading (for fadeout and hold)
byte r, g, b, alpha; // Fade color
int Flags; // Fading flags
DECLARE_SIMPLE_DATADESC();
};
BEGIN_SIMPLE_DATADESC( screenfade_t )
DEFINE_FIELD( Speed, FIELD_FLOAT ),
DEFINE_FIELD( End, FIELD_TIME ),
DEFINE_FIELD( Reset, FIELD_TIME ),
DEFINE_FIELD( r, FIELD_CHARACTER ),
DEFINE_FIELD( g, FIELD_CHARACTER ),
DEFINE_FIELD( b, FIELD_CHARACTER ),
DEFINE_FIELD( alpha, FIELD_CHARACTER ),
DEFINE_FIELD( Flags, FIELD_INTEGER ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Screen shake variables
//-----------------------------------------------------------------------------
struct screenshake_t
{
float endtime;
float duration;
float amplitude;
float frequency;
float nextShake;
Vector offset;
float angle;
int command;
DECLARE_SIMPLE_DATADESC();
};
BEGIN_SIMPLE_DATADESC( screenshake_t )
DEFINE_FIELD( endtime, FIELD_TIME ),
DEFINE_FIELD( duration, FIELD_FLOAT ),
DEFINE_FIELD( amplitude, FIELD_FLOAT ),
DEFINE_FIELD( frequency, FIELD_FLOAT ),
DEFINE_FIELD( nextShake, FIELD_TIME ),
DEFINE_FIELD( offset, FIELD_VECTOR ),
DEFINE_FIELD( angle, FIELD_FLOAT ),
END_DATADESC()
void CC_Shake_Stop();
//-----------------------------------------------------------------------------
// Purpose: Implements the view effects interface for the client .dll
//-----------------------------------------------------------------------------
class CViewEffects : public IViewEffects
{
public:
~CViewEffects()
{
ClearAllFades();
}
virtual void Init( void );
virtual void LevelInit( void );
virtual void GetFadeParams( byte *r, byte *g, byte *b, byte *a, bool *blend );
virtual void CalcShake( void );
virtual void ApplyShake( Vector& origin, QAngle& angles, float factor );
virtual void Shake( ScreenShake_t &data );
virtual void Fade( ScreenFade_t &data );
virtual void ClearPermanentFades( void );
virtual void FadeCalculate( void );
virtual void ClearAllFades( void );
// Save / Restore
virtual void Save( ISave *pSave );
virtual void Restore( IRestore *pRestore, bool fCreatePlayers );
private:
void ClearAllShakes();
screenshake_t *FindLongestShake();
CUtlVector<screenfade_t *> m_FadeList;
CUtlVector<screenshake_t *> m_ShakeList;
Vector m_vecShakeAppliedOffset;
float m_flShakeAppliedAngle;
int m_FadeColorRGBA[4];
bool m_bModulate;
friend void CC_Shake_Stop();
};
static CViewEffects g_ViewEffects;
IViewEffects *vieweffects = ( IViewEffects * )&g_ViewEffects;
// Callback function to call at end of screen m_Fade.
static int s_nCallbackParameter;
static void ( *s_pfnFadeDoneCallback )( int parm1 );
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pszName -
// iSize -
// *pbuf -
// Output : static int
//-----------------------------------------------------------------------------
void __MsgFunc_Shake( bf_read &msg )
{
ScreenShake_t shake;
shake.command = msg.ReadByte();
shake.amplitude = msg.ReadFloat();
shake.frequency = msg.ReadFloat();
shake.duration = msg.ReadFloat();
g_ViewEffects.Shake( shake );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pszName -
// iSize -
// *pbuf -
// Output : static int
//-----------------------------------------------------------------------------
void __MsgFunc_Fade( bf_read &msg )
{
ScreenFade_t fade;
fade.duration = msg.ReadShort(); // fade lasts this long
fade.holdTime = msg.ReadShort(); // fade lasts this long
fade.fadeFlags = msg.ReadShort(); // fade type (in / out)
fade.r = msg.ReadByte(); // fade red
fade.g = msg.ReadByte(); // fade green
fade.b = msg.ReadByte(); // fade blue
fade.a = msg.ReadByte(); // fade blue
g_ViewEffects.Fade( fade );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CViewEffects::Init( void )
{
HOOK_MESSAGE( Shake );
HOOK_MESSAGE( Fade );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CViewEffects::LevelInit( void )
{
ClearAllShakes();
ClearAllFades();
}
static ConVar shake_show( "shake_show", "0", 0, "Displays a list of the active screen shakes." );
static ConCommand shake_stop("shake_stop", CC_Shake_Stop, "Stops all active screen shakes.\n", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose: Stops all active screen shakes.
//-----------------------------------------------------------------------------
void CC_Shake_Stop()
{
g_ViewEffects.ClearAllShakes();
}
//-----------------------------------------------------------------------------
// Purpose: Apply noise to the eye position.
// UNDONE: Feedback a bit of this into the view model position. It shakes too much
//-----------------------------------------------------------------------------
void CViewEffects::CalcShake( void )
{
float fraction, freq;
// We'll accumulate the aggregate shake for this frame into these data members.
m_vecShakeAppliedOffset.Init(0, 0, 0);
m_flShakeAppliedAngle = 0;
float flRumbleAngle = 0;
// NVNT - haptic shake effect amplitude
float hapticShakeAmp = 0;
bool bShow = shake_show.GetBool();
int nShakeCount = m_ShakeList.Count();
for ( int nShake = nShakeCount - 1; nShake >= 0; nShake-- )
{
screenshake_t *pShake = m_ShakeList.Element( nShake );
if ( pShake->endtime == 0 )
{
// Shouldn't be any such shakes in the list.
Assert( false );
continue;
}
if ( ( gpGlobals->curtime > pShake->endtime ) ||
pShake->duration <= 0 ||
pShake->amplitude <= 0 ||
pShake->frequency <= 0 )
{
// Retire this shake.
delete m_ShakeList.Element( nShake );
m_ShakeList.FastRemove( nShake );
continue;
}
if ( bShow )
{
con_nprint_t np;
np.time_to_live = 2.0f;
np.fixed_width_font = true;
np.color[0] = 1.0;
np.color[1] = 0.8;
np.color[2] = 0.1;
np.index = nShake + 2;
engine->Con_NXPrintf( &np, "%02d: dur(%8.2f) amp(%8.2f) freq(%8.2f)", nShake + 1, (double)pShake->duration, (double)pShake->amplitude, (double)pShake->frequency );
}
if ( gpGlobals->curtime > pShake->nextShake )
{
// Higher frequency means we recalc the extents more often and perturb the display again
pShake->nextShake = gpGlobals->curtime + (1.0f / pShake->frequency);
// Compute random shake extents (the shake will settle down from this)
for (int i = 0; i < 3; i++ )
{
pShake->offset[i] = random->RandomFloat( -pShake->amplitude, pShake->amplitude );
}
pShake->angle = random->RandomFloat( -pShake->amplitude*0.25, pShake->amplitude*0.25 );
}
// Ramp down amplitude over duration (fraction goes from 1 to 0 linearly with slope 1/duration)
fraction = ( pShake->endtime - gpGlobals->curtime ) / pShake->duration;
// Ramp up frequency over duration
if ( fraction )
{
freq = (pShake->frequency / fraction);
}
else
{
freq = 0;
}
// square fraction to approach zero more quickly
fraction *= fraction;
// Sine wave that slowly settles to zero
float angle = gpGlobals->curtime * freq;
if ( angle > 1e8 )
{
angle = 1e8;
}
fraction = fraction * sin( angle );
if( pShake->command != SHAKE_START_NORUMBLE )
{
// As long as this isn't a NO RUMBLE effect, then accumulate rumble
flRumbleAngle += pShake->angle * fraction;
}
if( pShake->command != SHAKE_START_RUMBLEONLY )
{
// As long as this isn't a RUMBLE ONLY effect, then accumulate screen shake
// Add to view origin
m_vecShakeAppliedOffset += pShake->offset * fraction;
// Add to roll
m_flShakeAppliedAngle += pShake->angle * fraction;
}
// Drop amplitude a bit, less for higher frequency shakes
pShake->amplitude -= pShake->amplitude * ( gpGlobals->frametime / (pShake->duration * pShake->frequency) );
// NVNT - update our amplitude.
hapticShakeAmp += pShake->amplitude*fraction;
}
// NVNT - apply our screen shake update
if ( haptics )
haptics->SetShake(hapticShakeAmp,1);
// Feed this to the rumble system!
UpdateScreenShakeRumble( flRumbleAngle );
}
//-----------------------------------------------------------------------------
// Purpose: Apply the current screen shake to this origin/angles. Factor is the amount to apply
// This is so you can blend in part of the shake
// Input : origin -
// angles -
// factor -
//-----------------------------------------------------------------------------
void CViewEffects::ApplyShake( Vector& origin, QAngle& angles, float factor )
{
VectorMA( origin, factor, m_vecShakeAppliedOffset, origin );
angles.z += m_flShakeAppliedAngle * factor;
}
//-----------------------------------------------------------------------------
// Purpose: Zeros out all active screen shakes.
//-----------------------------------------------------------------------------
void CViewEffects::ClearAllShakes()
{
int nShakeCount = m_ShakeList.Count();
for ( int i = 0; i < nShakeCount; i++ )
{
delete m_ShakeList.Element( i );
}
m_ShakeList.Purge();
}
//-----------------------------------------------------------------------------
// Purpose: Returns the shake with the longest duration. This is the shake we
// use anytime we get an amplitude or frequency command, because the
// most likely case is that we're modifying a shake with a long
// duration rather than a brief shake caused by an explosion, etc.
//-----------------------------------------------------------------------------
screenshake_t *CViewEffects::FindLongestShake()
{
screenshake_t *pLongestShake = NULL;
int nShakeCount = m_ShakeList.Count();
for ( int i = 0; i < nShakeCount; i++ )
{
screenshake_t *pShake = m_ShakeList.Element( i );
if ( pShake && ( !pLongestShake || ( pShake->duration > pLongestShake->duration ) ) )
{
pLongestShake = pShake;
}
}
return pLongestShake;
}
//-----------------------------------------------------------------------------
// Purpose: Message hook to parse ScreenShake messages
// Input : pszName -
// iSize -
// pbuf -
// Output :
//-----------------------------------------------------------------------------
void CViewEffects::Shake( ScreenShake_t &data )
{
if ( ( data.command == SHAKE_START || data.command == SHAKE_START_RUMBLEONLY ) && ( m_ShakeList.Count() < MAX_SHAKES ) )
{
screenshake_t *pNewShake = new screenshake_t;
pNewShake->amplitude = data.amplitude;
pNewShake->frequency = data.frequency;
pNewShake->duration = data.duration;
pNewShake->nextShake = 0;
pNewShake->endtime = gpGlobals->curtime + data.duration;
pNewShake->command = data.command;
m_ShakeList.AddToTail( pNewShake );
}
else if ( data.command == SHAKE_STOP)
{
ClearAllShakes();
}
else if ( data.command == SHAKE_AMPLITUDE )
{
// Look for the most likely shake to modify.
screenshake_t *pShake = FindLongestShake();
if ( pShake )
{
pShake->amplitude = data.amplitude;
}
}
else if ( data.command == SHAKE_FREQUENCY )
{
// Look for the most likely shake to modify.
screenshake_t *pShake = FindLongestShake();
if ( pShake )
{
pShake->frequency = data.frequency;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Message hook to parse ScreenFade messages
// Input : *pszName -
// iSize -
// *pbuf -
// Output : int
//-----------------------------------------------------------------------------
void CViewEffects::Fade( ScreenFade_t &data )
{
// Create a new fade and append it to the list
screenfade_t *pNewFade = new screenfade_t;
pNewFade->End = data.duration * (1.0f/(float)(1<<SCREENFADE_FRACBITS));
pNewFade->Reset = data.holdTime * (1.0f/(float)(1<<SCREENFADE_FRACBITS));
pNewFade->r = data.r;
pNewFade->g = data.g;
pNewFade->b = data.b;
pNewFade->alpha = data.a;
pNewFade->Flags = data.fadeFlags;
pNewFade->Speed = 0;
// Calc fade speed
if ( data.duration > 0 )
{
if ( data.fadeFlags & FFADE_OUT )
{
if ( pNewFade->End )
{
pNewFade->Speed = -(float)pNewFade->alpha / pNewFade->End;
}
pNewFade->End += gpGlobals->curtime;
pNewFade->Reset += pNewFade->End;
}
else
{
if ( pNewFade->End )
{
pNewFade->Speed = (float)pNewFade->alpha / pNewFade->End;
}
pNewFade->Reset += gpGlobals->curtime;
pNewFade->End += pNewFade->Reset;
}
}
if ( data.fadeFlags & FFADE_PURGE )
{
ClearAllFades();
}
m_FadeList.AddToTail( pNewFade );
}
//-----------------------------------------------------------------------------
// Purpose: Compute the overall color & alpha of the fades
//-----------------------------------------------------------------------------
void CViewEffects::FadeCalculate( void )
{
// Cycle through all fades and remove any that have finished (work backwards)
int i;
int iSize = m_FadeList.Size();
for (i = iSize-1; i >= 0; i-- )
{
screenfade_t *pFade = m_FadeList[i];
// Keep pushing reset time out indefinitely
if ( pFade->Flags & FFADE_STAYOUT )
{
pFade->Reset = gpGlobals->curtime + 0.1;
}
// All done?
if ( ( gpGlobals->curtime > pFade->Reset ) && ( gpGlobals->curtime > pFade->End ) )
{
// User passed in a callback function, call it now
if ( s_pfnFadeDoneCallback )
{
s_pfnFadeDoneCallback( s_nCallbackParameter );
s_pfnFadeDoneCallback = NULL;
s_nCallbackParameter = 0;
}
// Remove this Fade from the list
m_FadeList.FindAndRemove( pFade );
delete pFade;
}
}
m_bModulate = false;
m_FadeColorRGBA[0] = m_FadeColorRGBA[1] = m_FadeColorRGBA[2] = m_FadeColorRGBA[3] = 0;
// Cycle through all fades in the list and calculate the overall color/alpha
for ( i = 0; i < m_FadeList.Size(); i++ )
{
screenfade_t *pFade = m_FadeList[i];
// Color
m_FadeColorRGBA[0] += pFade->r;
m_FadeColorRGBA[1] += pFade->g;
m_FadeColorRGBA[2] += pFade->b;
// Fading...
int iFadeAlpha;
if ( pFade->Flags & (FFADE_OUT|FFADE_IN) )
{
iFadeAlpha = pFade->Speed * ( pFade->End - gpGlobals->curtime );
if ( pFade->Flags & FFADE_OUT )
{
iFadeAlpha += pFade->alpha;
}
iFadeAlpha = MIN( iFadeAlpha, pFade->alpha );
iFadeAlpha = MAX( 0, iFadeAlpha );
}
else
{
iFadeAlpha = pFade->alpha;
}
// Use highest alpha
if ( iFadeAlpha > m_FadeColorRGBA[3] )
{
m_FadeColorRGBA[3] = iFadeAlpha;
}
// Modulate?
if ( pFade->Flags & FFADE_MODULATE )
{
m_bModulate = true;
}
}
// Divide colors
if ( m_FadeList.Size() )
{
m_FadeColorRGBA[0] /= m_FadeList.Size();
m_FadeColorRGBA[1] /= m_FadeList.Size();
m_FadeColorRGBA[2] /= m_FadeList.Size();
}
}
//-----------------------------------------------------------------------------
// Purpose: Clear only the permanent fades in our fade list
//-----------------------------------------------------------------------------
void CViewEffects::ClearPermanentFades( void )
{
int iSize = m_FadeList.Size();
for (int i = iSize-1; i >= 0; i-- )
{
screenfade_t *pFade = m_FadeList[i];
if ( pFade->Flags & FFADE_STAYOUT )
{
// Destroy this fade
m_FadeList.FindAndRemove( pFade );
delete pFade;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Purge & delete all fades in the queue
//-----------------------------------------------------------------------------
void CViewEffects::ClearAllFades( void )
{
int iSize = m_FadeList.Size();
for (int i = iSize-1; i >= 0; i-- )
{
delete m_FadeList[i];
}
m_FadeList.Purge();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : context - Which call to Render is this ( CViewSetup::context )
// *r -
// *g -
// *b -
// *a -
// *blend -
//-----------------------------------------------------------------------------
void CViewEffects::GetFadeParams( byte *r, byte *g, byte *b, byte *a, bool *blend )
{
// If the intro is overriding our fade, use that instead
if ( g_pIntroData && g_pIntroData->m_flCurrentFadeColor[3] )
{
*r = g_pIntroData->m_flCurrentFadeColor[0];
*g = g_pIntroData->m_flCurrentFadeColor[1];
*b = g_pIntroData->m_flCurrentFadeColor[2];
*a = g_pIntroData->m_flCurrentFadeColor[3];
*blend = false;
return;
}
FadeCalculate();
*r = m_FadeColorRGBA[0];
*g = m_FadeColorRGBA[1];
*b = m_FadeColorRGBA[2];
*a = m_FadeColorRGBA[3];
*blend = m_bModulate;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pSave -
//-----------------------------------------------------------------------------
void CViewEffects::Save( ISave *pSave )
{
// Save the view fades
int iCount = m_FadeList.Count();
pSave->WriteInt( &iCount );
for ( int i = 0; i < iCount; i++ )
{
pSave->StartBlock();
pSave->WriteAll( m_FadeList[i] );
pSave->EndBlock();
}
// Save the view shakes
iCount = m_ShakeList.Count();
pSave->WriteInt( &iCount );
for ( int i = 0; i < iCount; i++ )
{
pSave->StartBlock();
pSave->WriteAll( m_ShakeList[i] );
pSave->EndBlock();
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pRestore -
// fCreatePlayers -
//-----------------------------------------------------------------------------
void CViewEffects::Restore( IRestore *pRestore, bool fCreatePlayers )
{
CGameSaveRestoreInfo *pSaveData = pRestore->GetGameSaveRestoreInfo();
// View effects is a singleton so we only need to restore it once,
// from the level that we are going into.
if( !pSaveData->levelInfo.fUseLandmark )
{
ClearAllFades();
ClearAllShakes();
// Read in the view fades
int iCount = pRestore->ReadInt();
for ( int i = 0; i < iCount; i++ )
{
screenfade_t *pNewFade = new screenfade_t;
pRestore->StartBlock();
pRestore->ReadAll( pNewFade );
pRestore->EndBlock();
m_FadeList.AddToTail( pNewFade );
}
// Read in the view shakes
iCount = pRestore->ReadInt();
for ( int i = 0; i < iCount; i++ )
{
screenshake_t *pNewShake = new screenshake_t;
pRestore->StartBlock();
pRestore->ReadAll( pNewShake );
pRestore->EndBlock();
m_ShakeList.AddToTail( pNewShake );
}
}
}
//====================================================================================================
// CLIENTSIDE VIEW EFFECTS SAVE/RESTORE
//====================================================================================================
static short VIEWEFFECTS_SAVE_RESTORE_VERSION = 2;
class CViewEffectsSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler
{
struct QueuedItem_t;
public:
CViewEffectsSaveRestoreBlockHandler()
{
}
const char *GetBlockName()
{
return "ViewEffects";
}
//---------------------------------
virtual void PreSave( CSaveRestoreData * )
{
}
//---------------------------------
virtual void Save( ISave *pSave )
{
vieweffects->Save( pSave );
}
//---------------------------------
virtual void WriteSaveHeaders( ISave *pSave )
{
pSave->WriteShort( &VIEWEFFECTS_SAVE_RESTORE_VERSION );
}
//---------------------------------
virtual void PostSave()
{
}
//---------------------------------
virtual void PreRestore()
{
}
//---------------------------------
virtual void ReadRestoreHeaders( IRestore *pRestore )
{
// No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
short version = pRestore->ReadShort();
m_bDoLoad = ( version == VIEWEFFECTS_SAVE_RESTORE_VERSION );
}
//---------------------------------
virtual void Restore( IRestore *pRestore, bool fCreatePlayers )
{
if ( m_bDoLoad )
{
vieweffects->Restore( pRestore, fCreatePlayers );
}
}
//---------------------------------
virtual void PostRestore()
{
}
private:
bool m_bDoLoad;
};
//-----------------------------------------------------------------------------
CViewEffectsSaveRestoreBlockHandler g_ViewEffectsSaveRestoreBlockHandler;
ISaveRestoreBlockHandler *GetViewEffectsRestoreBlockHandler()
{
return &g_ViewEffectsSaveRestoreBlockHandler;
}

155
game/client/view_scene.cpp Normal file
View File

@@ -0,0 +1,155 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Responsible for drawing the scene
//
//===========================================================================//
#include "cbase.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/imaterialvar.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"
#include "rendertexture.h"
#include "view_scene.h"
#include "viewrender.h"
#include "sourcevr/isourcevirtualreality.h"
#include "client_virtualreality.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Convars related to controlling rendering
//-----------------------------------------------------------------------------
ConVar r_updaterefracttexture( "r_updaterefracttexture", "1", FCVAR_CHEAT );
ConVar r_depthoverlay( "r_depthoverlay", "0", FCVAR_CHEAT, "Replaces opaque objects with their grayscaled depth values. r_showz_power scales the output." );
int g_viewscene_refractUpdateFrame = 0;
bool g_bAllowMultipleRefractUpdatesPerScenePerFrame = false;
#if defined( _X360 )
class CAllowMultipleRefractsLogic : public CAutoGameSystem
{
public:
void LevelInitPreEntity()
{
// EP1 core room needs many refract updates per frame to avoid looking broken (ep1_citadel_03)
// Same with Kleiner's lab (d1_trainstation_05)
g_bAllowMultipleRefractUpdatesPerScenePerFrame = FStrEq( MapName(), "ep1_citadel_03" ) || FStrEq( MapName(), "d1_trainstation_05" );
}
};
static CAllowMultipleRefractsLogic s_AllowMultipleRefractsLogic;
#endif
void ViewTransform( const Vector &worldSpace, Vector &viewSpace )
{
const VMatrix &viewMatrix = engine->WorldToViewMatrix();
Vector3DMultiplyPosition( viewMatrix, worldSpace, viewSpace );
}
//-----------------------------------------------------------------------------
// Purpose: Transforms a world-space position into a 2D position inside a supplied frustum.
//-----------------------------------------------------------------------------
int FrustumTransform( const VMatrix &worldToSurface, const Vector& point, Vector& screen )
{
// UNDONE: Clean this up some, handle off-screen vertices
float w;
screen.x = worldToSurface[0][0] * point[0] + worldToSurface[0][1] * point[1] + worldToSurface[0][2] * point[2] + worldToSurface[0][3];
screen.y = worldToSurface[1][0] * point[0] + worldToSurface[1][1] * point[1] + worldToSurface[1][2] * point[2] + worldToSurface[1][3];
// z = worldToSurface[2][0] * point[0] + worldToSurface[2][1] * point[1] + worldToSurface[2][2] * point[2] + worldToSurface[2][3];
w = worldToSurface[3][0] * point[0] + worldToSurface[3][1] * point[1] + worldToSurface[3][2] * point[2] + worldToSurface[3][3];
// Just so we have something valid here
screen.z = 0.0f;
bool behind;
if( w < 0.001f )
{
behind = true;
screen.x *= 100000;
screen.y *= 100000;
}
else
{
behind = false;
float invw = 1.0f / w;
screen.x *= invw;
screen.y *= invw;
}
return behind;
}
//-----------------------------------------------------------------------------
// Purpose: UNDONE: Clean this up some, handle off-screen vertices
// Input : *point -
// *screen -
// Output : int
//-----------------------------------------------------------------------------
int ScreenTransform( const Vector& point, Vector& screen )
{
// UNDONE: Clean this up some, handle off-screen vertices
return FrustumTransform ( engine->WorldToScreenMatrix(), point, screen );
}
//-----------------------------------------------------------------------------
// Purpose: Same as ScreenTransform, but transforms to HUD space.
// These are totally different things in VR mode!
//-----------------------------------------------------------------------------
int HudTransform( const Vector& point, Vector& screen )
{
if ( UseVR() )
{
return FrustumTransform ( g_ClientVirtualReality.GetHudProjectionFromWorld(), point, screen );
}
else
{
return FrustumTransform ( engine->WorldToScreenMatrix(), point, screen );
}
}
void UpdateFullScreenDepthTexture( void )
{
if( !g_pMaterialSystemHardwareConfig->SupportsPixelShaders_2_b() )
return;
ITexture *pDepthTex = GetFullFrameDepthTexture();
CMatRenderContextPtr pRenderContext( materials );
if( IsX360() )
{
pRenderContext->CopyRenderTargetToTextureEx( pDepthTex, -1, NULL, NULL );
}
else
{
pRenderContext->CopyRenderTargetToTextureEx( pDepthTex, 0, NULL, NULL );
}
pRenderContext->SetFullScreenDepthTextureValidityFlag( true );
if( r_depthoverlay.GetBool() )
{
IMaterial *pMaterial = materials->FindMaterial( "debug/showz", TEXTURE_GROUP_OTHER, true );
pMaterial->IncrementReferenceCount();
IMaterialVar *BaseTextureVar = pMaterial->FindVar( "$basetexture", NULL, false );
IMaterialVar *pDepthInAlpha = NULL;
if( IsPC() )
{
pDepthInAlpha = pMaterial->FindVar( "$ALPHADEPTH", NULL, false );
pDepthInAlpha->SetIntValue( 1 );
}
BaseTextureVar->SetTextureValue( pDepthTex );
pRenderContext->OverrideDepthEnable( true, false ); //don't write to depth, or else we'll never see translucents
pRenderContext->DrawScreenSpaceQuad( pMaterial );
pRenderContext->OverrideDepthEnable( false, true );
pMaterial->DecrementReferenceCount();
}
}

166
game/client/view_scene.h Normal file
View File

@@ -0,0 +1,166 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef VIEW_SCENE_H
#define VIEW_SCENE_H
#ifdef _WIN32
#pragma once
#endif
#include "convar.h"
#include "iviewrender.h"
#include "view_shared.h"
#include "rendertexture.h"
#include "materialsystem/itexture.h"
extern ConVar mat_wireframe;
extern ConVar building_cubemaps;
// Transform into view space (translate and rotate the camera into the origin).
void ViewTransform( const Vector &worldSpace, Vector &viewSpace );
// Transform a world point into normalized screen space (X and Y from -1 to 1).
// Returns 0 if the point is behind the viewer.
int ScreenTransform( const Vector& point, Vector& screen );
int HudTransform( const Vector& point, Vector& screen );
extern ConVar r_updaterefracttexture;
extern int g_viewscene_refractUpdateFrame;
extern bool g_bAllowMultipleRefractUpdatesPerScenePerFrame;
bool DrawingShadowDepthView( void );
bool DrawingMainView();
inline void UpdateRefractTexture( int x, int y, int w, int h, bool bForceUpdate = false )
{
Assert( !DrawingShadowDepthView() );
if ( !IsRetail() && !r_updaterefracttexture.GetBool() )
return;
CMatRenderContextPtr pRenderContext( materials );
ITexture *pTexture = GetPowerOfTwoFrameBufferTexture();
if ( IsPC() || bForceUpdate || g_bAllowMultipleRefractUpdatesPerScenePerFrame || (gpGlobals->framecount != g_viewscene_refractUpdateFrame) )
{
// forced or only once per frame
Rect_t rect;
rect.x = x;
rect.y = y;
rect.width = w;
rect.height = h;
pRenderContext->CopyRenderTargetToTextureEx( pTexture, 0, &rect, NULL );
g_viewscene_refractUpdateFrame = gpGlobals->framecount;
}
pRenderContext->SetFrameBufferCopyTexture( pTexture );
}
inline void UpdateRefractTexture( bool bForceUpdate = false )
{
Assert( !DrawingShadowDepthView() );
CMatRenderContextPtr pRenderContext( materials );
int x,y,w,h;
pRenderContext->GetViewport( x, y, w, h );
UpdateRefractTexture( x, y, w, h, bForceUpdate );
}
inline void UpdateScreenEffectTexture( int textureIndex, int x, int y, int w, int h, bool bDestFullScreen = false, Rect_t *pActualRect = NULL )
{
Rect_t srcRect;
srcRect.x = x;
srcRect.y = y;
srcRect.width = w;
srcRect.height = h;
CMatRenderContextPtr pRenderContext( materials );
ITexture *pTexture = GetFullFrameFrameBufferTexture( textureIndex );
int nSrcWidth, nSrcHeight;
pRenderContext->GetRenderTargetDimensions( nSrcWidth, nSrcHeight );
int nDestWidth = pTexture->GetActualWidth();
int nDestHeight = pTexture->GetActualHeight();
Rect_t destRect = srcRect;
if( !bDestFullScreen && ( nSrcWidth > nDestWidth || nSrcHeight > nDestHeight ) )
{
// the source and target sizes aren't necessarily the same (specifically in dx7 where
// nonpow2 rendertargets aren't supported), so lets figure it out here.
float scaleX = ( float )nDestWidth / ( float )nSrcWidth;
float scaleY = ( float )nDestHeight / ( float )nSrcHeight;
destRect.x = srcRect.x * scaleX;
destRect.y = srcRect.y * scaleY;
destRect.width = srcRect.width * scaleX;
destRect.height = srcRect.height * scaleY;
destRect.x = clamp( destRect.x, 0, nDestWidth );
destRect.y = clamp( destRect.y, 0, nDestHeight );
destRect.width = clamp( destRect.width, 0, nDestWidth - destRect.x );
destRect.height = clamp( destRect.height, 0, nDestHeight - destRect.y );
}
pRenderContext->CopyRenderTargetToTextureEx( pTexture, 0, &srcRect, bDestFullScreen ? NULL : &destRect );
pRenderContext->SetFrameBufferCopyTexture( pTexture, textureIndex );
if ( pActualRect )
{
pActualRect->x = destRect.x;
pActualRect->y = destRect.y;
pActualRect->width = destRect.width;
pActualRect->height = destRect.height;
}
}
//-----------------------------------------------------------------------------
// Draws the screen effect
//-----------------------------------------------------------------------------
inline void DrawScreenEffectMaterial( IMaterial *pMaterial, int x, int y, int w, int h )
{
Rect_t actualRect;
UpdateScreenEffectTexture( 0, x, y, w, h, false, &actualRect );
ITexture *pTexture = GetFullFrameFrameBufferTexture( 0 );
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->DrawScreenSpaceRectangle( pMaterial, x, y, w, h,
actualRect.x, actualRect.y, actualRect.x+actualRect.width-1, actualRect.y+actualRect.height-1,
pTexture->GetActualWidth(), pTexture->GetActualHeight() );
}
//intended for use by dynamic meshes to naively update front buffer textures needed by a material
inline void UpdateFrontBufferTexturesForMaterial( IMaterial *pMaterial, bool bForce = false )
{
Assert( !DrawingShadowDepthView() );
if( pMaterial->NeedsPowerOfTwoFrameBufferTexture() )
{
UpdateRefractTexture( bForce );
}
else if( pMaterial->NeedsFullFrameBufferTexture() )
{
const CViewSetup *pView = view->GetViewSetup();
UpdateScreenEffectTexture( 0, pView->x, pView->y, pView->width, pView->height );
}
}
inline void UpdateScreenEffectTexture( void )
{
Assert( !DrawingShadowDepthView() );
const CViewSetup *pViewSetup = view->GetViewSetup();
UpdateScreenEffectTexture( 0, pViewSetup->x, pViewSetup->y, pViewSetup->width, pViewSetup->height);
}
// reset the tonem apping to a constant value, and clear the filter bank
void ResetToneMapping(float value);
void UpdateFullScreenDepthTexture( void );
#endif // VIEW_SCENE_H

View File

@@ -0,0 +1,386 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "filesystem.h"
#include "viewangleanim.h"
#include "KeyValues.h"
#include "tier0/memdbgon.h"
extern ConVar cl_pitchdown;
extern ConVar cl_pitchup;
// ConCommands useful for creating view animations
CViewAngleAnimation *g_pTestAnimation = NULL;
// create a view animation object to be used for creating an animation. parameter is flags
CON_COMMAND( viewanim_create, "viewanim_create" )
{
if ( g_pTestAnimation )
{
delete g_pTestAnimation;
g_pTestAnimation = NULL;
}
int flags = 0;
if ( args.ArgC() > 1 )
{
flags = atoi( args[1] );
}
g_pTestAnimation = CREATE_ENTITY( CViewAngleAnimation, "viewangleanim" );
if ( g_pTestAnimation )
{
g_pTestAnimation->Spawn();
}
}
// run the test animation
void TestViewAnim( void )
{
if ( g_pTestAnimation )
{
QAngle angles;
engine->GetViewAngles( angles );
g_pTestAnimation->RunAnimation( angles );
}
else
Msg( "No view anim created\n" );
}
ConCommand viewanim_test( "viewanim_test", TestViewAnim, "test view animation" );
// set view angles to (0,0,0)
void ResetViewAngles( void )
{
// create a blank anim
QAngle angles = vec3_angle;
engine->SetViewAngles( angles );
}
ConCommand viewanim_reset( "viewanim_reset", ResetViewAngles, "reset view angles!", FCVAR_CHEAT );
// add a key frame to the test animation. first parameter is the time taken to get to this keyframe
CON_COMMAND_F( viewanim_addkeyframe, "", FCVAR_CHEAT )
{
if ( g_pTestAnimation )
{
QAngle vecTarget;
engine->GetViewAngles( vecTarget );
float flDelay = 0.2;
if (args.ArgC() > 1)
{
flDelay = atof( args[1] );
}
int iFlags = 0;
if (args.ArgC() > 1)
{
iFlags = atof( args[2] );
}
g_pTestAnimation->AddKeyFrame( new CViewAngleKeyFrame( vecTarget, flDelay, iFlags ) );
}
else
Msg( "No view anim created, use viewanim_create" );
}
// save the current test anim, pass filename
CON_COMMAND( viewanim_save, "Save current animation to file" )
{
if (args.ArgC() < 2)
return;
if ( g_pTestAnimation )
{
g_pTestAnimation->SaveAsAnimFile( args[1] );
}
else
{
Msg( "No view anim created\n" );
}
}
// load a view animation file into the test anim
CON_COMMAND( viewanim_load, "load animation from file" )
{
if (args.ArgC() < 2)
return;
if ( g_pTestAnimation )
{
g_pTestAnimation->LoadViewAnimFile( args[1] );
}
else
Msg( "No view anim created\n" );
}
LINK_ENTITY_TO_CLASS( viewangleanim, CViewAngleAnimation );
CViewAngleAnimation::CViewAngleAnimation()
{
}
CViewAngleAnimation::~CViewAngleAnimation()
{
DeleteKeyFrames();
}
void CViewAngleAnimation::Spawn( void )
{
m_iFlags = 0;
QAngle angles;
engine->GetViewAngles( angles );
/*
if ( m_iFlags & VIEWANIM_RELATIVE )
{
AddKeyFrame( new CViewAngleKeyFrame( vec3_angle, 0.0, 0 ) );
// seed this so we can add keyframes and have them calc the delta properly
m_vecBaseAngles = angles;
}
else
{
AddKeyFrame( new CViewAngleKeyFrame( angles, 0.0, 0 ) );
}
*/
m_bFinished = true; // don't run right away
ClientEntityList().AddNonNetworkableEntity( this );
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
void CViewAngleAnimation::DeleteKeyFrames()
{
int i, c;
c = m_KeyFrames.Count();
for ( i = c - 1; i >= 0 ; --i )
{
delete m_KeyFrames[ i ];
}
m_KeyFrames.RemoveAll();
}
void CViewAngleAnimation::LoadViewAnimFile( const char *pKeyFrameFileName )
{
DeleteKeyFrames();
// load keyvalues from this file and stuff them in as keyframes
KeyValues *pData = new KeyValues( pKeyFrameFileName );
if ( false == pData->LoadFromFile( filesystem, pKeyFrameFileName, "GAME" ) )
{
Warning( "CViewAngleAnimation::LoadViewAnimFile failed to load script %s\n", pKeyFrameFileName );
pData->deleteThis();
return;
}
QAngle angles;
float flTime;
int iFlags;
KeyValues *pKey = pData->GetFirstSubKey();
while ( pKey )
{
// angles
const char *pszAngles = pKey->GetString( "angles", "0 0 0" );
sscanf( pszAngles, "%f %f %f", &angles[0], &angles[1], &angles[2] );
// time
flTime = pKey->GetFloat( "time", 0.001 );
// flags
iFlags = pKey->GetInt( "flags", 0 );
AddKeyFrame( new CViewAngleKeyFrame( angles, flTime, iFlags ) );
pKey = pKey->GetNextKey();
}
pData->deleteThis();
}
void CViewAngleAnimation::SaveAsAnimFile( const char *pKeyFrameFileName )
{
// save all of our keyframes into the file
KeyValues *pData = new KeyValues( pKeyFrameFileName );
pData->SetInt( "flags", m_iFlags );
KeyValues *pKey = new KeyValues( "keyframe" );
int i;
int c = m_KeyFrames.Count();
char buf[64];
for ( i=0;i<c;i++ )
{
pKey = pData->CreateNewKey();
Q_snprintf( buf, sizeof(buf), "%f %f %f",
m_KeyFrames[i]->m_vecAngles[0],
m_KeyFrames[i]->m_vecAngles[1],
m_KeyFrames[i]->m_vecAngles[2] );
pKey->SetString( "angles", buf );
pKey->SetFloat( "time", m_KeyFrames[i]->m_flTime );
pKey->SetInt( "flags", m_KeyFrames[i]->m_iFlags );
}
pData->SaveToFile( filesystem, pKeyFrameFileName, NULL );
pData->deleteThis();
}
void CViewAngleAnimation::AddKeyFrame( CViewAngleKeyFrame *pKeyFrame )
{
pKeyFrame->m_vecAngles -= m_vecBaseAngles;
m_KeyFrames.AddToTail( pKeyFrame );
}
bool CViewAngleAnimation::IsFinished( void )
{
return m_bFinished;
}
void CViewAngleAnimation::RunAnimation( QAngle angles )
{
if ( m_KeyFrames.Count() == 0 )
{
Warning( "CViewAngleAnimation::RunAnimation called on an empty view animation\n" );
return;
}
m_flAnimStartTime = gpGlobals->curtime;
m_bFinished = false;
m_vecBaseAngles = angles;
m_iFlags = m_KeyFrames[0]->m_iFlags;
if ( !( m_iFlags & VIEWANIM_RELATIVE ) )
{
m_KeyFrames[0]->m_vecAngles = angles;
}
}
void CViewAngleAnimation::ClientThink()
{
if ( IsFinished() )
return;
float flCurrentTime = gpGlobals->curtime - m_flAnimStartTime;
if ( flCurrentTime < 0 )
flCurrentTime = 0.001;
// find two nearest points
int i, c;
c = m_KeyFrames.Count();
float flTime = 0;
for ( i=0;i<c;i++ )
{
if ( flTime + m_KeyFrames[i]->m_flTime > flCurrentTime )
{
break;
}
flTime += m_KeyFrames[i]->m_flTime;
}
Assert( i > 0 );
if ( i >= c )
{
if ( i > 0 )
{
// animation complete, set to end point
SetAngles( m_KeyFrames[i-1]->m_vecAngles );
}
if ( m_pAnimCompleteCallback )
{
m_pAnimCompleteCallback();
}
m_bFinished = true;
return;
}
if ( m_KeyFrames[i]->m_iFlags != m_iFlags )
{
if ( ( m_KeyFrames[i]->m_iFlags & VIEWANIM_RELATIVE ) && !( m_iFlags & VIEWANIM_RELATIVE ) )
{
// new relative position is current angles
engine->GetViewAngles( m_vecBaseAngles );
}
// copy the rest over
m_iFlags = m_KeyFrames[i]->m_iFlags;
}
// previous frame is m_KeyFrames[i-1];
// next frame is m_KeyFrames[i];
float flFraction = ( flCurrentTime - flTime ) / ( m_KeyFrames[i]->m_flTime );
Vector v0, v1, v2, v3;
if ( i-2 <= 0 )
{
QAngleToVector( m_KeyFrames[i-1]->m_vecAngles, v0 );
}
else
{
QAngleToVector( m_KeyFrames[i-2]->m_vecAngles, v0 );
}
QAngleToVector( m_KeyFrames[i-1]->m_vecAngles, v1 );
QAngleToVector( m_KeyFrames[i]->m_vecAngles, v2 );
if ( i+1 >= c )
{
QAngleToVector( m_KeyFrames[i]->m_vecAngles, v3 );
}
else
{
QAngleToVector( m_KeyFrames[i+1]->m_vecAngles, v3 );
}
Vector out;
Catmull_Rom_Spline( v0, v1, v2, v3, flFraction, out );
QAngle vecCalculatedAngles;
QAngleToVector( out, vecCalculatedAngles );
SetAngles( vecCalculatedAngles );
}
void CViewAngleAnimation::SetAngles( QAngle vecCalculatedAngles )
{
if ( m_iFlags & VIEWANIM_RELATIVE )
vecCalculatedAngles += m_vecBaseAngles;
QAngle vecViewAngle;
engine->GetViewAngles( vecViewAngle );
if ( !(FBitSet( m_iFlags, VIEWANIM_IGNORE_X ) ) )
vecViewAngle[PITCH] = vecCalculatedAngles[PITCH];
if ( !(FBitSet( m_iFlags, VIEWANIM_IGNORE_Y ) ) )
vecViewAngle[YAW] = vecCalculatedAngles[YAW];
if ( !(FBitSet( m_iFlags, VIEWANIM_IGNORE_Z ) ) )
vecViewAngle[ROLL] = vecCalculatedAngles[ROLL];
// clamp pitch
vecViewAngle[PITCH] = clamp( vecViewAngle[PITCH], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() );
engine->SetViewAngles( vecViewAngle );
}

View File

@@ -0,0 +1,75 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "utlvector.h"
#define VIEWANIM_RELATIVE (1<<0) // angles in keyframe are relative, add anim to current angles
#define VIEWANIM_IGNORE_X (1<<1) // ignore the x component of this animation
#define VIEWANIM_IGNORE_Y (1<<2) // ditto for y
#define VIEWANIM_IGNORE_Z (1<<3) // ditto for z
#define QAngleToVector(a,v) { v[0] = a[0]; v[1] = a[1]; v[2] = a[2]; }
class CViewAngleKeyFrame
{
public:
CViewAngleKeyFrame( QAngle vecAngles, float flTime, int iFlags )
{
m_vecAngles = vecAngles;
m_flTime = flTime;
m_iFlags = iFlags;
}
// the target angles for this keyframe in the view angle animation
QAngle m_vecAngles;
// time position of this keyframe
float m_flTime;
int m_iFlags;
};
typedef void (*ViewAnimCompleteCallback)( void );
class CViewAngleAnimation : public C_BaseEntity
{
public:
CViewAngleAnimation();
~CViewAngleAnimation();
virtual void Spawn();
void DeleteKeyFrames();
void LoadViewAnimFile( const char *pKeyFrameFileName );
void SaveAsAnimFile( const char *pKeyFrameFileName );
void AddKeyFrame( CViewAngleKeyFrame *pKeyFrame );
bool IsFinished( void );
void RunAnimation( QAngle angles );
void ClientThink();
void SetAnimCompleteCallback( ViewAnimCompleteCallback pFunc )
{
m_pAnimCompleteCallback = pFunc;
}
private:
void SetAngles( QAngle vecCalculatedAngles );
float m_flAnimStartTime; // time this animation started
bool m_bFinished;
CUtlVector<CViewAngleKeyFrame *> m_KeyFrames;
QAngle m_vecBaseAngles;
int m_iFlags;
ViewAnimCompleteCallback m_pAnimCompleteCallback;
};

675
game/client/viewdebug.cpp Normal file
View File

@@ -0,0 +1,675 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "tier0/vprof.h"
#include "view_scene.h"
#include "viewrender.h"
#include "viewdebug.h"
#include "smoke_fog_overlay.h"
#include "materialsystem/imaterialvar.h"
#ifdef PORTAL
//#include "C_Portal_Player.h"
#include "portal_render_targets.h"
#include "PortalRender.h"
#endif
//-----------------------------------------------------------------------------
// debugging overlays
//-----------------------------------------------------------------------------
static ConVar cl_drawmaterial( "cl_drawmaterial", "", FCVAR_CHEAT, "Draw a particular material over the frame" );
static ConVar mat_showwatertextures( "mat_showwatertextures", "0", FCVAR_CHEAT );
static ConVar mat_wateroverlaysize( "mat_wateroverlaysize", "256" );
static ConVar mat_showframebuffertexture( "mat_showframebuffertexture", "0", FCVAR_CHEAT );
static ConVar mat_framebuffercopyoverlaysize( "mat_framebuffercopyoverlaysize", "256" );
static ConVar mat_showcamerarendertarget( "mat_showcamerarendertarget", "0", FCVAR_CHEAT );
static ConVar mat_camerarendertargetoverlaysize( "mat_camerarendertargetoverlaysize", "256", FCVAR_CHEAT );
static ConVar mat_hsv( "mat_hsv", "0", FCVAR_CHEAT );
static ConVar mat_yuv( "mat_yuv", "0", FCVAR_CHEAT );
static ConVar cl_overdraw_test( "cl_overdraw_test", "0", FCVAR_CHEAT | FCVAR_NEVER_AS_STRING );
static ConVar mat_drawTexture( "mat_drawTexture", "", 0, "Enable debug view texture" );
static ConVar mat_drawTextureScale( "mat_drawTextureScale", "1.0", 0, "Debug view texture scale" );
#ifdef _X360
static ConVar mat_drawColorRamp( "mat_drawColorRamp", "0", 0, "Draw color test pattern (0=Off, 1=[0..255], 2=[0..127]" );
#endif
//-----------------------------------------------------------------------------
// debugging
//-----------------------------------------------------------------------------
// (the engine owns this cvar).
ConVar mat_wireframe( "mat_wireframe", "0", FCVAR_CHEAT );
const ConVar *sv_cheats = NULL;
ConVar mat_showlightmappage( "mat_showlightmappage", "-1" ); // set this to the lightmap page that you want to see on screen, set to -1 to show nothing.
ConVar cl_drawshadowtexture( "cl_drawshadowtexture", "0", FCVAR_CHEAT );
ConVar cl_shadowtextureoverlaysize( "cl_shadowtextureoverlaysize", "256", FCVAR_CHEAT );
static ConVar r_flashlightdrawdepth( "r_flashlightdrawdepth", "0" );
//-----------------------------------------------------------------------------
// Lightmap debugging mode view
//-----------------------------------------------------------------------------
class CLightmapDebugView : public CRendering3dView
{
public:
CLightmapDebugView(CViewRender *pMainView) : CRendering3dView( pMainView ) {}
void Draw()
{
extern bool s_bCanAccessCurrentView;
s_bCanAccessCurrentView = true;
Frustum frustum;
render->Push3DView( *this, 0, NULL, frustum );
BuildWorldRenderLists( this, true, true );
render->PopView( frustum );
s_bCanAccessCurrentView = false;
render->DrawLightmaps( m_pWorldRenderList, mat_showlightmappage.GetInt() );
}
};
//-----------------------------------------------------------------------------
// Renders a material orthographically to screen...
//-----------------------------------------------------------------------------
static void RenderMaterial( const char *pMaterialName )
{
// So it's not in the very top left
float x = 100.0f, y = 100.0f;
// float x = 0.0f, y = 0.0f;
IMaterial *pMaterial = materials->FindMaterial( pMaterialName, TEXTURE_GROUP_OTHER, false );
if ( !IsErrorMaterial( pMaterial ) )
{
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( pMaterial );
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
meshBuilder.Position3f( x, y, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( x + pMaterial->GetMappingWidth(), y, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( x + pMaterial->GetMappingWidth(), y + pMaterial->GetMappingHeight(), 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( x, y + pMaterial->GetMappingHeight(), 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
}
static void OverlayWaterTexture( IMaterial *pMaterial, int xOffset, int yOffset, bool bFlip )
{
// screen safe
float xBaseOffset = IsPC() ? 0 : 32;
float yBaseOffset = IsPC() ? 0 : 32;
float offsetS = ( 0.5f / 256.0f );
float offsetT = ( 0.5f / 256.0f );
float fFlip0 = bFlip ? 1.0f : 0.0f;
float fFlip1 = bFlip ? 0.0f : 1.0f;
if( !IsErrorMaterial( pMaterial ) )
{
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( pMaterial );
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
float w = mat_wateroverlaysize.GetFloat();
float h = mat_wateroverlaysize.GetFloat();
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
meshBuilder.Position3f( xBaseOffset + xOffset * w, yBaseOffset + yOffset * h, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f + offsetS, fFlip1 + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xBaseOffset + ( xOffset + 1 ) * w, yBaseOffset + yOffset * h, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f + offsetS, fFlip1 + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xBaseOffset + ( xOffset + 1 ) * w, yBaseOffset + ( yOffset + 1 ) * h, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f + offsetS, fFlip0 + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xBaseOffset + xOffset * w, yBaseOffset + ( yOffset + 1 ) * h, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f + offsetS, fFlip0 + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
}
static void OverlayWaterTextures( void )
{
OverlayWaterTexture( materials->FindMaterial( "debug/debugreflect", NULL ), 0, 0, false );
OverlayWaterTexture( materials->FindMaterial( "debug/debugrefract", NULL ), 0, 1, true );
}
void OverlayCameraRenderTarget( const char *pszMaterialName, float flX, float flY, float w, float h )
{
float offsetS = ( 0.5f / 256.0f );
float offsetT = ( 0.5f / 256.0f );
IMaterial *pMaterial;
pMaterial = materials->FindMaterial( pszMaterialName, TEXTURE_GROUP_OTHER, true );
if( !IsErrorMaterial( pMaterial ) )
{
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( pMaterial );
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
meshBuilder.Position3f( flX, flY, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f + offsetS, 0.0f + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( flX+w, flY, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f + offsetS, 0.0f + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( flX+w, flY+h, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f + offsetS, 1.0f + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( flX, flY+h, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f + offsetS, 1.0f + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
}
static void OverlayFrameBufferTexture( int nFrameBufferIndex )
{
float offsetS = ( 0.5f / 256.0f );
float offsetT = ( 0.5f / 256.0f );
IMaterial *pMaterial;
char buf[MAX_PATH];
Q_snprintf( buf, MAX_PATH, "debug/debugfbtexture%d", nFrameBufferIndex );
pMaterial = materials->FindMaterial( buf, TEXTURE_GROUP_OTHER, true );
if( !IsErrorMaterial( pMaterial ) )
{
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( pMaterial );
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
float w = mat_framebuffercopyoverlaysize.GetFloat();
float h = mat_framebuffercopyoverlaysize.GetFloat();
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
meshBuilder.Position3f( w * nFrameBufferIndex, 0.0f, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f + offsetS, 0.0f + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( w * ( nFrameBufferIndex + 1 ), 0.0f, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f + offsetS, 0.0f + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( w * ( nFrameBufferIndex + 1 ), h, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f + offsetS, 1.0f + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( w * nFrameBufferIndex, h, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f + offsetS, 1.0f + offsetT );
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
}
//-----------------------------------------------------------------------------
// Debugging aid to display a texture
//-----------------------------------------------------------------------------
static void OverlayShowTexture( const char* textureName, float scale )
{
bool foundVar;
IMaterial *pMaterial;
IMaterialVar *BaseTextureVar;
ITexture *pTex;
float x, y, w, h;
// screen safe
x = 32;
y = 32;
pMaterial = materials->FindMaterial( "___debug", TEXTURE_GROUP_OTHER, true );
BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
if (!foundVar)
return;
CMatRenderContextPtr pRenderContext( materials );
if ( textureName && textureName[0] )
{
pTex = materials->FindTexture( textureName, TEXTURE_GROUP_OTHER, false );
BaseTextureVar->SetTextureValue( pTex );
w = pTex->GetActualWidth() * scale;
h = pTex->GetActualHeight() * scale;
}
else
{
w = h = 64.0f * scale;
}
pRenderContext->Bind( pMaterial );
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
meshBuilder.Position3f( x, y, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( x+w, y, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( x+w, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( x, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Debugging aid to display a color ramp
//-----------------------------------------------------------------------------
#if defined( _X360 )
static void OverlayColorRamp( bool bHalfSpace )
{
IMaterial *pMaterial;
float x, y, w, h;
pMaterial = materials->FindMaterial( "vgui/white", TEXTURE_GROUP_OTHER, true );
int backBufferWidth, backBufferHeight;
materials->GetBackBufferDimensions( backBufferWidth, backBufferHeight );
w = ( backBufferWidth == 1280 ) ? 1024 : 512;
h = 80;
x = ( backBufferWidth - w )/2;
y = ( backBufferHeight - 4*h )/2;
int numBands = 32;
int color0 = 0;
int color1 = bHalfSpace ? 127 : 255;
int colorStep = (color1 - color0 + 1)/numBands;
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( pMaterial );
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
CMeshBuilder meshBuilder;
// draw ticks
int xx = x;
meshBuilder.Begin( pMesh, MATERIAL_LINES, numBands+1 );
for ( int i=0; i<numBands+1; i++ )
{
meshBuilder.Position3f( xx, y-10, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
meshBuilder.Color3ub( 255, 255, 0 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx, y, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
meshBuilder.Color3ub( 255, 255, 0 );
meshBuilder.AdvanceVertex();
xx += w/numBands;
}
meshBuilder.End();
pMesh->Draw();
// black to white band
xx = x;
int color = color0;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, numBands );
for ( int i=0; i<numBands+1; i++ )
{
meshBuilder.Position3f( xx, y, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
meshBuilder.Color3ub( color, color, color );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx+w/numBands, y, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
meshBuilder.Color3ub( color, color, color );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx+w/numBands, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
meshBuilder.Color3ub( color, color, color );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
meshBuilder.Color3ub( color, color, color );
meshBuilder.AdvanceVertex();
color += colorStep;
if ( color > 255 )
color = 255;
xx += w/numBands;
}
meshBuilder.End();
pMesh->Draw();
// white to black band
color = color1;
y += h;
xx = x;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, numBands );
for ( int i=0; i<numBands+1; i++ )
{
meshBuilder.Position3f( xx, y, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
meshBuilder.Color3ub( color, color, color );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx+w/numBands, y, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
meshBuilder.Color3ub( color, color, color );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx+w/numBands, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
meshBuilder.Color3ub( color, color, color );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
meshBuilder.Color3ub( color, color, color );
meshBuilder.AdvanceVertex();
color -= colorStep;
if ( color < 0 )
color = 0;
xx += w/numBands;
}
meshBuilder.End();
pMesh->Draw();
// red band
color = color1;
y += h;
xx = x;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, numBands );
for ( int i=0; i<numBands+1; i++ )
{
meshBuilder.Position3f( xx, y, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
meshBuilder.Color3ub( color, 0, 0 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx+w/numBands, y, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
meshBuilder.Color3ub( color, 0, 0 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx+w/numBands, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
meshBuilder.Color3ub( color, 0, 0 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
meshBuilder.Color3ub( color, 0, 0 );
meshBuilder.AdvanceVertex();
color -= colorStep;
if ( color < 0 )
color = 0;
xx += w/numBands;
}
meshBuilder.End();
pMesh->Draw();
// green band
color = color1;
y += h;
xx = x;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, numBands );
for ( int i=0; i<numBands+1; i++ )
{
meshBuilder.Position3f( xx, y, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
meshBuilder.Color3ub( 0, color, 0 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx+w/numBands, y, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
meshBuilder.Color3ub( 0, color, 0 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx+w/numBands, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
meshBuilder.Color3ub( 0, color, 0 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
meshBuilder.Color3ub( 0, color, 0 );
meshBuilder.AdvanceVertex();
color -= colorStep;
if ( color < 0 )
color = 0;
xx += w/numBands;
}
meshBuilder.End();
pMesh->Draw();
// blue band
color = color1;
y += h;
xx = x;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, numBands );
for ( int i=0; i<numBands+1; i++ )
{
meshBuilder.Position3f( xx, y, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
meshBuilder.Color3ub( 0, 0, color );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx+w/numBands, y, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
meshBuilder.Color3ub( 0, 0, color );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx+w/numBands, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
meshBuilder.Color3ub( 0, 0, color );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( xx, y+h, 0.0f );
meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
meshBuilder.Color3ub( 0, 0, color );
meshBuilder.AdvanceVertex();
color -= colorStep;
if ( color < 0 )
color = 0;
xx += w/numBands;
}
meshBuilder.End();
pMesh->Draw();
}
#endif
//-----------------------------------------------------------------------------
// Draws all the debugging info
//-----------------------------------------------------------------------------
void CDebugViewRender::Draw3DDebuggingInfo( const CViewSetup &view )
{
VPROF("CViewRender::Draw3DDebuggingInfo");
// Draw 3d overlays
render->Draw3DDebugOverlays();
// Draw the line file used for debugging leaks
render->DrawLineFile();
}
//-----------------------------------------------------------------------------
// Draws all the debugging info
//-----------------------------------------------------------------------------
void CDebugViewRender::Draw2DDebuggingInfo( const CViewSetup &view )
{
if ( IsX360() && IsRetail() )
return;
// HDRFIXME: Assert NULL rendertarget
if ( mat_yuv.GetInt() && (engine->GetDXSupportLevel() >= 80) )
{
IMaterial *pMaterial;
pMaterial = materials->FindMaterial( "debug/yuv", TEXTURE_GROUP_OTHER, true );
if( !IsErrorMaterial( pMaterial ) )
{
pMaterial->IncrementReferenceCount();
DrawScreenEffectMaterial( pMaterial, view.x, view.y, view.width, view.height );
pMaterial->DecrementReferenceCount();
}
}
if ( mat_hsv.GetInt() && (engine->GetDXSupportLevel() >= 90) )
{
IMaterial *pMaterial;
pMaterial = materials->FindMaterial( "debug/hsv", TEXTURE_GROUP_OTHER, true );
if( !IsErrorMaterial( pMaterial ) )
{
pMaterial->IncrementReferenceCount();
DrawScreenEffectMaterial( pMaterial, view.x, view.y, view.width, view.height );
pMaterial->DecrementReferenceCount();
}
}
// Draw debugging lightmaps
if ( mat_showlightmappage.GetInt() != -1 )
{
CLightmapDebugView clientView( assert_cast<CViewRender *>( ::view ) );
clientView.Setup( view );
clientView.Draw();
}
if ( cl_drawshadowtexture.GetInt() )
{
int nSize = cl_shadowtextureoverlaysize.GetInt();
g_pClientShadowMgr->RenderShadowTexture( nSize, nSize );
}
const char *pDrawMaterial = cl_drawmaterial.GetString();
if ( pDrawMaterial && pDrawMaterial[0] )
{
RenderMaterial( pDrawMaterial );
}
if ( mat_showwatertextures.GetBool() )
{
OverlayWaterTextures();
}
if ( mat_showcamerarendertarget.GetBool() )
{
float w = mat_wateroverlaysize.GetFloat();
float h = mat_wateroverlaysize.GetFloat();
#ifdef PORTAL
g_pPortalRender->OverlayPortalRenderTargets( w, h );
#else
OverlayCameraRenderTarget( "debug/debugcamerarendertarget", 0, 0, w, h );
#endif
}
if ( mat_showframebuffertexture.GetBool() )
{
// HDRFIXME: Get rid of these rendertarget sets assuming that the assert at the top of this function is true.
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->PushRenderTargetAndViewport( NULL );
OverlayFrameBufferTexture( 0 );
OverlayFrameBufferTexture( 1 );
pRenderContext->PopRenderTargetAndViewport( );
}
const char *pDrawTexture = mat_drawTexture.GetString();
if ( pDrawTexture && pDrawTexture[0] )
{
OverlayShowTexture( pDrawTexture, mat_drawTextureScale.GetFloat() );
}
#ifdef _X360
if ( mat_drawColorRamp.GetBool() )
{
OverlayColorRamp( mat_drawColorRamp.GetInt() == 2 );
}
#endif
if ( r_flashlightdrawdepth.GetBool() )
{
shadowmgr->DrawFlashlightDepthTexture( );
}
}
//-----------------------------------------------------------------------------
// A console command allowing you to draw a material as an overlay
//-----------------------------------------------------------------------------
CON_COMMAND_F( r_screenoverlay, "Draw specified material as an overlay", FCVAR_CHEAT|FCVAR_SERVER_CAN_EXECUTE )
{
if( args.ArgC() == 2 )
{
if ( !Q_stricmp( "off", args[1] ) )
{
view->SetScreenOverlayMaterial( NULL );
}
else
{
IMaterial *pMaterial = materials->FindMaterial( args[1], TEXTURE_GROUP_OTHER, false );
if ( !IsErrorMaterial( pMaterial ) )
{
view->SetScreenOverlayMaterial( pMaterial );
}
else
{
view->SetScreenOverlayMaterial( NULL );
}
}
}
else
{
IMaterial *pMaterial = view->GetScreenOverlayMaterial();
Warning( "r_screenoverlay: %s\n", pMaterial ? pMaterial->GetName() : "off" );
}
}
// Used to verify frame syncing.
void CDebugViewRender::GenerateOverdrawForTesting()
{
if ( IsX360() )
return;
if ( !cl_overdraw_test.GetInt() )
return;
for ( int i=0; i < 40; i++ )
{
g_SmokeFogOverlayAlpha = 20 / 255.0;
DrawSmokeFogOverlay();
}
g_SmokeFogOverlayAlpha = 0;
}

29
game/client/viewdebug.h Normal file
View File

@@ -0,0 +1,29 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef VIEWDEBUG_H
#define VIEWDEBUG_H
#if defined( _WIN32 )
#pragma once
#endif
class CViewSetup;
//-----------------------------------------------------------------------------
// Purpose: Implements the debugging elements of view rendering
//-----------------------------------------------------------------------------
class CDebugViewRender
{
DECLARE_CLASS_NOBASE( CDebugViewRender );
public:
// Draws all the debugging info
static void Draw3DDebuggingInfo( const CViewSetup &view );
static void Draw2DDebuggingInfo( const CViewSetup &view );
static void GenerateOverdrawForTesting();
};
#endif // VIEWDEBUG_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef VIEWPOSTPROCESS_H
#define VIEWPOSTPROCESS_H
#if defined( _WIN32 )
#pragma once
#endif
void DoEnginePostProcessing( int x, int y, int w, int h, bool bFlashlightIsOn, bool bPostVGui = false );
void DoImageSpaceMotionBlur( const CViewSetup &view, int x, int y, int w, int h );
void DumpTGAofRenderTarget( const int width, const int height, const char *pFilename );
void DoSSAO(const CViewSetup &viewSet);
#endif // VIEWPOSTPROCESS_H

7302
game/client/viewrender.cpp Normal file

File diff suppressed because it is too large Load Diff

560
game/client/viewrender.h Normal file
View File

@@ -0,0 +1,560 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#if !defined( VIEWRENDER_H )
#define VIEWRENDER_H
#ifdef _WIN32
#pragma once
#endif
#include "shareddefs.h"
#include "tier1/utlstack.h"
#include "iviewrender.h"
#include "view_shared.h"
#include "replay/ireplayscreenshotsystem.h"
//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
class ConVar;
class CClientRenderablesList;
class IClientVehicle;
class C_PointCamera;
class C_EnvProjectedTexture;
class IScreenSpaceEffect;
class CClientViewSetup;
class CViewRender;
struct ClientWorldListInfo_t;
class C_BaseEntity;
struct WriteReplayScreenshotParams_t;
class CReplayScreenshotTaker;
#ifdef HL2_EPISODIC
class CStunEffect;
#endif // HL2_EPISODIC
#ifdef MAPBASE
class C_FuncFakeWorldPortal;
#endif
//-----------------------------------------------------------------------------
// Data specific to intro mode to control rendering.
//-----------------------------------------------------------------------------
struct IntroDataBlendPass_t
{
int m_BlendMode;
float m_Alpha; // in [0.0f,1.0f] This needs to add up to 1.0 for all passes, unless you are fading out.
};
struct IntroData_t
{
bool m_bDrawPrimary;
Vector m_vecCameraView;
QAngle m_vecCameraViewAngles;
#ifdef MAPBASE
// Used for ortho views
CHandle<C_PointCamera> m_hCameraEntity;
#endif
float m_playerViewFOV;
CUtlVector<IntroDataBlendPass_t> m_Passes;
// Fade overriding for the intro
float m_flCurrentFadeColor[4];
#ifdef MAPBASE
// Draws the skybox.
bool m_bDrawSky;
// Draws the skybox in the secondary camera as well.
bool m_bDrawSky2;
#endif
};
// Robin, make this point at something to get intro mode.
extern IntroData_t *g_pIntroData;
// This identifies the view for certain systems that are unique per view (e.g. pixel visibility)
// NOTE: This is identifying which logical part of the scene an entity is being redered in
// This is not identifying a particular render target necessarily. This is mostly needed for entities that
// can be rendered more than once per frame (pixel vis queries need to be identified per-render call)
enum view_id_t
{
VIEW_ILLEGAL = -2,
VIEW_NONE = -1,
VIEW_MAIN = 0,
VIEW_3DSKY = 1,
VIEW_MONITOR = 2,
VIEW_REFLECTION = 3,
VIEW_REFRACTION = 4,
VIEW_INTRO_PLAYER = 5,
VIEW_INTRO_CAMERA = 6,
VIEW_SHADOW_DEPTH_TEXTURE = 7,
VIEW_SSAO = 8,
VIEW_ID_COUNT
};
view_id_t CurrentViewID();
//-----------------------------------------------------------------------------
// Purpose: Stored pitch drifting variables
//-----------------------------------------------------------------------------
class CPitchDrift
{
public:
float pitchvel;
bool nodrift;
float driftmove;
double laststop;
};
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
struct ViewCustomVisibility_t
{
ViewCustomVisibility_t()
{
m_nNumVisOrigins = 0;
m_VisData.m_fDistToAreaPortalTolerance = FLT_MAX;
m_iForceViewLeaf = -1;
}
void AddVisOrigin( const Vector& origin )
{
// Don't allow them to write past array length
AssertMsg( m_nNumVisOrigins < MAX_VIS_LEAVES, "Added more origins than will fit in the array!" );
// If the vis origin count is greater than the size of our array, just fail to add this origin
if ( m_nNumVisOrigins >= MAX_VIS_LEAVES )
return;
m_rgVisOrigins[ m_nNumVisOrigins++ ] = origin;
}
void ForceVisOverride( VisOverrideData_t& visData )
{
m_VisData = visData;
}
void ForceViewLeaf ( int iViewLeaf )
{
m_iForceViewLeaf = iViewLeaf;
}
// Set to true if you want to use multiple origins for doing client side map vis culling
// NOTE: In generaly, you won't want to do this, and by default the 3d origin of the camera, as above,
// will be used as the origin for vis, too.
int m_nNumVisOrigins;
// Array of origins
Vector m_rgVisOrigins[ MAX_VIS_LEAVES ];
// The view data overrides for visibility calculations with area portals
VisOverrideData_t m_VisData;
// The starting leaf to determing which area to start in when performing area portal culling on the engine
// Default behavior is to use the leaf the camera position is in.
int m_iForceViewLeaf;
};
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
struct WaterRenderInfo_t
{
bool m_bCheapWater : 1;
bool m_bReflect : 1;
bool m_bRefract : 1;
bool m_bReflectEntities : 1;
bool m_bDrawWaterSurface : 1;
bool m_bOpaqueWater : 1;
};
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CBase3dView : public CRefCounted<>,
protected CViewSetup
{
DECLARE_CLASS_NOBASE( CBase3dView );
public:
CBase3dView( CViewRender *pMainView );
VPlane * GetFrustum();
virtual int GetDrawFlags() { return 0; }
#ifdef PORTAL
virtual void EnableWorldFog() {};
#endif
protected:
// @MULTICORE (toml 8/11/2006): need to have per-view frustum. Change when move view stack to client
VPlane *m_Frustum;
CViewRender *m_pMainView;
};
//-----------------------------------------------------------------------------
// Base class for 3d views
//-----------------------------------------------------------------------------
class CRendering3dView : public CBase3dView
{
DECLARE_CLASS( CRendering3dView, CBase3dView );
public:
CRendering3dView( CViewRender *pMainView );
virtual ~CRendering3dView() { ReleaseLists(); }
void Setup( const CViewSetup &setup );
// What are we currently rendering? Returns a combination of DF_ flags.
virtual int GetDrawFlags();
virtual void Draw() {};
protected:
// Fog setup
void EnableWorldFog( void );
void SetFogVolumeState( const VisibleFogVolumeInfo_t &fogInfo, bool bUseHeightFog );
// Draw setup
void SetupRenderablesList( int viewID );
void UpdateRenderablesOpacity();
// If iForceViewLeaf is not -1, then it uses the specified leaf as your starting area for setting up area portal culling.
// This is used by water since your reflected view origin is often in solid space, but we still want to treat it as though
// the first portal we're looking out of is a water portal, so our view effectively originates under the water.
void BuildWorldRenderLists( bool bDrawEntities, int iForceViewLeaf = -1, bool bUseCacheIfEnabled = true, bool bShadowDepth = false, float *pReflectionWaterHeight = NULL );
// Purpose: Builds render lists for renderables. Called once for refraction, once for over water
void BuildRenderableRenderLists( int viewID );
// More concise version of the above BuildRenderableRenderLists(). Called for shadow depth map rendering
void BuildShadowDepthRenderableRenderLists();
void DrawWorld( float waterZAdjust );
// Draws all opaque/translucent renderables in leaves that were rendered
void DrawOpaqueRenderables( ERenderDepthMode DepthMode );
void DrawTranslucentRenderables( bool bInSkybox, bool bShadowDepth );
// Renders all translucent entities in the render list
void DrawTranslucentRenderablesNoWorld( bool bInSkybox );
// Draws translucent renderables that ignore the Z buffer
void DrawNoZBufferTranslucentRenderables( void );
// Renders all translucent world surfaces in a particular set of leaves
void DrawTranslucentWorldInLeaves( bool bShadowDepth );
// Renders all translucent world + detail objects in a particular set of leaves
void DrawTranslucentWorldAndDetailPropsInLeaves( int iCurLeaf, int iFinalLeaf, int nEngineDrawFlags, int &nDetailLeafCount, LeafIndex_t* pDetailLeafList, bool bShadowDepth );
// Purpose: Computes the actual world list info based on the render flags
void PruneWorldListInfo();
#ifdef PORTAL
virtual bool ShouldDrawPortals() { return true; }
#endif
void ReleaseLists();
//-----------------------------------------------
// Combination of DF_ flags.
int m_DrawFlags;
int m_ClearFlags;
IWorldRenderList *m_pWorldRenderList;
CClientRenderablesList *m_pRenderablesList;
ClientWorldListInfo_t *m_pWorldListInfo;
ViewCustomVisibility_t *m_pCustomVisibility;
};
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CRenderExecutor
{
DECLARE_CLASS_NOBASE( CRenderExecutor );
public:
virtual void AddView( CRendering3dView *pView ) = 0;
virtual void Execute() = 0;
protected:
CRenderExecutor( CViewRender *pMainView ) : m_pMainView( pMainView ) {}
CViewRender *m_pMainView;
};
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CSimpleRenderExecutor : public CRenderExecutor
{
DECLARE_CLASS( CSimpleRenderExecutor, CRenderExecutor );
public:
CSimpleRenderExecutor( CViewRender *pMainView ) : CRenderExecutor( pMainView ) {}
void AddView( CRendering3dView *pView );
void Execute() {}
};
//-----------------------------------------------------------------------------
// Purpose: Implements the interface to view rendering for the client .dll
//-----------------------------------------------------------------------------
class CViewRender : public IViewRender,
public IReplayScreenshotSystem
{
DECLARE_CLASS_NOBASE( CViewRender );
public:
virtual void Init( void );
virtual void Shutdown( void );
const CViewSetup *GetPlayerViewSetup( ) const;
virtual void StartPitchDrift( void );
virtual void StopPitchDrift( void );
virtual float GetZNear();
virtual float GetZFar();
virtual void OnRenderStart();
void DriftPitch (void);
static CViewRender * GetMainView() { return assert_cast<CViewRender *>( view ); }
void AddViewToScene( CRendering3dView *pView ) { m_SimpleExecutor.AddView( pView ); }
protected:
// Sets up the view parameters for all views (left, middle and right eyes).
void SetUpViews();
// Sets up the view parameters of map overview mode (cl_leveloverview)
void SetUpOverView();
// generates a low-res screenshot for save games
virtual void WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded = false, bool bWriteVTF = false );
void WriteSaveGameScreenshot( const char *filename );
virtual IReplayScreenshotSystem *GetReplayScreenshotSystem() { return this; }
// IReplayScreenshot implementation
virtual void WriteReplayScreenshot( WriteReplayScreenshotParams_t &params );
virtual void UpdateReplayScreenshotCache();
StereoEye_t GetFirstEye() const;
StereoEye_t GetLastEye() const;
CViewSetup & GetView(StereoEye_t eEye);
const CViewSetup & GetView(StereoEye_t eEye) const ;
// This stores all of the view setup parameters that the engine needs to know about.
// Best way to pick the right one is with ::GetView(), rather than directly.
CViewSetup m_View; // mono <- in stereo mode, this will be between the two eyes and is the "main" view.
CViewSetup m_ViewLeft; // left (unused for mono)
CViewSetup m_ViewRight; // right (unused for mono)
// Pitch drifting data
CPitchDrift m_PitchDrift;
public:
CViewRender();
virtual ~CViewRender( void ) {}
// Implementation of IViewRender interface
public:
void SetupVis( const CViewSetup& view, unsigned int &visFlags, ViewCustomVisibility_t *pCustomVisibility = NULL );
// Render functions
virtual void Render( vrect_t *rect );
virtual void RenderView( const CViewSetup &view, int nClearFlags, int whatToDraw );
void DrawDOF(int x, int y, int width, int height);//OverCharged
// void DrawSSAO2_Support(int x, int y, int width, int height);//OverCharged
void DrawIRDOF(int x, int y, int width, int height);//OverCharged
// void DoSSAO(const CViewSetup &viewSet);//OverCharged
virtual void RenderPlayerSprites();
virtual void Render2DEffectsPreHUD( const CViewSetup &view );
virtual void Render2DEffectsPostHUD( const CViewSetup &view );
void DisableFog( void );
// Called once per level change
void LevelInit( void );
void LevelShutdown( void );
// Add entity to transparent entity queue
bool ShouldDrawEntities( void );
bool ShouldDrawBrushModels( void );
const CViewSetup *GetViewSetup( ) const;
void DisableVis( void );
// Sets up the view model position relative to the local player
void MoveViewModels( );
// Gets the abs origin + angles of the view models
void GetViewModelPosition( int nIndex, Vector *pPos, QAngle *pAngle );
void SetCheapWaterStartDistance( float flCheapWaterStartDistance );
void SetCheapWaterEndDistance( float flCheapWaterEndDistance );
void GetWaterLODParams( float &flCheapWaterStartDistance, float &flCheapWaterEndDistance );
virtual void QueueOverlayRenderView( const CViewSetup &view, int nClearFlags, int whatToDraw );
virtual void GetScreenFadeDistances( float *min, float *max );
virtual C_BaseEntity *GetCurrentlyDrawingEntity();
virtual void SetCurrentlyDrawingEntity( C_BaseEntity *pEnt );
virtual bool UpdateShadowDepthTexture( ITexture *pRenderTarget, ITexture *pDepthTexture, const CViewSetup &shadowView );
int GetBaseDrawFlags() { return m_BaseDrawFlags; }
virtual bool ShouldForceNoVis() { return m_bForceNoVis; }
int BuildRenderablesListsNumber() const { return m_BuildRenderableListsNumber; }
int IncRenderablesListsNumber() { return ++m_BuildRenderableListsNumber; }
int BuildWorldListsNumber() const;
int IncWorldListsNumber() { return ++m_BuildWorldListsNumber; }
virtual VPlane* GetFrustum() { return ( m_pActiveRenderer ) ? m_pActiveRenderer->GetFrustum() : m_Frustum; }
// What are we currently rendering? Returns a combination of DF_ flags.
virtual int GetDrawFlags() { return ( m_pActiveRenderer ) ? m_pActiveRenderer->GetDrawFlags() : 0; }
CBase3dView * GetActiveRenderer() { return m_pActiveRenderer; }
CBase3dView * SetActiveRenderer( CBase3dView *pActiveRenderer ) { CBase3dView *pPrevious = m_pActiveRenderer; m_pActiveRenderer = pActiveRenderer; return pPrevious; }
void FreezeFrame( float flFreezeTime );
void SetWaterOverlayMaterial( IMaterial *pMaterial )
{
m_UnderWaterOverlayMaterial.Init( pMaterial );
}
private:
int m_BuildWorldListsNumber;
// General draw methods
// baseDrawFlags is a combination of DF_ defines. DF_MONITOR is passed into here while drawing a monitor.
void ViewDrawScene( bool bDrew3dSkybox, SkyboxVisibility_t nSkyboxVisible, const CViewSetup &view, int nClearFlags, view_id_t viewID, bool bDrawViewModel = false, int baseDrawFlags = 0, ViewCustomVisibility_t *pCustomVisibility = NULL );
void DrawMonitors( const CViewSetup &cameraView );
void DrawScope(void/*const CViewSetup &cameraView*/);//OverCharged
void DrawScopeFalse(const CViewSetup &cameraView);//OverCharged
bool DrawOneMonitor( ITexture *pRenderTarget, int cameraNum, C_PointCamera *pCameraEnt, const CViewSetup &cameraView, C_BasePlayer *localPlayer,
int x, int y, int width, int height );
#ifdef MAPBASE
bool DrawFakeWorldPortal( ITexture *pRenderTarget, C_FuncFakeWorldPortal *pCameraEnt, const CViewSetup &cameraView, C_BasePlayer *localPlayer,
int x, int y, int width, int height,
const CViewSetup &mainView, cplane_t &ourPlane );
#endif
// Drawing primitives
bool ShouldDrawViewModel( bool drawViewmodel );
void DrawViewModels( const CViewSetup &view, bool drawViewmodel );
void PerformScreenSpaceEffects( int x, int y, int w, int h );
// Overlays
void SetScreenOverlayMaterial( IMaterial *pMaterial );
IMaterial *GetScreenOverlayMaterial( );
void PerformScreenOverlay( int x, int y, int w, int h );
void DrawUnderwaterOverlay( void );
// Water-related methods
void DrawWorldAndEntities( bool drawSkybox, const CViewSetup &view, int nClearFlags, ViewCustomVisibility_t *pCustomVisibility = NULL );
#ifdef MAPBASE
virtual void ViewDrawScene_Intro( const CViewSetup &view, int nClearFlags, const IntroData_t &introData, bool bDrew3dSkybox = false, SkyboxVisibility_t nSkyboxVisible = SKYBOX_NOT_VISIBLE, bool bDrawViewModel = false, ViewCustomVisibility_t *pCustomVisibility = NULL );
#else
virtual void ViewDrawScene_Intro( const CViewSetup &view, int nClearFlags, const IntroData_t &introData );
#endif
#ifdef PORTAL
// Intended for use in the middle of another ViewDrawScene call, this allows stencils to be drawn after opaques but before translucents are drawn in the main view.
void ViewDrawScene_PortalStencil( const CViewSetup &view, ViewCustomVisibility_t *pCustomVisibility );
void Draw3dSkyboxworld_Portal( const CViewSetup &view, int &nClearFlags, bool &bDrew3dSkybox, SkyboxVisibility_t &nSkyboxVisible, ITexture *pRenderTarget = NULL );
#endif // PORTAL
// Determines what kind of water we're going to use
void DetermineWaterRenderInfo( const VisibleFogVolumeInfo_t &fogVolumeInfo, WaterRenderInfo_t &info );
bool UpdateRefractIfNeededByList( CUtlVector< IClientRenderable * > &list );
void DrawRenderablesInList( CUtlVector< IClientRenderable * > &list, int flags = 0 );
// Sets up, cleans up the main 3D view
void SetupMain3DView( const CViewSetup &view, int &nClearFlags );
void CleanupMain3DView( const CViewSetup &view );
// This stores the current view
CViewSetup m_CurrentView;
// VIS Overrides
// Set to true to turn off client side vis ( !!!! rendering will be slow since everything will draw )
bool m_bForceNoVis;
// Some cvars needed by this system
const ConVar *m_pDrawEntities;
const ConVar *m_pDrawBrushModels;
// Some materials used...
CMaterialReference m_TranslucentSingleColor;
CMaterialReference m_ModulateSingleColor;
CMaterialReference m_ScreenOverlayMaterial;
CMaterialReference m_UnderWaterOverlayMaterial;
Vector m_vecLastFacing;
float m_flCheapWaterStartDistance;
float m_flCheapWaterEndDistance;
CViewSetup m_OverlayViewSetup;
int m_OverlayClearFlags;
int m_OverlayDrawFlags;
bool m_bDrawOverlay;
int m_BaseDrawFlags; // Set in ViewDrawScene and OR'd into m_DrawFlags as it goes.
C_BaseEntity *m_pCurrentlyDrawingEntity;
#if defined( CSTRIKE_DLL )
float m_flLastFOV;
#endif
#ifdef PORTAL
friend class CPortalRender; //portal drawing needs muck with views in weird ways
friend class CPortalRenderable;
#endif
int m_BuildRenderableListsNumber;
friend class CBase3dView;
Frustum m_Frustum;
CBase3dView *m_pActiveRenderer;
CSimpleRenderExecutor m_SimpleExecutor;
bool m_rbTakeFreezeFrame[ STEREO_EYE_MAX ];
float m_flFreezeFrameUntil;
#if defined( REPLAY_ENABLED )
CReplayScreenshotTaker *m_pReplayScreenshotTaker;
#endif
};
#endif // VIEWRENDER_H

789
game/client/vis_tester.cpp Normal file
View File

@@ -0,0 +1,789 @@
#include "cbase.h"
#include "filesystem.h"
#include "lumpfiles.h"
#include "tier1/memstack.h"
#include "lzmaDecoder.h"
#include "tier0/memdbgon.h"
#pragma region CORE
static CMemoryStack g_MemStack;
template <typename T> static T* Hunk_Alloc(size_t s, bool clear = true)
{
return static_cast<T*>(g_MemStack.Alloc(s, clear));
}
static void CM_LoadMap(const char* name);
static void CM_FreeMap();
static class CVisMemoryManager : public CAutoGameSystem
{
public:
CVisMemoryManager() : CAutoGameSystem("visMemoryManager") {}
bool Init() OVERRIDE
{
const int nMaxBytes = 48 * 1024 * 1024;
const int nMinCommitBytes = 0x8000;
const int nInitialCommit = 0x280000;
g_MemStack.Init(nMaxBytes, nMinCommitBytes, nInitialCommit);
return true;
}
void Shutdown() OVERRIDE
{
g_MemStack.Term();
}
void LevelInitPreEntity() OVERRIDE
{
CM_LoadMap(VarArgs("maps/%s.bsp", MapName()));
}
void LevelShutdownPreEntity() OVERRIDE
{
CM_FreeMap();
g_MemStack.FreeAll(false);
}
} memManager;
template <class T>
class CRangeValidatedArray
{
public:
void Attach(int nCount, T* pData)
{
m_pArray = pData;
#ifdef _DEBUG
m_nCount = nCount;
#endif
}
void Detach()
{
m_pArray = NULL;
#ifdef _DEBUG
m_nCount = 0;
#endif
}
T &operator[](int i)
{
Assert((i >= 0) && (i < m_nCount));
return m_pArray[i];
}
const T &operator[](int i) const
{
Assert((i >= 0) && (i < m_nCount));
return m_pArray[i];
}
T* Base()
{
return m_pArray;
}
private:
T* m_pArray;
#ifdef _DEBUG
int m_nCount;
#endif
};
struct cnode_t
{
cplane_t* plane;
int children[2]; // negative numbers are leafs
};
struct cleaf_t
{
int contents;
short cluster;
short area : 9;
short flags : 7;
unsigned short firstleafbrush;
unsigned short numleafbrushes;
unsigned short dispListStart;
unsigned short dispCount;
};
class CCollisionBSPData
{
public:
// This is sort of a hack, but it was a little too painful to do this any other way
// The goal of this dude is to allow us to override the tree with some
// other tree (or a subtree)
cnode_t* map_rootnode;
int numplanes;
CRangeValidatedArray<cplane_t> map_planes;
int numnodes;
CRangeValidatedArray<cnode_t> map_nodes;
int numleafs; // allow leaf funcs to be called without a map
CRangeValidatedArray<cleaf_t> map_leafs;
int emptyleaf;
// this points to the whole block of memory for vis data, but it is used to
// reference the header at the top of the block.
int numvisibility;
dvis_t* map_vis;
int numclusters;
};
class CMapLoadHelper
{
public:
CMapLoadHelper(int lumpToLoad)
{
if (s_MapFileHandle == FILESYSTEM_INVALID_HANDLE)
{
Warning("Can't load map from invalid handle!!!");
return;
}
if (lumpToLoad < 0 || lumpToLoad >= HEADER_LUMPS)
{
Warning("Can't load lump %i, range is 0 to %i!!!", lumpToLoad, HEADER_LUMPS - 1);
}
m_pData = NULL;
m_pRawData = NULL;
// Load raw lump from disk
lump_t* lump = &s_MapHeader.lumps[lumpToLoad];
m_nLumpSize = lump->filelen;
m_nLumpUncompressedSize = lump->uncompressedSize;
m_nLumpOffset = lump->fileofs;
m_nLumpVersion = lump->version;
if (!m_nLumpSize)
return; // this lump has no data
unsigned nOffsetAlign, nSizeAlign, nBufferAlign;
filesystem->GetOptimalIOConstraints(s_MapFileHandle, &nOffsetAlign, &nSizeAlign, &nBufferAlign);
const bool bTryOptimal = (m_nLumpOffset % 4 == 0); // Don't return badly aligned data
unsigned int alignedOffset = m_nLumpOffset;
unsigned int alignedBytesToRead = ((m_nLumpSize) ? m_nLumpSize : 1);
if (bTryOptimal)
{
alignedOffset = AlignValue((alignedOffset - nOffsetAlign) + 1, nOffsetAlign);
alignedBytesToRead = AlignValue((m_nLumpOffset - alignedOffset) + alignedBytesToRead, nSizeAlign);
}
m_pRawData = static_cast<byte*>(filesystem->AllocOptimalReadBuffer(s_MapFileHandle, alignedBytesToRead, alignedOffset));
if (!m_pRawData)
{
Warning("Can't load lump %i, allocation of %i bytes failed!!!", lumpToLoad, m_nLumpSize + 1);
}
filesystem->Seek(s_MapFileHandle, alignedOffset, FILESYSTEM_SEEK_HEAD);
filesystem->ReadEx(m_pRawData, alignedBytesToRead, alignedBytesToRead, s_MapFileHandle);
if (m_nLumpUncompressedSize)
{
if (CLZMA::IsCompressed(m_pRawData) && m_nLumpUncompressedSize == static_cast<int>(CLZMA::GetActualSize(m_pRawData)))
{
m_pData = static_cast<byte*>(MemAlloc_AllocAligned(m_nLumpUncompressedSize, 4));
const int outSize = CLZMA::Uncompress(m_pRawData, m_pData);
if (outSize != m_nLumpUncompressedSize)
{
Warning("Decompressed size differs from header, BSP may be corrupt\n");
}
}
else
{
Assert(0);
Warning("Unsupported BSP: Unrecognized compressed lump\n");
}
}
else
{
m_pData = m_pRawData + (m_nLumpOffset - alignedOffset);
}
}
~CMapLoadHelper()
{
if (m_nLumpUncompressedSize)
{
MemAlloc_FreeAligned(m_pData);
}
if (m_pRawData)
{
filesystem->FreeOptimalReadBuffer(m_pRawData);
}
}
byte* LumpBase() const
{
return m_pData;
}
int LumpSize() const
{
return m_nLumpUncompressedSize ? m_nLumpUncompressedSize : m_nLumpSize;
}
int LumpOffset() const
{
return m_nLumpOffset;
}
int LumpVersion() const
{
return m_nLumpVersion;
}
// Global setup/shutdown
static void Init(const char* loadname)
{
if (++s_nMapLoadRecursion > 1)
{
return;
}
s_MapFileHandle = FILESYSTEM_INVALID_HANDLE;
V_memset(&s_MapHeader, 0, sizeof(s_MapHeader));
V_strcpy_safe(s_szLoadName, loadname);
s_MapFileHandle = filesystem->OpenEx(loadname, "rb");
if (s_MapFileHandle == FILESYSTEM_INVALID_HANDLE)
{
Warning("CMapLoadHelper::Init, unable to open %s\n", loadname);
return;
}
filesystem->Read(&s_MapHeader, sizeof(dheader_t), s_MapFileHandle);
if (s_MapHeader.ident != IDBSPHEADER)
{
filesystem->Close(s_MapFileHandle);
s_MapFileHandle = FILESYSTEM_INVALID_HANDLE;
Warning("CMapLoadHelper::Init, map %s has wrong identifier\n", loadname);
return;
}
if (s_MapHeader.version < MINBSPVERSION || s_MapHeader.version > BSPVERSION)
{
filesystem->Close(s_MapFileHandle);
s_MapFileHandle = FILESYSTEM_INVALID_HANDLE;
Warning("CMapLoadHelper::Init, map %s has wrong version (%i when expecting %i)\n", loadname,
s_MapHeader.version, BSPVERSION);
}
}
static void Shutdown()
{
if (--s_nMapLoadRecursion > 0)
{
return;
}
if (s_MapFileHandle != FILESYSTEM_INVALID_HANDLE)
{
filesystem->Close(s_MapFileHandle);
s_MapFileHandle = FILESYSTEM_INVALID_HANDLE;
}
s_szLoadName[0] = 0;
V_memset(&s_MapHeader, 0, sizeof(s_MapHeader));
}
private:
int m_nLumpSize;
int m_nLumpUncompressedSize;
int m_nLumpOffset;
int m_nLumpVersion;
byte* m_pRawData;
byte* m_pData;
static dheader_t s_MapHeader;
static FileHandle_t s_MapFileHandle;
static char s_szLoadName[64];
static int s_nMapLoadRecursion;
};
dheader_t CMapLoadHelper::s_MapHeader;
FileHandle_t CMapLoadHelper::s_MapFileHandle = FILESYSTEM_INVALID_HANDLE;
char CMapLoadHelper::s_szLoadName[64];
int CMapLoadHelper::s_nMapLoadRecursion = 0;
static void CollisionBSPData_LoadLeafs(CCollisionBSPData*);
static void CollisionBSPData_LoadVisibility(CCollisionBSPData*);
static void CollisionBSPData_LoadNodes(CCollisionBSPData*);
static void CollisionBSPData_LoadPlanes(CCollisionBSPData*);
static void CollisionBSPData_Load(CCollisionBSPData* pBSPData)
{
COM_TimestampedLog(" CollisionBSPData_LoadPlanes");
CollisionBSPData_LoadPlanes(pBSPData);
COM_TimestampedLog(" CollisionBSPData_LoadNodes");
CollisionBSPData_LoadNodes(pBSPData);
COM_TimestampedLog(" CollisionBSPData_LoadLeafs");
CollisionBSPData_LoadLeafs(pBSPData);
COM_TimestampedLog(" CollisionBSPData_LoadVisibility");
CollisionBSPData_LoadVisibility(pBSPData);
}
static void CollisionBSPData_LoadLeafs_Version_0(CCollisionBSPData* pBSPData, CMapLoadHelper &lh)
{
dleaf_version_0_t* in = reinterpret_cast<dleaf_version_0_t*>(lh.LumpBase());
if (lh.LumpSize() % sizeof(dleaf_version_0_t))
Warning("CollisionBSPData_LoadLeafs: funny lump size");
const int count = lh.LumpSize() / sizeof(dleaf_version_0_t);
if (count < 1)
Warning("Map with no leafs");
// need to save space for box planes
if (count > MAX_MAP_PLANES)
Warning("Map has too many planes");
// Need an extra one for the emptyleaf below
const int nSize = (count + 1) * sizeof(cleaf_t);
pBSPData->map_leafs.Attach(count + 1, Hunk_Alloc<cleaf_t>(nSize));
pBSPData->numleafs = count;
pBSPData->numclusters = 0;
for (int i = 0; i < count; i++, in++)
{
cleaf_t *out = &pBSPData->map_leafs[i];
out->contents = in->contents;
out->cluster = in->cluster;
out->area = in->area;
out->flags = in->flags;
out->firstleafbrush = in->firstleafbrush;
out->numleafbrushes = in->numleafbrushes;
out->dispCount = 0;
if (out->cluster >= pBSPData->numclusters)
{
pBSPData->numclusters = out->cluster + 1;
}
}
if (pBSPData->map_leafs[0].contents != CONTENTS_SOLID)
Warning("Map leaf 0 is not CONTENTS_SOLID");
pBSPData->emptyleaf = pBSPData->numleafs;
V_memset(&pBSPData->map_leafs[pBSPData->emptyleaf], 0, sizeof(pBSPData->map_leafs[pBSPData->emptyleaf]));
pBSPData->numleafs++;
}
static void CollisionBSPData_LoadLeafs_Version_1(CCollisionBSPData* pBSPData, CMapLoadHelper &lh)
{
dleaf_t* in = reinterpret_cast<dleaf_t*>(lh.LumpBase());
if (lh.LumpSize() % sizeof(dleaf_t))
Warning("CollisionBSPData_LoadLeafs: funny lump size");
const int count = lh.LumpSize() / sizeof(dleaf_t);
if (count < 1)
Warning("Map with no leafs");
// need to save space for box planes
if (count > MAX_MAP_PLANES)
Warning("Map has too many planes");
// Need an extra one for the emptyleaf below
const int nSize = (count + 1) * sizeof(cleaf_t);
pBSPData->map_leafs.Attach(count + 1, Hunk_Alloc<cleaf_t>(nSize));
pBSPData->numleafs = count;
pBSPData->numclusters = 0;
for (int i = 0; i < count; i++, in++)
{
cleaf_t *out = &pBSPData->map_leafs[i];
out->contents = in->contents;
out->cluster = in->cluster;
out->area = in->area;
out->flags = in->flags;
out->firstleafbrush = in->firstleafbrush;
out->numleafbrushes = in->numleafbrushes;
out->dispCount = 0;
if (out->cluster >= pBSPData->numclusters)
{
pBSPData->numclusters = out->cluster + 1;
}
}
if (pBSPData->map_leafs[0].contents != CONTENTS_SOLID)
Warning("Map leaf 0 is not CONTENTS_SOLID");
pBSPData->emptyleaf = pBSPData->numleafs;
V_memset(&pBSPData->map_leafs[pBSPData->emptyleaf], 0, sizeof(pBSPData->map_leafs[pBSPData->emptyleaf]));
pBSPData->numleafs++;
}
static void CollisionBSPData_LoadLeafs(CCollisionBSPData* pBSPData)
{
CMapLoadHelper lh(LUMP_LEAFS);
switch (lh.LumpVersion())
{
case 0:
CollisionBSPData_LoadLeafs_Version_0(pBSPData, lh);
break;
case 1:
CollisionBSPData_LoadLeafs_Version_1(pBSPData, lh);
break;
default:
Assert(0);
Warning("Unknown LUMP_LEAFS version\n");
break;
}
}
static void CollisionBSPData_LoadVisibility(CCollisionBSPData* pBSPData)
{
CMapLoadHelper lh(LUMP_VISIBILITY);
pBSPData->numvisibility = lh.LumpSize();
if (lh.LumpSize() > MAX_MAP_VISIBILITY)
Warning("Map has too large visibility lump");
const int visDataSize = lh.LumpSize();
if (visDataSize == 0)
{
pBSPData->map_vis = NULL;
}
else
{
pBSPData->map_vis = Hunk_Alloc<dvis_t>(visDataSize, false);
V_memcpy(pBSPData->map_vis, lh.LumpBase(), visDataSize);
}
}
static void CollisionBSPData_LoadNodes(CCollisionBSPData* pBSPData)
{
CMapLoadHelper lh(LUMP_NODES);
dnode_t* in = reinterpret_cast<dnode_t*>(lh.LumpBase());
if (lh.LumpSize() % sizeof(dnode_t))
Warning("CollisionBSPData_LoadNodes: funny lump size");
const int count = lh.LumpSize() / sizeof(dnode_t);
if (count < 1)
Warning("Map has no nodes");
if (count > MAX_MAP_NODES)
Warning("Map has too many nodes");
// 6 extra for box hull
const int nSize = (count + 6) * sizeof(cnode_t);
pBSPData->map_nodes.Attach(count + 6, Hunk_Alloc<cnode_t>(nSize));
pBSPData->numnodes = count;
pBSPData->map_rootnode = pBSPData->map_nodes.Base();
for (int i = 0; i < count; i++, in++)
{
cnode_t *out = &pBSPData->map_nodes[i];
out->plane = &pBSPData->map_planes[in->planenum];
for (int j = 0; j < 2; j++)
{
out->children[j] = in->children[j];
}
}
}
static void CollisionBSPData_LoadPlanes(CCollisionBSPData* pBSPData)
{
CMapLoadHelper lh(LUMP_PLANES);
dplane_t* in = reinterpret_cast<dplane_t*>(lh.LumpBase());
if (lh.LumpSize() % sizeof(dplane_t))
Warning("CollisionBSPData_LoadPlanes: funny lump size");
const int count = lh.LumpSize() / sizeof(dplane_t);
if (count < 1)
Warning("Map with no planes");
// need to save space for box planes
if (count > MAX_MAP_PLANES)
Warning("Map has too many planes");
const int nSize = count * sizeof(cplane_t);
pBSPData->map_planes.Attach(count, Hunk_Alloc<cplane_t>(nSize));
pBSPData->numplanes = count;
for (int i = 0; i < count; i++, in++)
{
cplane_t* out = &pBSPData->map_planes[i];
int bits = 0;
for (int j = 0; j < 3; j++)
{
out->normal[j] = in->normal[j];
if (out->normal[j] < 0)
{
bits |= 1 << j;
}
}
out->dist = in->dist;
out->type = in->type;
out->signbits = bits;
}
}
static void CollisionBSPData_Init(CCollisionBSPData* pBSPData)
{
pBSPData->numleafs = 1;
pBSPData->map_vis = NULL;
pBSPData->numclusters = 1;
}
static CCollisionBSPData* GetCollisionBSPData()
{
static CCollisionBSPData data;
return &data;
}
static void CM_FreeMap()
{
// get the current collision bsp -- there is only one!
CCollisionBSPData* pBSPData = GetCollisionBSPData();
if (pBSPData->map_planes.Base())
{
pBSPData->map_planes.Detach();
}
if (pBSPData->map_leafs.Base())
{
pBSPData->map_leafs.Detach();
}
if (pBSPData->map_nodes.Base())
{
pBSPData->map_nodes.Detach();
}
if (pBSPData->map_vis)
{
pBSPData->map_vis = NULL;
}
pBSPData->numplanes = 0;
pBSPData->emptyleaf = 0;
pBSPData->numnodes = 0;
pBSPData->numleafs = 0;
pBSPData->numclusters = 0;
pBSPData->numvisibility = 0;
pBSPData->map_rootnode = NULL;
}
static void CM_LoadMap(const char* name)
{
// get the current bsp -- there is currently only one!
CCollisionBSPData* pBSPData = GetCollisionBSPData();
// initialize the collision bsp data
CollisionBSPData_Init(pBSPData);
if (!name || !name[0])
return;
// read in the collision model data
CMapLoadHelper::Init(name);
CollisionBSPData_Load(pBSPData);
CMapLoadHelper::Shutdown();
}
static int CM_NumClusters()
{
return GetCollisionBSPData()->numclusters;
}
static void CM_NullVis(CCollisionBSPData* pBSPData, byte* out)
{
int numClusterBytes = (pBSPData->numclusters + 7) >> 3;
byte* out_p = out;
while (numClusterBytes)
{
*out_p++ = 0xff;
numClusterBytes--;
}
}
static void CM_DecompressVis(CCollisionBSPData* pBSPData, int cluster, int visType, byte* out)
{
if (!pBSPData)
{
Assert(false); // Shouldn't ever happen.
}
if (cluster > pBSPData->numclusters || cluster < 0)
{
// This can happen if this is called while the level is loading. See Map_VisCurrentCluster.
CM_NullVis(pBSPData, out);
return;
}
// no vis info, so make all visible
if (!pBSPData->numvisibility || !pBSPData->map_vis)
{
CM_NullVis(pBSPData, out);
return;
}
byte* in = reinterpret_cast<byte*>(pBSPData->map_vis) + pBSPData->map_vis->bitofs[cluster][visType];
const int numClusterBytes = (pBSPData->numclusters + 7) >> 3;
byte* out_p = out;
// no vis info, so make all visible
if (!in)
{
CM_NullVis(pBSPData, out);
return;
}
do
{
if (*in)
{
*out_p++ = *in++;
continue;
}
int c = in[1];
in += 2;
if ((out_p - out) + c > numClusterBytes)
{
c = numClusterBytes - (out_p - out);
DevWarning("Vis decompression overrun\n");
}
while (c)
{
*out_p++ = 0;
c--;
}
} while (out_p - out < numClusterBytes);
}
static void CM_Vis(byte* dest, int destlen, int cluster, int visType)
{
// get the current collision bsp -- there is only one!
CCollisionBSPData* pBSPData = GetCollisionBSPData();
if (!dest || visType > 2 || visType < 0)
{
Warning("CM_Vis: error");
return;
}
if (cluster == -1)
{
int len = (pBSPData->numclusters + 7) >> 3;
if (len > destlen)
{
Warning("CM_Vis: buffer not big enough (%i but need %i)\n",
destlen, len);
}
V_memset(dest, 0, (pBSPData->numclusters + 7) >> 3);
}
else
{
CM_DecompressVis(pBSPData, cluster, visType, dest);
}
}
static int CM_LeafCluster(int leafnum)
{
const CCollisionBSPData* pBSPData = GetCollisionBSPData();
Assert(leafnum >= 0);
Assert(leafnum < pBSPData->numleafs);
return pBSPData->map_leafs[leafnum].cluster;
}
static int CM_PointLeafnum_r(CCollisionBSPData* pBSPData, const Vector& p, int num)
{
float d;
while (num >= 0)
{
cnode_t* node = pBSPData->map_rootnode + num;
cplane_t* plane = node->plane;
if (plane->type < 3)
d = p[plane->type] - plane->dist;
else
d = DotProduct(plane->normal, p) - plane->dist;
if (d < 0)
num = node->children[1];
else
num = node->children[0];
}
return -1 - num;
}
static int CM_PointLeafnum(const Vector& p)
{
// get the current collision bsp -- there is only one!
CCollisionBSPData* pBSPData = GetCollisionBSPData();
if (!pBSPData->numnodes)
return 0;
return CM_PointLeafnum_r(pBSPData, p, 0);
}
#pragma endregion
int GetClusterForOrigin(const Vector& org)
{
return CM_LeafCluster(CM_PointLeafnum(org));
}
int GetPVSForCluster(int clusterIndex, int outputpvslength, byte* outputpvs)
{
int length = (CM_NumClusters() + 7) >> 3;
if (outputpvs)
{
if (outputpvslength < length)
{
Warning("GetPVSForOrigin called with inusfficient sized pvs array, need %i bytes!", length);
return length;
}
CM_Vis(outputpvs, outputpvslength, clusterIndex, DVIS_PVS);
}
return length;
}
bool CheckOriginInPVS(const Vector& org, const byte* checkpvs, int checkpvssize)
{
const int clusterIndex = GetClusterForOrigin(org);
if (clusterIndex < 0)
return false;
const int offset = clusterIndex >> 3;
if (offset > checkpvssize)
{
Warning("CheckOriginInPVS: cluster would read past end of pvs data (%i:%i)\n",
offset, checkpvssize);
return false;
}
return (checkpvs[offset] & (1 << (clusterIndex & 7))) != 0;
}

123
game/client/voice_menu.cpp Normal file
View File

@@ -0,0 +1,123 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_baseplayer.h"
#include "menu.h"
#include "KeyValues.h"
#include "multiplay_gamerules.h"
static int g_ActiveVoiceMenu = 0;
void OpenVoiceMenu( int index )
{
// do not show the menu if the player is dead or is an observer
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer )
return;
if ( !pPlayer->IsAlive() || pPlayer->IsObserver() )
return;
CHudMenu *pMenu = (CHudMenu *) gHUD.FindElement( "CHudMenu" );
if ( !pMenu )
return;
// if they hit the key again, close the menu
if ( g_ActiveVoiceMenu == index )
{
if ( pMenu->IsMenuOpen() )
{
pMenu->HideMenu();
g_ActiveVoiceMenu = 0;
return;
}
}
if ( index > 0 && index < 9 )
{
KeyValues *pKV = new KeyValues( "MenuItems" );
CMultiplayRules *pRules = dynamic_cast< CMultiplayRules * >( GameRules() );
if ( pRules )
{
if ( !pRules->GetVoiceMenuLabels( index-1, pKV ) )
{
pKV->deleteThis();
return;
}
}
pMenu->ShowMenu_KeyValueItems( pKV );
pKV->deleteThis();
g_ActiveVoiceMenu = index;
}
else
{
g_ActiveVoiceMenu = 0;
}
}
static void OpenVoiceMenu_1( void )
{
OpenVoiceMenu( 1 );
}
static void OpenVoiceMenu_2( void )
{
OpenVoiceMenu( 2 );
}
static void OpenVoiceMenu_3( void )
{
OpenVoiceMenu( 3 );
}
ConCommand voice_menu_1( "voice_menu_1", OpenVoiceMenu_1, "Opens voice menu 1" );
ConCommand voice_menu_2( "voice_menu_2", OpenVoiceMenu_2, "Opens voice menu 2" );
ConCommand voice_menu_3( "voice_menu_3", OpenVoiceMenu_3, "Opens voice menu 3" );
CON_COMMAND( menuselect, "menuselect" )
{
if ( args.ArgC() < 2 )
return;
if( g_ActiveVoiceMenu == 0 )
{
// if we didn't have a menu open, maybe a plugin did. send it on to the server.
const char *cmd = VarArgs( "menuselect %s", args[1] );
engine->ServerCmd( cmd );
return;
}
int iSelection = atoi( args[ 1 ] );
switch( g_ActiveVoiceMenu )
{
case 1:
case 2:
case 3:
{
char cmd[128];
Q_snprintf( cmd, sizeof(cmd), "voicemenu %d %d", g_ActiveVoiceMenu - 1, iSelection - 1 );
engine->ServerCmd( cmd );
}
break;
default:
{
// if we didn't have a menu open, maybe a plugin did. send it on to the server.
const char *cmd = VarArgs( "menuselect %d", iSelection );
engine->ServerCmd( cmd );
}
break;
}
// reset menu
g_ActiveVoiceMenu = 0;
}

View File

@@ -0,0 +1,95 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Screen warp overlay
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "view.h"
#include "c_sun.h"
#include "particles_simple.h"
#include "clienteffectprecachesystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectWarp )
CLIENTEFFECT_MATERIAL( "sun/overlay" )
CLIENTEFFECT_REGISTER_END()
//-----------------------------------------------------------------------------
// Purpose: Special draw for the warped overlay
//-----------------------------------------------------------------------------
void CWarpOverlay::Draw( bool bCacheFullSceneState )
{
// Get the vector to the sun.
Vector vToGlow;
if( m_bDirectional )
vToGlow = m_vDirection;
else
vToGlow = m_vPos - CurrentViewOrigin();
VectorNormalize( vToGlow );
float flDot = vToGlow.Dot( CurrentViewForward() );
if( flDot <= g_flOverlayRange )
return;
UpdateGlowObstruction( vToGlow, bCacheFullSceneState );
if( m_flGlowObstructionScale == 0 )
return;
CMatRenderContextPtr pRenderContext( materials );
//FIXME: Allow multiple?
for( int iSprite=0; iSprite < m_nSprites; iSprite++ )
{
CGlowSprite *pSprite = &m_Sprites[iSprite];
// Figure out the color and size to draw it.
float flHorzSize, flVertSize;
Vector vColor;
CalcSpriteColorAndSize( flDot, pSprite, &flHorzSize, &flVertSize, &vColor );
// Setup the basis to draw the sprite.
Vector vBasePt, vUp, vRight;
CalcBasis( vToGlow, flHorzSize, flVertSize, vBasePt, vUp, vRight );
// Draw the sprite.
IMaterial *pMaterial = materials->FindMaterial( "sun/overlay", TEXTURE_GROUP_CLIENT_EFFECTS );
IMesh *pMesh = pRenderContext->GetDynamicMesh( false, 0, 0, pMaterial );
CMeshBuilder builder;
builder.Begin( pMesh, MATERIAL_QUADS, 1 );
Vector vPt;
vPt = vBasePt - vRight + vUp;
builder.Position3fv( vPt.Base() );
builder.Color4f( VectorExpand(vColor), 1 );
builder.TexCoord2f( 0, 0, 1 );
builder.AdvanceVertex();
vPt = vBasePt + vRight + vUp;
builder.Position3fv( vPt.Base() );
builder.Color4f( VectorExpand(vColor), 1 );
builder.TexCoord2f( 0, 1, 1 );
builder.AdvanceVertex();
vPt = vBasePt + vRight - vUp;
builder.Position3fv( vPt.Base() );
builder.Color4f( VectorExpand(vColor), 1 );
builder.TexCoord2f( 0, 1, 0 );
builder.AdvanceVertex();
vPt = vBasePt - vRight - vUp;
builder.Position3fv( vPt.Base() );
builder.Color4f( VectorExpand(vColor), 1 );
builder.TexCoord2f( 0, 0, 0 );
builder.AdvanceVertex();
builder.End( false, true );
}
}

View File

@@ -0,0 +1,712 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Weapon selection handling
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "weapon_selection.h"
#include "hud_macros.h"
#include "history_resource.h"
#include "menu.h"
#include "in_buttons.h"
#include <KeyValues.h>
#include "filesystem.h"
#include "iinput.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define HISTORY_DRAW_TIME "5"
ConVar hud_drawhistory_time( "hud_drawhistory_time", HISTORY_DRAW_TIME, 0 );
ConVar hud_fastswitch( "hud_fastswitch", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBOX );
//-----------------------------------------------------------------------------
// Purpose: Weapon Selection commands
//-----------------------------------------------------------------------------
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot1, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot2, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot3, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot4, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot5, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot6, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot7, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot8, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot9, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot0, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Slot10, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, Close, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, NextWeapon, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, PrevWeapon, "CHudWeaponSelection");
DECLARE_HUD_COMMAND_NAME(CBaseHudWeaponSelection, LastWeapon, "CHudWeaponSelection");
HOOK_COMMAND( slot1, Slot1 );
HOOK_COMMAND( slot2, Slot2 );
HOOK_COMMAND( slot3, Slot3 );
HOOK_COMMAND( slot4, Slot4 );
HOOK_COMMAND( slot5, Slot5 );
HOOK_COMMAND( slot6, Slot6 );
HOOK_COMMAND( slot7, Slot7 );
HOOK_COMMAND( slot8, Slot8 );
HOOK_COMMAND( slot9, Slot9 );
HOOK_COMMAND( slot0, Slot0 );
HOOK_COMMAND( slot10, Slot10 );
HOOK_COMMAND( cancelselect, Close );
HOOK_COMMAND( invnext, NextWeapon );
HOOK_COMMAND( invprev, PrevWeapon );
HOOK_COMMAND( lastinv, LastWeapon );
// instance info
CBaseHudWeaponSelection *CBaseHudWeaponSelection::s_pInstance = NULL;
CBaseHudWeaponSelection *CBaseHudWeaponSelection::GetInstance()
{
return s_pInstance;
}
CBaseHudWeaponSelection *GetHudWeaponSelection()
{
return CBaseHudWeaponSelection::GetInstance();
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CBaseHudWeaponSelection::CBaseHudWeaponSelection( const char *pElementName ) : CHudElement( pElementName )
{
s_pInstance = this;
CheatsWasEnabled = false;
SetHiddenBits( HIDEHUD_WEAPONSELECTION | HIDEHUD_NEEDSUIT | HIDEHUD_PLAYERDEAD | HIDEHUD_INVEHICLE );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::Init(void)
{
Reset();
// Initialise the weapons resource
gWR.Init();
m_flSelectionTime = gpGlobals->curtime;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::Reset(void)
{
gWR.Reset();
// Start hidden
m_bSelectionVisible = false;
m_flSelectionTime = gpGlobals->curtime;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::UpdateSelectionTime( void )
{
m_flSelectionTime = gpGlobals->curtime;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::VidInit(void)
{
// If we've already loaded weapons, let's get new sprites
gWR.LoadAllWeaponSprites();
// set spacing of pickup history
CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource );
if( pHudHR )
{
pHudHR->SetHistoryGap( 21 );
}
Reset();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::OnThink( void )
{
// Don't allow weapon selection if we're frozen in place
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( pPlayer->GetFlags() & FL_FROZEN || pPlayer->IsPlayerDead() )
{
if ( IsInSelectionMode() )
{
CancelWeaponSelection();
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Think used for selection of weapon menu item.
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::ProcessInput()
{
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( !pPlayer )
return;
// Check to see if the player is in VGUI mode...
if ( pPlayer->IsInVGuiInputMode() && !pPlayer->IsInViewModelVGuiInputMode() )
{
// If so, close weapon selection when they press fire
if ( gHUD.m_iKeyBits & IN_ATTACK )
{
if ( HUDTYPE_PLUS != hud_fastswitch.GetInt() )
{
// Swallow the button
gHUD.m_iKeyBits &= ~IN_ATTACK;
input->ClearInputButton( IN_ATTACK );
}
engine->ClientCmd( "cancelselect\n" );
}
return;
}
// Has the player selected a weapon?
if ( gHUD.m_iKeyBits & (IN_ATTACK | IN_ATTACK2) )
{
if ( IsWeaponSelectable() )
{
#ifndef TF_CLIENT_DLL
if ( HUDTYPE_PLUS != hud_fastswitch.GetInt() )
#endif
{
// Swallow the button
gHUD.m_iKeyBits &= ~(IN_ATTACK | IN_ATTACK2);
input->ClearInputButton( IN_ATTACK );
input->ClearInputButton( IN_ATTACK2 );
}
// select weapon
SelectWeapon();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseHudWeaponSelection::IsInSelectionMode()
{
return m_bSelectionVisible;
}
//ConVar oc_player_weap_selection_time_threshold("oc_player_weap_selection_time_threshold", "0.9", FCVAR_ARCHIVE, "Selection menu time threshold");
void CBaseHudWeaponSelection::EnableSlowMo(void)
{
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if (!pPlayer) return;
if (pPlayer->GetSlowMoIsEnabled()) return;
if (pPlayer->IsSuitEquipped() && pPlayer->WeaponCount())
{
ConVarRef sv_cheats("sv_cheats");
if (!sv_cheats.GetInt())
{
CheatsWasEnabled = true;
sv_cheats.SetValue(1);
}
float threshold = 1 - 0.8f;//oc_player_weap_selection_time_threshold.GetFloat();
threshold = Clamp(threshold, 0.1f, 0.95f);
ConVarRef host_timescale("host_timescale");
host_timescale.SetValue(threshold);
ConVarRef oc_player_state_inselection("oc_player_state_inselection");
oc_player_state_inselection.SetValue(1);
//engine->ServerCmd("Server_OpenSelection\n", false);
}
}
void CBaseHudWeaponSelection::DisableSlowMo(void)
{
ConVarRef host_timescale("host_timescale");
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if (!pPlayer)
{
host_timescale.SetValue(1);
ConVarRef oc_player_state_inselection("oc_player_state_inselection");
oc_player_state_inselection.SetValue(0);
return;
}
if (pPlayer->GetSlowMoIsEnabled()) return;
if (pPlayer->IsInSelectionSlowMo() || host_timescale.GetFloat() < 1.f)
{
ConVarRef sv_cheats("sv_cheats");
if (!sv_cheats.GetInt() && CheatsWasEnabled)
{
sv_cheats.SetValue(1);
}
host_timescale.SetValue(1);
ConVarRef oc_player_state_inselection("oc_player_state_inselection");
oc_player_state_inselection.SetValue(0);
if (CheatsWasEnabled)
{
CheatsWasEnabled = false;
sv_cheats.SetValue(0);
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::OpenSelection( void )
{
m_bSelectionVisible = true;
if (cvar->FindVar("oc_player_weap_selection_enable_fade")->GetBool())
EnableSlowMo();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::HideSelection( void )
{
m_bSelectionVisible = false;
DisableSlowMo();
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether a weapon can be selected in the HUD, based on hud type
//-----------------------------------------------------------------------------
bool CBaseHudWeaponSelection::CanBeSelectedInHUD( C_BaseCombatWeapon *pWeapon )
{
// Xbox: In plus type, weapons without ammo can still be selected in the HUD
if( HUDTYPE_PLUS == hud_fastswitch.GetInt() )
{
return pWeapon->VisibleInWeaponSelection();
}
if ( !pWeapon->VisibleInWeaponSelection() )
{
return false;
}
// All other current hud types
return pWeapon->CanBeSelected();
}
//-----------------------------------------------------------------------------
// Purpose: handles keyboard input
//-----------------------------------------------------------------------------
int CBaseHudWeaponSelection::KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
{
if (IsInSelectionMode() && pszCurrentBinding && !stricmp(pszCurrentBinding, "cancelselect"))
{
HideSelection();
// returning 0 indicates, we've handled it, no more action needs to be taken
return 0;
}
if ( down >= 1 && keynum >= KEY_1 && keynum <= KEY_9 )
{
if ( HandleHudMenuInput( keynum - KEY_0 ) )
return 0;
}
// let someone else handle it
return 1;
}
//-----------------------------------------------------------------------------
// Purpose: called when a weapon has been picked up
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::OnWeaponPickup( C_BaseCombatWeapon *pWeapon )
{
// add to pickup history
CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource );
if ( pHudHR )
{
pHudHR->AddToHistory( pWeapon );
}
}
//------------------------------------------------------------------------
// Command Handlers
//------------------------------------------------------------------------
void CBaseHudWeaponSelection::UserCmd_Slot1(void)
{
if( HUDTYPE_CAROUSEL == hud_fastswitch.GetInt() )
{
UserCmd_LastWeapon();
}
else
{
SelectSlot( 1 );
}
}
void CBaseHudWeaponSelection::UserCmd_Slot2(void)
{
if( HUDTYPE_CAROUSEL == hud_fastswitch.GetInt() )
{
UserCmd_NextWeapon();
}
else
{
SelectSlot( 2 );
}
}
void CBaseHudWeaponSelection::UserCmd_Slot3(void)
{
if( HUDTYPE_CAROUSEL == hud_fastswitch.GetInt() )
{
engine->ClientCmd( "phys_swap" );
}
else
{
SelectSlot( 3 );
}
}
void CBaseHudWeaponSelection::UserCmd_Slot4(void)
{
if( HUDTYPE_CAROUSEL == hud_fastswitch.GetInt() )
{
UserCmd_PrevWeapon();
}
else
{
SelectSlot( 4 );
}
}
void CBaseHudWeaponSelection::UserCmd_Slot5(void)
{
SelectSlot( 5 );
}
void CBaseHudWeaponSelection::UserCmd_Slot6(void)
{
SelectSlot( 6 );
}
void CBaseHudWeaponSelection::UserCmd_Slot7(void)
{
SelectSlot( 7 );
}
void CBaseHudWeaponSelection::UserCmd_Slot8(void)
{
SelectSlot( 8 );
}
void CBaseHudWeaponSelection::UserCmd_Slot9(void)
{
SelectSlot( 9 );
}
void CBaseHudWeaponSelection::UserCmd_Slot0(void)
{
SelectSlot( 0 );
}
void CBaseHudWeaponSelection::UserCmd_Slot10(void)
{
SelectSlot( 10 );
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the CHudMenu should take slot1, etc commands
//-----------------------------------------------------------------------------
bool CBaseHudWeaponSelection::IsHudMenuTakingInput()
{
CHudMenu *pHudMenu = GET_HUDELEMENT( CHudMenu );
return ( pHudMenu && pHudMenu->IsMenuOpen() );
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the CHudMenu handles the slot command
//-----------------------------------------------------------------------------
bool CBaseHudWeaponSelection::HandleHudMenuInput( int iSlot )
{
CHudMenu *pHudMenu = GET_HUDELEMENT( CHudMenu );
if ( !pHudMenu || !pHudMenu->IsMenuOpen() )
return false;
pHudMenu->SelectMenuItem( iSlot );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the weapon selection hud should be hidden because
// the CHudMenu is open
//-----------------------------------------------------------------------------
bool CBaseHudWeaponSelection::IsHudMenuPreventingWeaponSelection()
{
// Don't allow weapon selection if we're frozen in place
C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
if ( pPlayer->GetFlags() & FL_FROZEN || pPlayer->IsPlayerDead() )
return true;
return IsHudMenuTakingInput();
}
//-----------------------------------------------------------------------------
// Purpose: Menu Selection Code
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::SelectSlot( int iSlot )
{
// A menu may be overriding weapon selection commands
if ( HandleHudMenuInput( iSlot ) )
{
return;
}
// If we're not allowed to draw, ignore weapon selections
if ( !BaseClass::ShouldDraw() )
{
return;
}
UpdateSelectionTime();
SelectWeaponSlot( iSlot );
}
//-----------------------------------------------------------------------------
// Purpose: Close the weapon selection
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::UserCmd_Close(void)
{
CancelWeaponSelection();
}
//-----------------------------------------------------------------------------
// Purpose: Selects the next item in the weapon menu
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::UserCmd_NextWeapon(void)
{
// If we're not allowed to draw, ignore weapon selections
if ( !BaseClass::ShouldDraw() )
return;
CycleToNextWeapon();
if( hud_fastswitch.GetInt() > 0 )
{
SelectWeapon();
}
UpdateSelectionTime();
}
//-----------------------------------------------------------------------------
// Purpose: Selects the previous item in the menu
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::UserCmd_PrevWeapon(void)
{
// If we're not allowed to draw, ignore weapon selections
if ( !BaseClass::ShouldDraw() )
return;
CycleToPrevWeapon();
if( hud_fastswitch.GetInt() > 0 )
{
SelectWeapon();
}
UpdateSelectionTime();
}
//-----------------------------------------------------------------------------
// Purpose: Switches the last weapon the player was using
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::UserCmd_LastWeapon(void)
{
// If we're not allowed to draw, ignore weapon selections
if ( !BaseClass::ShouldDraw() )
return;
/*
if ( IsHudMenuPreventingWeaponSelection() )
{
return;
}
*/
SwitchToLastWeapon();
}
//-----------------------------------------------------------------------------
// Purpose: Switches the last weapon the player was using
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::SwitchToLastWeapon( void )
{
// Get the player's last weapon
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return;
input->MakeWeaponSelection( player->GetLastWeapon() );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::SetWeaponSelected( void )
{
Assert( GetSelectedWeapon() );
// Mark selection so that it's placed into next CUserCmd created
input->MakeWeaponSelection( GetSelectedWeapon() );
}
//-----------------------------------------------------------------------------
// Purpose: Player has chosen to draw the currently selected weapon
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::SelectWeapon( void )
{
if ( !GetSelectedWeapon() )
{
engine->ClientCmd( "cancelselect\n" );
return;
}
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return;
// Don't allow selections of weapons that can't be selected (out of ammo, etc)
if ( !GetSelectedWeapon()->CanBeSelected() )
{
player->EmitSound( "Player.DenyWeaponSelection" );
}
else
{
SetWeaponSelected();
m_hSelectedWeapon = NULL;
engine->ClientCmd( "cancelselect\n" );
// Play the "weapon selected" sound
player->EmitSound( "Player.WeaponSelected" );
}
}
//-----------------------------------------------------------------------------
// Purpose: Abort selecting a weapon
//-----------------------------------------------------------------------------
void CBaseHudWeaponSelection::CancelWeaponSelection( void )
{
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return;
// Fastswitches happen in a single frame, so the Weapon Selection HUD Element isn't visible
// yet, but it's going to be next frame. We need to ask it if it thinks it's going to draw,
// instead of checking it's IsActive flag.
if ( ShouldDraw() )
{
HideSelection();
m_hSelectedWeapon = NULL;
// Play the "close weapon selection" sound
player->EmitSound( "Player.WeaponSelectionClose" );
}
else
{
engine->ClientCmd("escape");
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns the first weapon for a given slot.
//-----------------------------------------------------------------------------
C_BaseCombatWeapon *CBaseHudWeaponSelection::GetFirstPos( int iSlot )
{
int iLowestPosition = MAX_WEAPON_POSITIONS;
C_BaseCombatWeapon *pFirstWeapon = NULL;
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return NULL;
for ( int i = 0; i < MAX_WEAPONS; i++ )
{
C_BaseCombatWeapon *pWeapon = player->GetWeapon( i );
if ( !pWeapon )
continue;
if ( ( pWeapon->GetSlot() == iSlot ) && (pWeapon->VisibleInWeaponSelection()) )
{
// If this weapon is lower in the slot than the current lowest, it's our new winner
if ( pWeapon->GetPosition() <= iLowestPosition )
{
iLowestPosition = pWeapon->GetPosition();
pFirstWeapon = pWeapon;
}
}
}
return pFirstWeapon;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_BaseCombatWeapon *CBaseHudWeaponSelection::GetNextActivePos( int iSlot, int iSlotPos )
{
if ( iSlotPos >= MAX_WEAPON_POSITIONS || iSlot >= MAX_WEAPON_SLOTS )
return NULL;
int iLowestPosition = MAX_WEAPON_POSITIONS;
C_BaseCombatWeapon *pNextWeapon = NULL;
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return NULL;
for ( int i = 0; i < MAX_WEAPONS; i++ )
{
C_BaseCombatWeapon *pWeapon = player->GetWeapon( i );
if ( !pWeapon )
continue;
if ( CanBeSelectedInHUD( pWeapon ) && pWeapon->GetSlot() == iSlot )
{
// If this weapon is lower in the slot than the current lowest, and above our desired position, it's our new winner
if ( pWeapon->GetPosition() <= iLowestPosition && pWeapon->GetPosition() >= iSlotPos )
{
iLowestPosition = pWeapon->GetPosition();
pNextWeapon = pWeapon;
}
}
}
return pNextWeapon;
}

View File

@@ -0,0 +1,119 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Weapon selection handling
//
// $NoKeywords: $
//=============================================================================//
#if !defined( WEAPON_SELECTION_H )
#define WEAPON_SELECTION_H
#ifdef _WIN32
#pragma once
#endif
#include "hudelement.h"
class C_BaseCombatWeapon;
class C_BasePlayer;
extern ConVar hud_fastswitch;
// weapon switch types for Convar hud_fastswitch
#define HUDTYPE_BUCKETS 0 // PC buckets
#define HUDTYPE_FASTSWITCH 1 // PC fastswitch
#define HUDTYPE_PLUS 2 // console buckets
#define HUDTYPE_CAROUSEL 3 // console carousel scroll
//-----------------------------------------------------------------------------
// Purpose: Base class for tf2 & hl2 weapon selection hud elements
//-----------------------------------------------------------------------------
abstract_class CBaseHudWeaponSelection : public CHudElement
{
DECLARE_CLASS( CBaseHudWeaponSelection, CHudElement );
public:
CBaseHudWeaponSelection( const char *pElementName );
virtual void Init( void );
virtual void VidInit( void );
virtual void ProcessInput();
virtual void Reset(void);
virtual void OnThink(void);
virtual void OpenSelection( void );
virtual void HideSelection( void );
virtual void CancelWeaponSelection( void );
// Game specific overrides
virtual void CycleToNextWeapon( void ) = 0;
virtual void CycleToPrevWeapon( void ) = 0;
virtual void SwitchToLastWeapon( void );
virtual C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos ) = 0;
virtual void SelectWeaponSlot( int iSlot ) = 0;
virtual C_BaseCombatWeapon *GetFirstPos( int iSlot );
virtual C_BaseCombatWeapon *GetNextActivePos( int iSlot, int iSlotPos );
virtual void SetWeaponSelected( void );
virtual void SelectWeapon( void );
virtual C_BaseCombatWeapon *GetSelectedWeapon( void ) = 0;
virtual void OnWeaponPickup( C_BaseCombatWeapon *pWeapon );
virtual bool IsInSelectionMode();
void UserCmd_Slot1( void );
void UserCmd_Slot2( void );
void UserCmd_Slot3( void );
void UserCmd_Slot4( void );
void UserCmd_Slot5( void );
void UserCmd_Slot6( void );
void UserCmd_Slot7( void );
void UserCmd_Slot8( void );
void UserCmd_Slot9( void );
void UserCmd_Slot0( void );
void UserCmd_Slot10( void );
void UserCmd_Close( void );
void UserCmd_NextWeapon( void );
void UserCmd_PrevWeapon( void );
void UserCmd_LastWeapon( void );
void UserCmd_DropPrimary( void );
virtual void SelectSlot( int iSlot );
virtual bool IsHudMenuTakingInput();
virtual bool IsHudMenuPreventingWeaponSelection();
bool HandleHudMenuInput( int iSlot );
static CBaseHudWeaponSelection *GetInstance();
// these functions are exposed as virtual so that the tf_hints system can redraw the weapon selection
virtual void DrawWList( C_BasePlayer *pPlayer, C_BaseCombatWeapon *pSelectedWeapon, bool drawOutline = false, int ora = 0, int og = 0, int ob = 0, int oa = 0 ) {}
virtual bool ComputeRect( C_BasePlayer *pPlayer, C_BaseCombatWeapon *pSelectedWeapon, wrect_t *outrect ) { return false; }
virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding );
protected:
// returns true if there is a weapon currently visible to select
virtual bool IsWeaponSelectable() { return IsInSelectionMode(); }
bool CanBeSelectedInHUD( C_BaseCombatWeapon *pWeapon );
void UpdateSelectionTime( void );
float m_flSelectionTime; // most recent time at which weapon selection had input
static CBaseHudWeaponSelection *s_pInstance;
bool m_bSelectionVisible;
CHandle< C_BaseCombatWeapon > m_hSelectedWeapon;
private:
void EnableSlowMo();
void DisableSlowMo();
bool CheatsWasEnabled;
};
// accessor
CBaseHudWeaponSelection *GetHudWeaponSelection();
#endif // WEAPON_SELECTION_H

View File

@@ -0,0 +1,270 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Weapons Resource implementation
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "history_resource.h"
#include <vgui_controls/Controls.h>
#include <vgui/ISurface.h>
#include "c_baseplayer.h"
#include "hud.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
WeaponsResource gWR;
void FreeHudTextureList( CUtlDict< CHudTexture *, int >& list );
static CHudTexture *FindHudTextureInDict( CUtlDict< CHudTexture *, int >& list, const char *psz )
{
int idx = list.Find( psz );
if ( idx == list.InvalidIndex() )
return NULL;
return list[ idx ];
}
//-----------------------------------------------------------------------------
// Purpose:
// Output :
//-----------------------------------------------------------------------------
WeaponsResource::WeaponsResource( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Output :
//-----------------------------------------------------------------------------
WeaponsResource::~WeaponsResource( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void WeaponsResource::Init( void )
{
Reset();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void WeaponsResource::Reset( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Load all the sprites needed for all registered weapons
//-----------------------------------------------------------------------------
void WeaponsResource::LoadAllWeaponSprites( void )
{
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return;
for (int i = 0; i < MAX_WEAPONS; i++)
{
if ( player->GetWeapon(i) )
{
LoadWeaponSprites( player->GetWeapon(i)->GetWeaponFileInfoHandle() );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void WeaponsResource::LoadWeaponSprites( WEAPON_FILE_INFO_HANDLE hWeaponFileInfo )
{
// WeaponsResource is a friend of C_BaseCombatWeapon
FileWeaponInfo_t *pWeaponInfo = GetFileWeaponInfoFromHandle( hWeaponFileInfo );
if ( !pWeaponInfo )
return;
// Already parsed the hud elements?
if ( pWeaponInfo->bLoadedHudElements )
return;
pWeaponInfo->bLoadedHudElements = true;
pWeaponInfo->iconActive = NULL;
pWeaponInfo->iconInactive = NULL;
pWeaponInfo->iconAmmo = NULL;
pWeaponInfo->iconAmmo2 = NULL;
pWeaponInfo->iconCrosshair = NULL;
pWeaponInfo->iconAutoaim = NULL;
pWeaponInfo->iconSmall = NULL;
char sz[128];
Q_snprintf(sz, sizeof( sz ), "scripts/weapons/%s", pWeaponInfo->szClassName);
CUtlDict< CHudTexture *, int > tempList;
LoadHudTextures( tempList, sz, g_pGameRules->GetEncryptionKey() );
if ( !tempList.Count() )
{
// no sprite description file for weapon, use default small blocks
pWeaponInfo->iconActive = gHUD.GetIcon( "selection" );
pWeaponInfo->iconInactive = gHUD.GetIcon( "selection" );
pWeaponInfo->iconAmmo = gHUD.GetIcon( "bucket1" );
return;
}
CHudTexture *p;
p = FindHudTextureInDict( tempList, "crosshair" );
if ( p )
{
pWeaponInfo->iconCrosshair = gHUD.AddUnsearchableHudIconToList( *p );
}
p = FindHudTextureInDict( tempList, "autoaim" );
if ( p )
{
pWeaponInfo->iconAutoaim = gHUD.AddUnsearchableHudIconToList( *p );
}
p = FindHudTextureInDict( tempList, "zoom" );
if ( p )
{
pWeaponInfo->iconZoomedCrosshair = gHUD.AddUnsearchableHudIconToList( *p );
}
else
{
pWeaponInfo->iconZoomedCrosshair = pWeaponInfo->iconCrosshair; //default to non-zoomed crosshair
}
p = FindHudTextureInDict( tempList, "zoom_autoaim" );
if ( p )
{
pWeaponInfo->iconZoomedAutoaim = gHUD.AddUnsearchableHudIconToList( *p );
}
else
{
pWeaponInfo->iconZoomedAutoaim = pWeaponInfo->iconZoomedCrosshair; //default to zoomed crosshair
}
CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource );
if( pHudHR )
{
p = FindHudTextureInDict( tempList, "weapon" );
if ( p )
{
pWeaponInfo->iconInactive = gHUD.AddUnsearchableHudIconToList( *p );
if ( pWeaponInfo->iconInactive )
{
pWeaponInfo->iconInactive->Precache();
pHudHR->SetHistoryGap( pWeaponInfo->iconInactive->Height() );
}
}
p = FindHudTextureInDict( tempList, "weapon_s" );
if ( p )
{
pWeaponInfo->iconActive = gHUD.AddUnsearchableHudIconToList( *p );
if ( pWeaponInfo->iconActive )
{
pWeaponInfo->iconActive->Precache();
}
}
p = FindHudTextureInDict( tempList, "weapon_small" );
if ( p )
{
pWeaponInfo->iconSmall = gHUD.AddUnsearchableHudIconToList( *p );
if ( pWeaponInfo->iconSmall )
{
pWeaponInfo->iconSmall->Precache();
}
}
p = FindHudTextureInDict( tempList, "ammo" );
if ( p )
{
pWeaponInfo->iconAmmo = gHUD.AddUnsearchableHudIconToList( *p );
if ( pWeaponInfo->iconAmmo )
{
pWeaponInfo->iconAmmo->Precache();
pHudHR->SetHistoryGap( pWeaponInfo->iconAmmo->Height() );
}
}
p = FindHudTextureInDict( tempList, "ammo2" );
if ( p )
{
pWeaponInfo->iconAmmo2 = gHUD.AddUnsearchableHudIconToList( *p );
if ( pWeaponInfo->iconAmmo2 )
{
pWeaponInfo->iconAmmo2->Precache();
pHudHR->SetHistoryGap( pWeaponInfo->iconAmmo2->Height() );
}
}
}
FreeHudTextureList( tempList );
}
//-----------------------------------------------------------------------------
// Purpose: Helper function to return a Ammo pointer from id
//-----------------------------------------------------------------------------
CHudTexture *WeaponsResource::GetAmmoIconFromWeapon( int iAmmoId )
{
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return NULL;
for ( int i = 0; i < MAX_WEAPONS; i++ )
{
C_BaseCombatWeapon *weapon = player->GetWeapon( i );
if ( !weapon )
continue;
if ( weapon->GetPrimaryAmmoType() == iAmmoId )
{
return weapon->GetWpnData().iconAmmo;
}
else if ( weapon->GetSecondaryAmmoType() == iAmmoId )
{
return weapon->GetWpnData().iconAmmo2;
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Get a pointer to a weapon using this ammo
//-----------------------------------------------------------------------------
const FileWeaponInfo_t *WeaponsResource::GetWeaponFromAmmo( int iAmmoId )
{
C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
if ( !player )
return NULL;
for ( int i = 0; i < MAX_WEAPONS; i++ )
{
C_BaseCombatWeapon *weapon = player->GetWeapon( i );
if ( !weapon )
continue;
if ( weapon->GetPrimaryAmmoType() == iAmmoId )
{
return &weapon->GetWpnData();
}
else if ( weapon->GetSecondaryAmmoType() == iAmmoId )
{
return &weapon->GetWpnData();
}
}
return NULL;
}

View File

@@ -0,0 +1,44 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef WEAPONS_RESOURCE_H
#define WEAPONS_RESOURCE_H
#pragma once
#include "shareddefs.h"
#include "weapon_parse.h"
#include "utldict.h"
#include "hud.h"
class C_BaseCombatWeapon;
class CHudTexture;
//-----------------------------------------------------------------------------
// Purpose: Stores data about the Weapon Definitions passed to the client when
// the client first connects to a server.
//-----------------------------------------------------------------------------
class WeaponsResource
{
public:
WeaponsResource( void );
~WeaponsResource( void );
void Init( void );
void Reset( void );
// Sprite handling
void LoadWeaponSprites( WEAPON_FILE_INFO_HANDLE hWeaponFileInfo );
void LoadAllWeaponSprites( void );
// Ammo Handling
CHudTexture *GetAmmoIconFromWeapon( int iAmmoId );
const FileWeaponInfo_t *GetWeaponFromAmmo( int iAmmoId );
};
extern WeaponsResource gWR;
#endif // WEAPONS_RESOURCE_H

307
game/client/worldlight.cpp Normal file
View File

@@ -0,0 +1,307 @@
//========= Copyright (C) 2018, CSProMod Team, All rights reserved. =========//
//
// Purpose: provide world light related functions to the client
//
// As the engine provides no access to brush/model data (brushdata_t, model_t),
// we hence have no access to dworldlight_t. Therefore, we manually extract the
// world light data from the BSP itself, before entities are initialised on map
// load.
//
// To find the brightest light at a point, all world lights are iterated.
// Lights whose radii do not encompass our sample point are quickly rejected,
// as are lights which are not in our PVS, or visible from the sample point.
// If the sky light is visible from the sample point, then it shall supersede
// all other world lights.
//
// Written: November 2011
// Author: Saul Rennison
//
//===========================================================================//
#include "cbase.h"
#include "worldlight.h"
#include "bspfile.h"
#include "filesystem.h"
#include "client_factorylist.h" // FactoryList_Retrieve
#include "eiface.h" // IVEngineServer
static IVEngineServer *g_pEngineServer = NULL;
//-----------------------------------------------------------------------------
// Singleton exposure
//-----------------------------------------------------------------------------
static CWorldLights s_WorldLights;
CWorldLights *g_pWorldLights = &s_WorldLights;
//-----------------------------------------------------------------------------
// Purpose: calculate intensity ratio for a worldlight by distance
// Author: Valve Software
//-----------------------------------------------------------------------------
static float Engine_WorldLightDistanceFalloff( const dworldlight_t *wl, const Vector& delta )
{
float falloff;
switch (wl->type)
{
case emit_surface:
// Cull out stuff that's too far
if(wl->radius != 0)
{
if(DotProduct( delta, delta ) > (wl->radius * wl->radius))
return 0.0f;
}
return InvRSquared(delta);
break;
case emit_skylight:
return 1.f;
break;
case emit_quakelight:
// X - r;
falloff = wl->linear_attn - FastSqrt( DotProduct( delta, delta ) );
if(falloff < 0)
return 0.f;
return falloff;
break;
case emit_skyambient:
return 1.f;
break;
case emit_point:
case emit_spotlight: // directional & positional
{
float dist2, dist;
dist2 = DotProduct(delta, delta);
dist = FastSqrt(dist2);
// Cull out stuff that's too far
if(wl->radius != 0 && dist > wl->radius)
return 0.f;
return 1.f / (wl->constant_attn + wl->linear_attn * dist + wl->quadratic_attn * dist2);
}
break;
}
return 1.f;
}
//-----------------------------------------------------------------------------
// Purpose: initialise game system and members
//-----------------------------------------------------------------------------
CWorldLights::CWorldLights() : CAutoGameSystem("World lights")
{
m_nWorldLights = 0;
m_pWorldLights = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: clear worldlights, free memory
//-----------------------------------------------------------------------------
void CWorldLights::Clear()
{
m_nWorldLights = 0;
if(m_pWorldLights)
{
delete [] m_pWorldLights;
m_pWorldLights = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose: get the IVEngineServer, we need this for the PVS functions
//-----------------------------------------------------------------------------
bool CWorldLights::Init()
{
factorylist_t factories;
FactoryList_Retrieve(factories);
if((g_pEngineServer = (IVEngineServer*)factories.appSystemFactory(INTERFACEVERSION_VENGINESERVER, NULL)) == NULL)
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: get all world lights from the BSP
//-----------------------------------------------------------------------------
void CWorldLights::LevelInitPreEntity()
{
// Get the map path
const char *pszMapName = modelinfo->GetModelName(modelinfo->GetModel(1));
// Open map
FileHandle_t hFile = g_pFullFileSystem->Open(pszMapName, "rb");
if(!hFile)
{
Warning("CWorldLights: unable to open map\n");
return;
}
// Read the BSP header. We don't need to do any version checks, etc. as we
// can safely assume that the engine did this for us
dheader_t hdr;
g_pFullFileSystem->Read(&hdr, sizeof(hdr), hFile);
// Grab the light lump and seek to it
lump_t &lightLump = hdr.lumps[LUMP_WORLDLIGHTS];
// INSOLENCE: If the worldlights lump is empty, that means theres no normal, LDR lights to extract
// This can happen when, for example, the map is compiled in HDR mode only
// So move on to the HDR worldlights lump
if (lightLump.filelen == 0)
{
lightLump = hdr.lumps[LUMP_WORLDLIGHTS_HDR];
}
// If we can't divide the lump data into a whole number of worldlights,
// then the BSP format changed and we're unaware
if(lightLump.filelen % sizeof(dworldlight_t))
{
Warning("CWorldLights: unknown world light lump\n");
// Close file
g_pFullFileSystem->Close(hFile);
return;
}
g_pFullFileSystem->Seek(hFile, lightLump.fileofs, FILESYSTEM_SEEK_HEAD);
// Allocate memory for the worldlights
m_nWorldLights = lightLump.filelen / sizeof(dworldlight_t);
m_pWorldLights = new dworldlight_t[m_nWorldLights];
// Read worldlights then close
g_pFullFileSystem->Read(m_pWorldLights, lightLump.filelen, hFile);
g_pFullFileSystem->Close(hFile);
DevMsg("CWorldLights: load successful (%d lights at 0x%p)\n", m_nWorldLights, m_pWorldLights);
}
//-----------------------------------------------------------------------------
// Purpose: find the brightest light source at a point
//-----------------------------------------------------------------------------
bool CWorldLights::GetBrightestLightSource(const Vector &vecPosition, Vector &vecLightPos, Vector &vecLightBrightness)
{
if(!m_nWorldLights || !m_pWorldLights)
return false;
// Default light position and brightness to zero
vecLightBrightness.Init();
vecLightPos.Init();
// Find the size of the PVS for our current position
int nCluster = g_pEngineServer->GetClusterForOrigin(vecPosition);
int nPVSSize = g_pEngineServer->GetPVSForCluster(nCluster, 0, NULL);
// Get the PVS at our position
byte *pvs = new byte[nPVSSize];
g_pEngineServer->GetPVSForCluster(nCluster, nPVSSize, pvs);
// Iterate through all the worldlights
for(int i = 0; i < m_nWorldLights; ++i)
{
dworldlight_t *light = &m_pWorldLights[i];
// Skip skyambient
if(light->type == emit_skyambient)
{
//engine->Con_NPrintf(i, "%d: skyambient", i);
continue;
}
// Handle sun
if(light->type == emit_skylight)
{
// Calculate sun position
Vector vecAbsStart = vecPosition + Vector(0,0,30);
Vector vecAbsEnd = vecAbsStart - (light->normal * MAX_TRACE_LENGTH);
trace_t tr;
UTIL_TraceLine(vecPosition, vecAbsEnd, MASK_OPAQUE, NULL, COLLISION_GROUP_NONE, &tr);
// If we didn't hit anything then we have a problem
if(!tr.DidHit())
{
//engine->Con_NPrintf(i, "%d: skylight: couldn't touch sky", i);
continue;
}
// If we did hit something, and it wasn't the skybox, then skip
// this worldlight
if(!(tr.surface.flags & SURF_SKY) && !(tr.surface.flags & SURF_SKY2D))
{
//engine->Con_NPrintf(i, "%d: skylight: no sight to sun", i);
continue;
}
// Act like we didn't find any valid worldlights, so the shadow
// manager uses the default shadow direction instead (should be the
// sun direction)
delete[] pvs;
return false;
}
// Calculate square distance to this worldlight
Vector vecDelta = light->origin - vecPosition;
float flDistSqr = vecDelta.LengthSqr();
float flRadiusSqr = light->radius * light->radius;
// Skip lights that are out of our radius
if(flRadiusSqr > 0 && flDistSqr >= flRadiusSqr)
{
//engine->Con_NPrintf(i, "%d: out-of-radius (dist: %d, radius: %d)", i, sqrt(flDistSqr), light->radius);
continue;
}
// Is it out of our PVS?
if(!g_pEngineServer->CheckOriginInPVS(light->origin, pvs, nPVSSize))
{
//engine->Con_NPrintf(i, "%d: out of PVS", i);
continue;
}
// Calculate intensity at our position
float flRatio = Engine_WorldLightDistanceFalloff(light, vecDelta);
Vector vecIntensity = light->intensity * flRatio;
// Is this light more intense than the one we already found?
if(vecIntensity.LengthSqr() <= vecLightBrightness.LengthSqr())
{
//engine->Con_NPrintf(i, "%d: too dim", i);
continue;
}
// Can we see the light?
trace_t tr;
Vector vecAbsStart = vecPosition + Vector(0,0,30);
UTIL_TraceLine(vecAbsStart, light->origin, MASK_OPAQUE, NULL, COLLISION_GROUP_NONE, &tr);
if(tr.DidHit())
{
//engine->Con_NPrintf(i, "%d: trace failed", i);
continue;
}
vecLightPos = light->origin;
vecLightBrightness = vecIntensity;
//engine->Con_NPrintf(i, "%d: set (%.2f)", i, vecIntensity.Length());
}
delete[] pvs;
//engine->Con_NPrintf(m_nWorldLights, "result: %d", !vecLightBrightness.IsZero());
return !vecLightBrightness.IsZero();
}

50
game/client/worldlight.h Normal file
View File

@@ -0,0 +1,50 @@
//========= Copyright (C) 2018, CSProMod Team, All rights reserved. =========//
//
// Purpose: provide world light related functions to the client
//
// Written: November 2011
// Author: Saul Rennison
//
//===========================================================================//
#pragma once
#include "igamesystem.h" // CAutoGameSystem
class Vector;
struct dworldlight_t;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CWorldLights : public CAutoGameSystem
{
public:
CWorldLights();
~CWorldLights() { Clear(); }
//-------------------------------------------------------------------------
// Find the brightest light source at a point
//-------------------------------------------------------------------------
bool GetBrightestLightSource(const Vector &vecPosition, Vector &vecLightPos, Vector &vecLightBrightness);
#ifdef MAPBASE
bool GetCumulativeLightSource(const Vector &vecPosition, Vector &vecLightPos, float flMinBrightnessSqr);
#endif
// CAutoGameSystem overrides
public:
virtual bool Init();
virtual void LevelInitPreEntity();
virtual void LevelShutdownPostEntity() { Clear(); }
private:
void Clear();
int m_nWorldLights;
dworldlight_t *m_pWorldLights;
};
//-----------------------------------------------------------------------------
// Singleton exposure
//-----------------------------------------------------------------------------
extern CWorldLights *g_pWorldLights;

17
game/protobuf_include.vpc Normal file
View File

@@ -0,0 +1,17 @@
//-----------------------------------------------------------------------------
// protobuf_include.vpc
//
// Project Script
//-----------------------------------------------------------------------------
$MacroRequired "PLATFORM"
$Project
{
$Folder "Link Libraries"
{
$Libexternal $SRCDIR\lib\public\2010\libprotobuf [$VS2010]
$Libexternal 2012\libprotobuf [$VS2012]
$Libexternal libprotobuf [$VS2013 || !$WINDOWS]
}
}

516
game/server/AI_Criteria.cpp Normal file
View File

@@ -0,0 +1,516 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "AI_Criteria.h"
#include "ai_speech.h"
#include <KeyValues.h>
#include "engine/IEngineSound.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
AI_CriteriaSet::AI_CriteriaSet() : m_Lookup( 0, 0, CritEntry_t::LessFunc )
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : src -
//-----------------------------------------------------------------------------
AI_CriteriaSet::AI_CriteriaSet( const AI_CriteriaSet& src ) : m_Lookup( 0, 0, CritEntry_t::LessFunc )
{
m_Lookup.Purge();
for ( short i = src.m_Lookup.FirstInorder();
i != src.m_Lookup.InvalidIndex();
i = src.m_Lookup.NextInorder( i ) )
{
m_Lookup.Insert( src.m_Lookup[ i ] );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
AI_CriteriaSet::~AI_CriteriaSet()
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *criteria -
// "" -
// 1.0f -
//-----------------------------------------------------------------------------
void AI_CriteriaSet::AppendCriteria( const char *criteria, const char *value /*= ""*/, float weight /*= 1.0f*/ )
{
// Note: value pointer may come from an entry inside m_Lookup!
// that value string must be copied out before any modification
// to the m_Lookup struct which could make the pointer invalid
int idx = FindCriterionIndex( criteria );
if ( idx == -1 )
{
CritEntry_t entry;
entry.criterianame = criteria;
MEM_ALLOC_CREDIT();
entry.SetValue(value);
entry.weight = weight;
m_Lookup.Insert( entry );
}
else
{
CritEntry_t *entry = &m_Lookup[ idx ];
entry->SetValue( value );
entry->weight = weight;
}
}
//-----------------------------------------------------------------------------
// Removes criteria in a set
//-----------------------------------------------------------------------------
void AI_CriteriaSet::RemoveCriteria( const char *criteria )
{
int idx = FindCriterionIndex( criteria );
if ( idx == -1 )
return;
m_Lookup.RemoveAt( idx );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int AI_CriteriaSet::GetCount() const
{
return m_Lookup.Count();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// Output : int
//-----------------------------------------------------------------------------
int AI_CriteriaSet::FindCriterionIndex( const char *name ) const
{
CritEntry_t search;
search.criterianame = name;
int idx = m_Lookup.Find( search );
if ( idx == m_Lookup.InvalidIndex() )
return -1;
return idx;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
// Output : char const
//-----------------------------------------------------------------------------
const char *AI_CriteriaSet::GetName( int index ) const
{
static char namebuf[ 128 ];
if ( index < 0 || index >= (int)m_Lookup.Count() )
return "";
const CritEntry_t *entry = &m_Lookup[ index ];
Q_strncpy( namebuf, entry->criterianame.String(), sizeof( namebuf ) );
return namebuf;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
// Output : char const
//-----------------------------------------------------------------------------
const char *AI_CriteriaSet::GetValue( int index ) const
{
if ( index < 0 || index >= (int)m_Lookup.Count() )
return "";
const CritEntry_t *entry = &m_Lookup[ index ];
return entry->value ? entry->value : "";
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
// Output : float
//-----------------------------------------------------------------------------
float AI_CriteriaSet::GetWeight( int index ) const
{
if ( index < 0 || index >= (int)m_Lookup.Count() )
return 1.0f;
const CritEntry_t *entry = &m_Lookup[ index ];
return entry->weight;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void AI_CriteriaSet::Describe()
{
for ( short i = m_Lookup.FirstInorder(); i != m_Lookup.InvalidIndex(); i = m_Lookup.NextInorder( i ) )
{
CritEntry_t *entry = &m_Lookup[ i ];
if ( entry->weight != 1.0f )
{
DevMsg( " %20s = '%s' (weight %f)\n", entry->criterianame.String(), entry->value ? entry->value : "", entry->weight );
}
else
{
DevMsg( " %20s = '%s'\n", entry->criterianame.String(), entry->value ? entry->value : "" );
}
}
}
BEGIN_SIMPLE_DATADESC( AI_ResponseParams )
DEFINE_FIELD( flags, FIELD_SHORT ),
DEFINE_FIELD( odds, FIELD_SHORT ),
DEFINE_FIELD( soundlevel, FIELD_CHARACTER ),
DEFINE_FIELD( delay, FIELD_INTEGER ), // These are compressed down to two float16s, so treat as an INT for saverestore
DEFINE_FIELD( respeakdelay, FIELD_INTEGER ), //
END_DATADESC()
BEGIN_SIMPLE_DATADESC( AI_Response )
DEFINE_FIELD( m_Type, FIELD_CHARACTER ),
DEFINE_ARRAY( m_szResponseName, FIELD_CHARACTER, AI_Response::MAX_RESPONSE_NAME ),
DEFINE_ARRAY( m_szMatchingRule, FIELD_CHARACTER, AI_Response::MAX_RULE_NAME ),
// DEFINE_FIELD( m_pCriteria, FIELD_??? ), // Don't need to save this probably
DEFINE_EMBEDDED( m_Params ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
AI_Response::AI_Response()
{
m_Type = RESPONSE_NONE;
m_szResponseName[0] = 0;
m_pCriteria = NULL;
m_szMatchingRule[0]=0;
m_szContext = NULL;
m_bApplyContextToWorld = false;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
AI_Response::AI_Response( const AI_Response &from )
{
Assert( (void*)(&m_Type) == (void*)this );
m_pCriteria = NULL;
memcpy( this, &from, sizeof(*this) );
m_pCriteria = NULL;
m_szContext = NULL;
SetContext( from.m_szContext );
m_bApplyContextToWorld = from.m_bApplyContextToWorld;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
AI_Response::~AI_Response()
{
delete m_pCriteria;
delete[] m_szContext;
}
//-----------------------------------------------------------------------------
AI_Response &AI_Response::operator=( const AI_Response &from )
{
Assert( (void*)(&m_Type) == (void*)this );
delete m_pCriteria;
m_pCriteria = NULL;
memcpy( this, &from, sizeof(*this) );
m_pCriteria = NULL;
m_szContext = NULL;
SetContext( from.m_szContext );
m_bApplyContextToWorld = from.m_bApplyContextToWorld;
return *this;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *response -
// *criteria -
//-----------------------------------------------------------------------------
void AI_Response::Init( ResponseType_t type, const char *responseName, const AI_CriteriaSet& criteria, const AI_ResponseParams& responseparams, const char *ruleName, const char *applyContext, bool bApplyContextToWorld )
{
m_Type = type;
Q_strncpy( m_szResponseName, responseName, sizeof( m_szResponseName ) );
// Copy underlying criteria
m_pCriteria = new AI_CriteriaSet( criteria );
Q_strncpy( m_szMatchingRule, ruleName ? ruleName : "NULL", sizeof( m_szMatchingRule ) );
m_Params = responseparams;
SetContext( applyContext );
m_bApplyContextToWorld = bApplyContextToWorld;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void AI_Response::Describe()
{
if ( m_pCriteria )
{
DevMsg( "Search criteria:\n" );
m_pCriteria->Describe();
}
if ( m_szMatchingRule[ 0 ] )
{
DevMsg( "Matched rule '%s', ", m_szMatchingRule );
}
if ( m_szContext )
{
DevMsg( "Contexts to set '%s' on %s, ", m_szContext, m_bApplyContextToWorld ? "world" : "speaker" );
}
DevMsg( "response %s = '%s'\n", DescribeResponse( (ResponseType_t)m_Type ), m_szResponseName );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : char const
//-----------------------------------------------------------------------------
void AI_Response::GetName( char *buf, size_t buflen ) const
{
Q_strncpy( buf, m_szResponseName, buflen );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : char const
//-----------------------------------------------------------------------------
void AI_Response::GetResponse( char *buf, size_t buflen ) const
{
GetName( buf, buflen );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : type -
// Output : char const
//-----------------------------------------------------------------------------
const char *AI_Response::DescribeResponse( ResponseType_t type )
{
if ( (int)type < 0 || (int)type >= NUM_RESPONSES )
{
Assert( 0 );
return "???AI_Response bogus index";
}
switch( type )
{
default:
{
Assert( 0 );
}
// Fall through
case RESPONSE_NONE:
return "RESPONSE_NONE";
case RESPONSE_SPEAK:
return "RESPONSE_SPEAK";
case RESPONSE_SENTENCE:
return "RESPONSE_SENTENCE";
case RESPONSE_SCENE:
return "RESPONSE_SCENE";
case RESPONSE_RESPONSE:
return "RESPONSE_RESPONSE";
case RESPONSE_PRINT:
return "RESPONSE_PRINT";
}
return "RESPONSE_NONE";
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : const AI_CriteriaSet
//-----------------------------------------------------------------------------
const AI_CriteriaSet *AI_Response::GetCriteria()
{
return m_pCriteria;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void AI_Response::Release()
{
delete this;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : soundlevel_t
//-----------------------------------------------------------------------------
soundlevel_t AI_Response::GetSoundLevel() const
{
if ( m_Params.flags & AI_ResponseParams::RG_SOUNDLEVEL )
{
return (soundlevel_t)m_Params.soundlevel;
}
return SNDLVL_TALKING;
}
float AI_Response::GetRespeakDelay( void ) const
{
if ( m_Params.flags & AI_ResponseParams::RG_RESPEAKDELAY )
{
interval_t temp;
m_Params.respeakdelay.ToInterval( temp );
return RandomInterval( temp );
}
return 0.0f;
}
float AI_Response::GetWeaponDelay( void ) const
{
if ( m_Params.flags & AI_ResponseParams::RG_WEAPONDELAY )
{
interval_t temp;
m_Params.weapondelay.ToInterval( temp );
return RandomInterval( temp );
}
return 0.0f;
}
bool AI_Response::GetSpeakOnce( void ) const
{
if ( m_Params.flags & AI_ResponseParams::RG_SPEAKONCE )
{
return true;
}
return false;
}
bool AI_Response::ShouldntUseScene( void ) const
{
return ( m_Params.flags & AI_ResponseParams::RG_DONT_USE_SCENE ) != 0;
}
bool AI_Response::ShouldBreakOnNonIdle( void ) const
{
return ( m_Params.flags & AI_ResponseParams::RG_STOP_ON_NONIDLE ) != 0;
}
int AI_Response::GetOdds( void ) const
{
if ( m_Params.flags & AI_ResponseParams::RG_ODDS )
{
return m_Params.odds;
}
return 100;
}
float AI_Response::GetDelay() const
{
if ( m_Params.flags & AI_ResponseParams::RG_DELAYAFTERSPEAK )
{
interval_t temp;
m_Params.delay.ToInterval( temp );
return RandomInterval( temp );
}
return 0.0f;
}
float AI_Response::GetPreDelay() const
{
if ( m_Params.flags & AI_ResponseParams::RG_DELAYBEFORESPEAK )
{
interval_t temp;
m_Params.predelay.ToInterval( temp );
return RandomInterval( temp );
}
return 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose: Sets context string
// Output : void
//-----------------------------------------------------------------------------
void AI_Response::SetContext( const char *context )
{
delete[] m_szContext;
m_szContext = NULL;
if ( context )
{
int len = Q_strlen( context );
m_szContext = new char[ len + 1 ];
Q_memcpy( m_szContext, context, len );
m_szContext[ len ] = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *raw -
// *key -
// keylen -
// *value -
// valuelen -
// *duration -
// Output : static bool
//-----------------------------------------------------------------------------
const char *SplitContext( const char *raw, char *key, int keylen, char *value, int valuelen, float *duration )
{
char *colon1 = Q_strstr( raw, ":" );
if ( !colon1 )
{
DevMsg( "SplitContext: warning, ignoring context '%s', missing colon separator!\n", raw );
*key = *value = 0;
return NULL;
}
int len = colon1 - raw;
Q_strncpy( key, raw, MIN( len + 1, keylen ) );
key[ MIN( len, keylen - 1 ) ] = 0;
bool last = false;
char *end = Q_strstr( colon1 + 1, "," );
if ( !end )
{
int remaining = Q_strlen( colon1 + 1 );
end = colon1 + 1 + remaining;
last = true;
}
char *colon2 = Q_strstr( colon1 + 1, ":" );
if ( colon2 && ( colon2 < end ) )
{
if ( duration )
*duration = atof( colon2 + 1 );
len = MIN( colon2 - ( colon1 + 1 ), valuelen - 1 );
Q_strncpy( value, colon1 + 1, len + 1 );
value[ len ] = 0;
}
else
{
if ( duration )
*duration = 0.0;
len = MIN( end - ( colon1 + 1 ), valuelen - 1 );
Q_strncpy( value, colon1 + 1, len + 1 );
value[ len ] = 0;
}
return last ? NULL : end + 1;
}

237
game/server/AI_Criteria.h Normal file
View File

@@ -0,0 +1,237 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_CRITERIA_H
#define AI_CRITERIA_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlrbtree.h"
#include "tier1/utlsymbol.h"
#include "interval.h"
#include "mathlib/compressed_vector.h"
extern const char *SplitContext( const char *raw, char *key, int keylen, char *value, int valuelen, float *duration );
class AI_CriteriaSet
{
public:
AI_CriteriaSet();
AI_CriteriaSet( const AI_CriteriaSet& src );
~AI_CriteriaSet();
void AppendCriteria( const char *criteria, const char *value = "", float weight = 1.0f );
void RemoveCriteria( const char *criteria );
void Describe();
int GetCount() const;
int FindCriterionIndex( const char *name ) const;
const char *GetName( int index ) const;
const char *GetValue( int index ) const;
float GetWeight( int index ) const;
private:
struct CritEntry_t
{
CritEntry_t() :
criterianame( UTL_INVAL_SYMBOL ),
weight( 0.0f )
{
value[ 0 ] = 0;
}
CritEntry_t( const CritEntry_t& src )
{
criterianame = src.criterianame;
value[ 0 ] = 0;
weight = src.weight;
SetValue( src.value );
}
CritEntry_t& operator=( const CritEntry_t& src )
{
if ( this == &src )
return *this;
criterianame = src.criterianame;
weight = src.weight;
SetValue( src.value );
return *this;
}
static bool LessFunc( const CritEntry_t& lhs, const CritEntry_t& rhs )
{
return Q_stricmp( lhs.criterianame.String(), rhs.criterianame.String() ) < 0 ? true : false;
}
void SetValue( char const *str )
{
if ( !str )
{
value[ 0 ] = 0;
}
else
{
Q_strncpy( value, str, sizeof( value ) );
}
}
CUtlSymbol criterianame;
char value[ 64 ];
float weight;
};
CUtlRBTree< CritEntry_t, short > m_Lookup;
};
#pragma pack(1)
template<typename T>
struct response_interval_t
{
T start;
T range;
interval_t &ToInterval( interval_t &dest ) const { dest.start = start; dest.range = range; return dest; }
void FromInterval( const interval_t &from ) { start = from.start; range = from.range; }
float Random() const { interval_t temp = { start, range }; return RandomInterval( temp ); }
};
typedef response_interval_t<float16_with_assign> responseparams_interval_t;
struct AI_ResponseParams
{
DECLARE_SIMPLE_DATADESC();
enum
{
RG_DELAYAFTERSPEAK = (1<<0),
RG_SPEAKONCE = (1<<1),
RG_ODDS = (1<<2),
RG_RESPEAKDELAY = (1<<3),
RG_SOUNDLEVEL = (1<<4),
RG_DONT_USE_SCENE = (1<<5),
RG_STOP_ON_NONIDLE = (1<<6),
RG_WEAPONDELAY = (1<<7),
RG_DELAYBEFORESPEAK = (1<<8),
};
AI_ResponseParams()
{
flags = 0;
odds = 100;
delay.start = 0;
delay.range = 0;
respeakdelay.start = 0;
respeakdelay.range = 0;
weapondelay.start = 0;
weapondelay.range = 0;
soundlevel = 0;
predelay.start = 0;
predelay.range = 0;
}
responseparams_interval_t delay; //4
responseparams_interval_t respeakdelay; //8
responseparams_interval_t weapondelay; //12
short odds; //14
short flags; //16
byte soundlevel; //17
responseparams_interval_t predelay; //21
};
#pragma pack()
//-----------------------------------------------------------------------------
// Purpose: Generic container for a response to a match to a criteria set
// This is what searching for a response returns
//-----------------------------------------------------------------------------
enum ResponseType_t
{
RESPONSE_NONE = 0,
RESPONSE_SPEAK,
RESPONSE_SENTENCE,
RESPONSE_SCENE,
RESPONSE_RESPONSE, // A reference to another response by name
RESPONSE_PRINT,
NUM_RESPONSES,
};
class AI_Response
{
public:
DECLARE_SIMPLE_DATADESC();
AI_Response();
AI_Response( const AI_Response &from );
~AI_Response();
AI_Response &operator=( const AI_Response &from );
void Release();
void GetName( char *buf, size_t buflen ) const;
void GetResponse( char *buf, size_t buflen ) const;
const AI_ResponseParams *GetParams() const { return &m_Params; }
ResponseType_t GetType() const { return (ResponseType_t)m_Type; }
soundlevel_t GetSoundLevel() const;
float GetRespeakDelay() const;
float GetWeaponDelay() const;
bool GetSpeakOnce() const;
bool ShouldntUseScene( ) const;
bool ShouldBreakOnNonIdle( void ) const;
int GetOdds() const;
float GetDelay() const;
float GetPreDelay() const;
void SetContext( const char *context );
const char * GetContext( void ) const { return m_szContext; }
bool IsApplyContextToWorld( void ) { return m_bApplyContextToWorld; }
void Describe();
const AI_CriteriaSet* GetCriteria();
void Init( ResponseType_t type,
const char *responseName,
const AI_CriteriaSet& criteria,
const AI_ResponseParams& responseparams,
const char *matchingRule,
const char *applyContext,
bool bApplyContextToWorld );
static const char *DescribeResponse( ResponseType_t type );
enum
{
MAX_RESPONSE_NAME = 64,
MAX_RULE_NAME = 64
};
private:
byte m_Type;
char m_szResponseName[ MAX_RESPONSE_NAME ];
char m_szMatchingRule[ MAX_RULE_NAME ];
// The initial criteria to which we are responsive
AI_CriteriaSet *m_pCriteria;
AI_ResponseParams m_Params;
char * m_szContext;
bool m_bApplyContextToWorld;
};
#endif // AI_CRITERIA_H

View File

@@ -0,0 +1,139 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hooks and classes for the support of humanoid NPCs with
// groovy facial animation capabilities, aka, "Actors"
//
//=============================================================================//
#include "cbase.h"
#include "AI_Interest_Target.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
bool CAI_InterestTarget_t::IsThis( CBaseEntity *pThis )
{
return (pThis == m_hTarget);
};
const Vector &CAI_InterestTarget_t::GetPosition( void )
{
if (m_eType == LOOKAT_ENTITY && m_hTarget != NULL)
{
m_vecPosition = m_hTarget->EyePosition();
}
return m_vecPosition;
};
bool CAI_InterestTarget_t::IsActive( void )
{
if (m_flEndTime < gpGlobals->curtime) return false;
if (m_eType == LOOKAT_ENTITY && m_hTarget == NULL) return false;
return true;
};
float CAI_InterestTarget_t::Interest( void )
{
float t = (gpGlobals->curtime - m_flStartTime) / (m_flEndTime - m_flStartTime);
if (t < 0.0f || t > 1.0f)
return 0.0f;
if (m_flRamp && t < 1 - m_flRamp)
{
//t = t / m_flRamp;
t = 1.0 - ExponentialDecay( 0.2, m_flRamp, t );
//t = 1.0 - ExponentialDecay( 0.01, 1 - m_flRamp, t );
}
else if (t > 1.0f - m_flRamp)
{
t = (1.0 - t) / m_flRamp;
t = 3.0f * t * t - 2.0f * t * t * t;
}
else
{
t = 1.0f;
}
// ramp
t *= m_flInterest;
return t;
}
void CAI_InterestTarget::Add( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp )
{
int i;
for (i = 0; i < Count(); i++)
{
CAI_InterestTarget_t &target = Element( i );
if (target.m_hTarget == pTarget && target.m_flRamp == 0)
{
if (target.m_flStartTime == gpGlobals->curtime)
{
flImportance = MAX( flImportance, target.m_flInterest );
}
Remove( i );
break;
}
}
Add( CAI_InterestTarget_t::LOOKAT_ENTITY, pTarget, Vector( 0, 0, 0 ), flImportance, flDuration, flRamp );
}
void CAI_InterestTarget::Add( const Vector &vecPosition, float flImportance, float flDuration, float flRamp )
{
int i;
for (i = 0; i < Count(); i++)
{
CAI_InterestTarget_t &target = Element( i );
if (target.m_vecPosition == vecPosition)
{
Remove( i );
break;
}
}
Add( CAI_InterestTarget_t::LOOKAT_POSITION, NULL, vecPosition, flImportance, flDuration, flRamp );
}
void CAI_InterestTarget::Add( CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp )
{
int i;
for (i = 0; i < Count(); i++)
{
CAI_InterestTarget_t &target = Element( i );
if (target.m_hTarget == pTarget)
{
if (target.m_flStartTime == gpGlobals->curtime)
{
flImportance = MAX( flImportance, target.m_flInterest );
}
Remove( i );
break;
}
}
Add( CAI_InterestTarget_t::LOOKAT_BOTH, pTarget, vecPosition, flImportance, flDuration, flRamp );
}
void CAI_InterestTarget::Add( CAI_InterestTarget_t::CAI_InterestTarget_e type, CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp )
{
int i = AddToTail();
CAI_InterestTarget_t &target = Element( i );
target.m_eType = type;
target.m_hTarget = pTarget;
target.m_vecPosition = vecPosition;
target.m_flInterest = flImportance;
target.m_flStartTime = gpGlobals->curtime;
target.m_flEndTime = gpGlobals->curtime + flDuration;
target.m_flRamp = flRamp / flDuration;
}

View File

@@ -0,0 +1,88 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Hooks and classes for the support of humanoid NPCs with
// groovy facial animation capabilities, aka, "Actors"
//
//=============================================================================//
#ifndef AI_INTEREST_TARGET_H
#define AI_INTEREST_TARGET_H
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
// CAI_BaseActor
//
// Purpose: The base class for all facially expressive NPCS.
//
//-----------------------------------------------------------------------------
class CAI_InterestTarget_t
{
public:
enum CAI_InterestTarget_e
{
LOOKAT_ENTITY = 0,
LOOKAT_POSITION,
LOOKAT_BOTH
};
public:
bool IsThis( CBaseEntity *pThis );
const Vector &GetPosition( void );
bool IsActive( void );
float Interest( void );
public:
CAI_InterestTarget_e m_eType; // ????
EHANDLE m_hTarget;
Vector m_vecPosition;
float m_flStartTime;
float m_flEndTime;
float m_flRamp;
float m_flInterest;
DECLARE_SIMPLE_DATADESC();
};
class CAI_InterestTarget : public CUtlVector<CAI_InterestTarget_t>
{
public:
void Add( CBaseEntity *pTarget, float flImportance, float flDuration, float flRamp );
void Add( const Vector &vecPosition, float flImportance, float flDuration, float flRamp );
void Add( CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp );
int Find( CBaseEntity *pTarget )
{
int i;
for ( i = 0; i < Count(); i++)
{
if (pTarget == (*this)[i].m_hTarget)
return i;
}
return InvalidIndex();
}
void Cleanup( void )
{
int i;
for (i = Count() - 1; i >= 0; i--)
{
if (!Element(i).IsActive())
{
Remove( i );
}
}
};
private:
void Add( CAI_InterestTarget_t::CAI_InterestTarget_e type, CBaseEntity *pTarget, const Vector &vecPosition, float flImportance, float flDuration, float flRamp );
};
//-----------------------------------------------------------------------------
#endif // AI_INTEREST_TARGET_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AI_RESPONSESYSTEM_H
#define AI_RESPONSESYSTEM_H
#include "utlvector.h"
#ifdef _WIN32
#pragma once
#endif
#include "AI_Criteria.h"
abstract_class IResponseFilter
{
public:
virtual bool IsValidResponse( ResponseType_t type, const char *pszValue ) = 0;
};
abstract_class IResponseSystem
{
public:
virtual ~IResponseSystem() {}
virtual bool FindBestResponse( const AI_CriteriaSet& set, AI_Response& response, IResponseFilter *pFilter = NULL ) = 0;
virtual void GetAllResponses( CUtlVector<AI_Response *> *pResponses ) = 0;
virtual void PrecacheResponses( bool bEnable ) = 0;
};
IResponseSystem *PrecacheCustomResponseSystem( const char *scriptfile );
IResponseSystem *BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore );
void DestroyCustomResponseSystems();
class ISaveRestoreBlockHandler *GetDefaultResponseSystemSaveRestoreBlockHandler();
class ISaveRestoreOps *GetResponseSystemSaveRestoreOps();
#endif // AI_RESPONSESYSTEM_H

268
game/server/AR2Bullet.cpp Normal file
View File

@@ -0,0 +1,268 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "AR2Bullet.h"
#include "soundent.h"
#include "decals.h"
#include "shake.h"
#include "smoke_trail.h"
#include "ar2_explosion.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "world.h"
#include "particle_parse.h"//OverCharged
#ifdef PORTAL
#include "portal_util_shared.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define NO_COLLIDE_TIME 0.2
#define AR2_GRENADE_MAX_DANGER_RADIUS 300
extern short g_sModelIndexFireball; // (in combatweapon.cpp) holds the index for the smoke cloud
// Moved to HL2_SharedGameRules because these are referenced by shared AmmoDef functions
ConVar sk_plr_dmg_ar2_bullet("sk_plr_dmg_ar2_bullet", "90");
ConVar sk_npc_dmg_ar2_bullet("sk_npc_dmg_ar2_bullet", "20");
ConVar sk_max_ar2_bullet("sk_max_ar2_bullet", "2000");
ConVar sk_ar2_bullet_radius("sk_ar2_bullet_radius", "0");
ConVar g_CV_SmokeTrail_ar2("smoke_trail_ar2", "1", 0); // temporary dust explosion switch
BEGIN_DATADESC(CAR2Bullet)
DEFINE_FIELD(m_hSmokeTrail, FIELD_EHANDLE),
DEFINE_FIELD(m_fSpawnTime, FIELD_TIME),
DEFINE_FIELD(m_fDangerRadius, FIELD_FLOAT),
// Function pointers
DEFINE_ENTITYFUNC(AR2BulletTouch),
DEFINE_THINKFUNC(AR2BulletThink),
END_DATADESC()
LINK_ENTITY_TO_CLASS(ar2bullet, CAR2Bullet);
void CAR2Bullet::Spawn(void)
{
Precache();
SetSolid(SOLID_BBOX);
// SetMoveType(MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE);
SetMoveType(MOVETYPE_FLYGRAVITY);
// Hits everything but debris
SetCollisionGroup(COLLISION_GROUP_PROJECTILE);
SetModel("models/Weapons/ar2_grenade.mdl");
UTIL_SetSize(this, Vector(-1, -1, -1), Vector(1, 1, 1));
// UTIL_SetSize(this, Vector(0, 0, 0), Vector(0, 0, 0));
AddEffects(EF_NODRAW);
SetUse(&CAR2Bullet::DetonateUse);
SetTouch(&CAR2Bullet::AR2BulletTouch);
SetThink(&CAR2Bullet::AR2BulletThink);
SetNextThink(gpGlobals->curtime + 0.02f);
if (GetOwnerEntity() && GetOwnerEntity()->IsPlayer())
{
m_flDamage = sk_plr_dmg_ar2_bullet.GetFloat();
}
else
{
m_flDamage = sk_npc_dmg_ar2_bullet.GetFloat();
}
m_DmgRadius = sk_ar2_bullet_radius.GetFloat();
m_takedamage = DAMAGE_YES;
m_bIsLive = true;
m_iHealth = 1;
// SetGravity(UTIL_ScaleForGravity(100)); // use a lower gravity for grenades to make them easier to see
SetFriction(0.8);
SetSequence(0);
m_fDangerRadius = 100;
m_fSpawnTime = gpGlobals->curtime;
// UTIL_Tracer(vecOrigin, tr.endpos, 0, TRACER_DONT_USE_ATTACHMENT, 600, true, "StriderTracer");
// -------------//OverCharged
// Smoke trail.
// -------------
if (g_CV_SmokeTrail_ar2.GetInt() && !IsXbox())
{
DispatchParticleEffect("shell_exhaust_smoke", PATTACH_ABSORIGIN_FOLLOW, this); //<2F><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
/////////////////////////////<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>//////////////////////////////
/* m_hSmokeTrail = SmokeTrail::CreateSmokeTrail();
if( m_hSmokeTrail )
{
m_hSmokeTrail->m_SpawnRate = 48;
m_hSmokeTrail->m_ParticleLifetime = 1;
m_hSmokeTrail->m_StartColor.Init(0.1f, 0.1f, 0.1f);
m_hSmokeTrail->m_EndColor.Init(0,0,0);
m_hSmokeTrail->m_StartSize = 12;
m_hSmokeTrail->m_EndSize = m_hSmokeTrail->m_StartSize * 4;
m_hSmokeTrail->m_SpawnRadius = 4;
m_hSmokeTrail->m_MinSpeed = 4;
m_hSmokeTrail->m_MaxSpeed = 24;
m_hSmokeTrail->m_Opacity = 0.2f;
m_hSmokeTrail->SetLifetime(10.0f);
m_hSmokeTrail->FollowEntity(this);
}*/
///////////////////////////////////////////////////////////////////////////////////////////////
}
}
//-----------------------------------------------------------------------------
// Purpose: The grenade has a slight delay before it goes live. That way the
// person firing it can bounce it off a nearby wall. However if it
// hits another character it blows up immediately
// Input :
// Output :
//-----------------------------------------------------------------------------
void CAR2Bullet::AR2BulletThink(void)
{
SetNextThink(gpGlobals->curtime + 0.01f);
if (!m_bIsLive)
{
// Go live after a short delay
if (m_fSpawnTime + NO_COLLIDE_TIME < gpGlobals->curtime)
{
m_bIsLive = true;
}
}
// If I just went solid and my velocity is zero, it means I'm resting on
// the floor already when I went solid so blow up
if (m_bIsLive)
{
if (GetAbsVelocity().Length() == 0.0 ||
GetGroundEntity() != NULL)
{
Detonate();
}
}
// The old way of making danger sounds would scare the crap out of EVERYONE between you and where the grenade
// was going to hit. The radius of the danger sound now 'blossoms' over the grenade's lifetime, making it seem
// dangerous to a larger area downrange than it does from where it was fired.
if (m_fDangerRadius <= AR2_GRENADE_MAX_DANGER_RADIUS)
{
m_fDangerRadius += (AR2_GRENADE_MAX_DANGER_RADIUS * 0.05);
}
CPASFilter filter(GetAbsOrigin());
te->DynamicLight(filter, 0.0, &GetAbsOrigin(), 255, 95, 55, 8, 100, 0.1, 0);//OverCharged
CSoundEnt::InsertSound(SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * 0.5, m_fDangerRadius, 0.2, this, SOUNDENT_CHANNEL_REPEATED_DANGER);
}
void CAR2Bullet::Event_Killed(const CTakeDamageInfo &info)
{
Detonate();
}
void CAR2Bullet::AR2BulletTouch(CBaseEntity *pOther)
{
Assert(pOther);
if (!pOther->IsSolid())
return;
// If I'm live go ahead and blow up
if (m_bIsLive)
{
Detonate();
}
else
{
// If I'm not live, only blow up if I'm hitting an chacter that
// is not the owner of the weapon
CBaseCombatCharacter *pBCC = ToBaseCombatCharacter(pOther);
if (pBCC && GetThrower() != pBCC)
{
m_bIsLive = true;
Detonate();
}
}
}
void CAR2Bullet::Detonate(void)
{
if (!m_bIsLive)
{
return;
}
m_bIsLive = false;
m_takedamage = DAMAGE_NO;
if (m_hSmokeTrail)
{
UTIL_Remove(m_hSmokeTrail);
m_hSmokeTrail = NULL;
}
CPASFilter filter(GetAbsOrigin());
te->Explosion(filter, 0.0,
&GetAbsOrigin(),
g_sModelIndexFireball,
2.0,
15,
TE_EXPLFLAG_NONE,
m_DmgRadius,
m_flDamage);
Vector vecForward = GetAbsVelocity();
VectorNormalize(vecForward);
trace_t tr;
UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() + 60 * vecForward, MASK_SHOT,
this, COLLISION_GROUP_NONE, &tr);
if ((tr.m_pEnt != GetWorldEntity()) || (tr.hitbox != 0))
{
// non-world needs smaller decals
if (tr.m_pEnt && !tr.m_pEnt->IsNPC())
{
UTIL_DecalTrace(&tr, "SmallScorch");
}
}
else
{
UTIL_DecalTrace(&tr, "Scorch");
}
UTIL_ScreenShake(GetAbsOrigin(), 25.0, 150.0, 1.0, 750, SHAKE_START);
DispatchParticleEffect("explosion_turret_break", GetAbsOrigin(), GetAbsAngles());//OverCharged
// DispatchParticleEffect("grenade_explosion_01", GetAbsOrigin(), GetAbsAngles());//OverCharged
te->DynamicLight(filter, 0.0, &GetAbsOrigin(), 255, 95, 55, 8, 100, 0.1, 0);//OverCharged
RadiusDamage(CTakeDamageInfo(this, GetThrower(), m_flDamage, DMG_BLAST), GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL);
UTIL_Remove(this);
}
void CAR2Bullet::Precache(void)
{
PrecacheModel("models/Weapons/ar2_grenade.mdl");
}
CAR2Bullet::CAR2Bullet(void)
{
m_hSmokeTrail = NULL;
}

47
game/server/AR2Bullet.h Normal file
View File

@@ -0,0 +1,47 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Projectile shot from the AR2
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef AR2_BULLET_H
#define AR2_BULLET_H
#include "basegrenade_shared.h"
#define MAX_AR2_NO_COLLIDE_TIME 0.2
class SmokeTrail;
class CWeaponSMG1;
class CAR2Bullet : public CBaseGrenade
{
public:
DECLARE_CLASS(CAR2Bullet, CBaseGrenade);
CHandle< SmokeTrail > m_hSmokeTrail;
float m_fSpawnTime;
float m_fDangerRadius;
void Spawn(void);
void Precache(void);
void AR2BulletTouch(CBaseEntity *pOther);
void AR2BulletThink(void);
void Event_Killed(const CTakeDamageInfo &info);
public:
void EXPORT Detonate(void);
CAR2Bullet(void);
DECLARE_DATADESC();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,232 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// #include "BaseAnimating.h"
#ifndef BASE_ANIMATING_OVERLAY_H
#define BASE_ANIMATING_OVERLAY_H
#ifdef _WIN32
#pragma once
#endif
class CBaseAnimatingOverlay;
class CAnimationLayer
{
public:
DECLARE_CLASS_NOBASE( CAnimationLayer );
CAnimationLayer( void );
void Init( CBaseAnimatingOverlay *pOverlay );
// float SetBlending( int iBlender, float flValue, CBaseAnimating *pOwner );
void StudioFrameAdvance( float flInterval, CBaseAnimating *pOwner );
void DispatchAnimEvents( CBaseAnimating *eventHandler, CBaseAnimating *pOwner );
void SetOrder( int nOrder );
float GetFadeout( float flCurTime );
// For CNetworkVars.
void NetworkStateChanged();
void NetworkStateChanged( void *pVar );
public:
#define ANIM_LAYER_ACTIVE 0x0001
#define ANIM_LAYER_AUTOKILL 0x0002
#define ANIM_LAYER_KILLME 0x0004
#define ANIM_LAYER_DONTRESTORE 0x0008
#define ANIM_LAYER_CHECKACCESS 0x0010
#define ANIM_LAYER_DYING 0x0020
int m_fFlags;
bool m_bSequenceFinished;
bool m_bLooping;
CNetworkVar( int, m_nSequence );
CNetworkVar( float, m_flCycle );
CNetworkVar( float, m_flPrevCycle );
CNetworkVar( float, m_flWeight );
float m_flPlaybackRate;
float m_flBlendIn; // start and end blend frac (0.0 for now blend)
float m_flBlendOut;
float m_flKillRate;
float m_flKillDelay;
float m_flLayerAnimtime;
float m_flLayerFadeOuttime;
// For checking for duplicates
Activity m_nActivity;
// order of layering on client
int m_nPriority;
CNetworkVar( int, m_nOrder );
bool IsActive( void ) { return ((m_fFlags & ANIM_LAYER_ACTIVE) != 0); }
bool IsAutokill( void ) { return ((m_fFlags & ANIM_LAYER_AUTOKILL) != 0); }
bool IsKillMe( void ) { return ((m_fFlags & ANIM_LAYER_KILLME) != 0); }
bool IsAutoramp( void ) { return (m_flBlendIn != 0.0 || m_flBlendOut != 0.0); }
void KillMe( void ) { m_fFlags |= ANIM_LAYER_KILLME; }
void Dying( void ) { m_fFlags |= ANIM_LAYER_DYING; }
bool IsDying( void ) { return ((m_fFlags & ANIM_LAYER_DYING) != 0); }
void Dead( void ) { m_fFlags &= ~ANIM_LAYER_DYING; }
bool IsAbandoned( void );
void MarkActive( void );
float m_flLastEventCheck;
float m_flLastAccess;
// Network state changes get forwarded here.
CBaseAnimatingOverlay *m_pOwnerEntity;
DECLARE_SIMPLE_DATADESC();
};
inline float CAnimationLayer::GetFadeout( float flCurTime )
{
float s;
if (m_flLayerFadeOuttime <= 0.0f)
{
s = 0;
}
else
{
// blend in over 0.2 seconds
s = 1.0 - (flCurTime - m_flLayerAnimtime) / m_flLayerFadeOuttime;
if (s > 0 && s <= 1.0)
{
// do a nice spline curve
s = 3 * s * s - 2 * s * s * s;
}
else if ( s > 1.0f )
{
// Shouldn't happen, but maybe curtime is behind animtime?
s = 1.0f;
}
}
return s;
}
class CBaseAnimatingOverlay : public CBaseAnimating
{
DECLARE_CLASS( CBaseAnimatingOverlay, CBaseAnimating );
public:
enum
{
MAX_OVERLAYS = 15,
};
private:
CUtlVector< CAnimationLayer > m_AnimOverlay;
//int m_nActiveLayers;
//int m_nActiveBaseLayers;
public:
virtual void OnRestore();
virtual void StudioFrameAdvance();
virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler );
virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask );
int AddGestureSequence( int sequence, bool autokill = true );
int AddGestureSequence( int sequence, float flDuration, bool autokill = true );
int AddGesture( Activity activity, bool autokill = true );
int AddGesture( Activity activity, float flDuration, bool autokill = true );
bool IsPlayingGesture( Activity activity );
void RestartGesture( Activity activity, bool addifmissing = true, bool autokill = true );
void RestartGestureOVR(Activity activity, bool addifmissing = true, bool autokill = true);
void RemoveGesture( Activity activity );
void RemoveAllGestures( void );
int AddLayeredSequence( int sequence, int iPriority );
void SetLayerPriority( int iLayer, int iPriority );
bool IsValidLayer( int iLayer );
void SetLayerDuration( int iLayer, float flDuration );
float GetLayerDuration( int iLayer );
void SetLayerCycle( int iLayer, float flCycle );
void SetLayerCycle( int iLayer, float flCycle, float flPrevCycle );
float GetLayerCycle( int iLayer );
void SetLayerPlaybackRate( int iLayer, float flPlaybackRate );
void SetLayerWeight( int iLayer, float flWeight );
float GetLayerWeight( int iLayer );
void SetLayerBlendIn( int iLayer, float flBlendIn );
void SetLayerBlendOut( int iLayer, float flBlendOut );
void SetLayerAutokill( int iLayer, bool bAutokill );
void SetLayerLooping( int iLayer, bool bLooping );
void SetLayerNoRestore( int iLayer, bool bNoRestore );
Activity GetLayerActivity( int iLayer );
int GetLayerSequence( int iLayer );
int FindGestureLayer( Activity activity );
void RemoveLayer( int iLayer, float flKillRate = 0.2, float flKillDelay = 0.0 );
void FastRemoveLayer( int iLayer );
CAnimationLayer *GetAnimOverlay( int iIndex );
int GetNumAnimOverlays() const;
void SetNumAnimOverlays( int num );
void VerifyOrder( void );
bool HasActiveLayer( void );
private:
int AllocateLayer( int iPriority = 0 ); // lower priorities are processed first
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
DECLARE_PREDICTABLE();
};
EXTERN_SEND_TABLE(DT_BaseAnimatingOverlay);
inline int CBaseAnimatingOverlay::GetNumAnimOverlays() const
{
return m_AnimOverlay.Count();
}
// ------------------------------------------------------------------------------------------ //
// CAnimationLayer inlines.
// ------------------------------------------------------------------------------------------ //
inline void CAnimationLayer::SetOrder( int nOrder )
{
m_nOrder = nOrder;
}
inline void CAnimationLayer::NetworkStateChanged()
{
if ( m_pOwnerEntity )
m_pOwnerEntity->NetworkStateChanged();
}
inline void CAnimationLayer::NetworkStateChanged( void *pVar )
{
if ( m_pOwnerEntity )
m_pOwnerEntity->NetworkStateChanged();
}
#endif // BASE_ANIMATING_OVERLAY_H

310
game/server/BasePropDoor.h Normal file
View File

@@ -0,0 +1,310 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A base class for model-based doors. The exact movement required to
// open or close the door is not dictated by this class, only that
// the door has open, closed, opening, and closing states.
//
// Doors must satisfy these requirements:
//
// - Derived classes must support being opened by NPCs.
// - Never autoclose in the face of a player.
// - Never close into an NPC.
//
//=============================================================================//
#ifndef BASEPROPDOOR_H
#define BASEPROPDOOR_H
#ifdef _WIN32
#pragma once
#endif
#include "props.h"
#include "locksounds.h"
#include "entityoutput.h"
extern ConVar g_debug_doors;
struct opendata_t
{
Vector vecStandPos; // Where the NPC should stand.
Vector vecFaceDir; // What direction the NPC should face.
Activity eActivity; // What activity the NPC should play.
};
abstract_class CBasePropDoor : public CDynamicProp
{
public:
DECLARE_CLASS( CBasePropDoor, CDynamicProp );
DECLARE_SERVERCLASS();
CBasePropDoor( void );
void Spawn();
void Precache();
void Activate();
int ObjectCaps();
void HandleAnimEvent( animevent_t *pEvent );
// Base class services.
// Do not make the functions in this block virtual!!
// {
inline bool IsDoorOpen();
inline bool IsDoorAjar();
inline bool IsDoorOpening();
inline bool IsDoorClosed();
inline bool IsDoorClosing();
inline bool IsDoorLocked();
inline bool IsDoorBlocked() const;
inline bool IsNPCOpening(CAI_BaseNPC *pNPC);
inline bool IsPlayerOpening();
inline bool IsOpener(CBaseEntity *pEnt);
bool NPCOpenDoor(CAI_BaseNPC *pNPC);
bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace );
// }
// Implement these in your leaf class.
// {
virtual bool DoorCanClose( bool bAutoClose ) { return true; }
virtual bool DoorCanOpen( void ) { return true; }
virtual void GetNPCOpenData(CAI_BaseNPC *pNPC, opendata_t &opendata) = 0;
virtual float GetOpenInterval(void) = 0;
// }
void Kick(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void TakeKick(const CTakeDamageInfo &info);
protected:
enum DoorState_t
{
DOOR_STATE_CLOSED = 0,
DOOR_STATE_OPENING,
DOOR_STATE_OPEN,
DOOR_STATE_CLOSING,
DOOR_STATE_AJAR,
};
// dvs: FIXME: make these private
void DoorClose();
CBasePropDoor *GetMaster( void ) { return m_hMaster; }
bool HasSlaves( void ) { return ( m_hDoorList.Count() > 0 ); }
inline void SetDoorState( DoorState_t eDoorState );
float m_flAutoReturnDelay; // How many seconds to wait before automatically closing, -1 never closes automatically.
CUtlVector< CHandle< CBasePropDoor > > m_hDoorList; // List of doors linked to us
inline CBaseEntity *GetActivator();
private:
// Implement these in your leaf class.
// {
// Called when the door becomes fully open.
virtual void OnDoorOpened() {}
// Called when the door becomes fully closed.
virtual void OnDoorClosed() {}
// Called to tell the door to start opening.
virtual void BeginOpening(CBaseEntity *pOpenAwayFrom) = 0;
virtual void BeginKicked(CBaseEntity *pOpenAwayFrom) = 0;
// Called to tell the door to start closing.
virtual void BeginClosing( void ) = 0;
// Called when blocked to tell the door to stop moving.
virtual void DoorStop( void ) = 0;
// Called when blocked to tell the door to continue moving.
virtual void DoorResume( void ) = 0;
// Called to send the door instantly to its spawn positions.
virtual void DoorTeleportToSpawnPosition() = 0;
// }
private:
// Main entry points for the door base behaviors.
// Do not make the functions in this block virtual!!
// {
bool DoorActivate();
void DoorOpen( CBaseEntity *pOpenAwayFrom );
void DoorKicked(CBaseEntity *pOpenAwayFrom);
void OpenIfUnlocked(CBaseEntity *pActivator, CBaseEntity *pOpenAwayFrom);
void DoorOpenMoveDone();
void DoorCloseMoveDone();
void DoorAutoCloseThink();
void Lock();
void Unlock();
void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void OnUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
inline bool WillAutoReturn() { return m_flAutoReturnDelay != -1; }
void StartBlocked(CBaseEntity *pOther);
void OnStartBlocked( CBaseEntity *pOther );
void MasterStartBlocked( CBaseEntity *pOther );
void Blocked(CBaseEntity *pOther);
void EndBlocked(void);
void OnEndBlocked( void );
void UpdateAreaPortals(bool bOpen);
// Input handlers
void InputClose(inputdata_t &inputdata);
void InputLock(inputdata_t &inputdata);
void InputOpen(inputdata_t &inputdata);
void InputOpenAwayFrom(inputdata_t &inputdata);
void InputToggle(inputdata_t &inputdata);
void InputUnlock(inputdata_t &inputdata);
// Player kick
void InputKickable(inputdata_t &inputdata);
void InputNotKickable(inputdata_t &inputdata);
void InputKickableNPC(inputdata_t &inputdata);
void InputNotKickableNPC(inputdata_t &inputdata);
void SetDoorBlocker( CBaseEntity *pBlocker );
void SetMaster( CBasePropDoor *pMaster ) { m_hMaster = pMaster; }
void CalcDoorSounds();
// }
int m_nHardwareType;
DoorState_t m_eDoorState; // Holds whether the door is open, closed, opening, or closing.
locksound_t m_ls; // The sounds the door plays when being locked, unlocked, etc.
EHANDLE m_hActivator;
bool m_bLocked; // True if the door is locked.
EHANDLE m_hBlocker; // Entity blocking the door currently
bool m_bFirstBlocked; // Marker for being the first door (in a group) to be blocked (needed for motion control)
bool m_bForceClosed; // True if this door must close no matter what.
string_t m_SoundMoving;
string_t m_SoundOpen;
string_t m_SoundClose;
string_t m_SoundKickOpen; // player kick
string_t m_SoundKickFail;
// dvs: FIXME: can we remove m_flSpeed from CBaseEntity?
//float m_flSpeed; // Rotation speed when opening or closing in degrees per second.
DECLARE_DATADESC();
string_t m_SlaveName;
CHandle< CBasePropDoor > m_hMaster;
static void RegisterPrivateActivities();
// Outputs
COutputEvent m_OnBlockedClosing; // Triggered when the door becomes blocked while closing.
COutputEvent m_OnBlockedOpening; // Triggered when the door becomes blocked while opening.
COutputEvent m_OnUnblockedClosing; // Triggered when the door becomes unblocked while closing.
COutputEvent m_OnUnblockedOpening; // Triggered when the door becomes unblocked while opening.
COutputEvent m_OnFullyClosed; // Triggered when the door reaches the fully closed position.
COutputEvent m_OnFullyOpen; // Triggered when the door reaches the fully open position.
COutputEvent m_OnClose; // Triggered when the door is told to close.
COutputEvent m_OnOpen; // Triggered when the door is told to open.
COutputEvent m_OnLockedUse; // Triggered when the user tries to open a locked door.
// BriJee: Overcharged ADDED breakable doors
COutputEvent m_OnBroken; // Triggered when the door gets broken
COutputEvent m_OnKickFail; // Triggered when the door gets kicked, but not broken
public:
bool AreWeLocked(void);
bool IsMyDoorLock(CBaseEntity *pLock);
void BreakDoors(Vector vecOrigin, AngularImpulse angImpulse);
void BreakDoor(Vector vecOrigin, AngularImpulse angImpulse);
void KickFail(void); // player kick
void PlayBreakOpenSound(void) {
EmitSound(STRING(m_SoundKickOpen));
}
void PlayBreakFailSound(void) {
EmitSound(STRING(m_SoundKickFail));
}
CBasePropDoor *HLSS_GetMaster(void) { return m_hMaster; }
};
void CBasePropDoor::SetDoorState( DoorState_t eDoorState )
{
m_eDoorState = eDoorState;
}
bool CBasePropDoor::IsDoorOpen()
{
return m_eDoorState == DOOR_STATE_OPEN;
}
bool CBasePropDoor::IsDoorAjar()
{
return ( m_eDoorState == DOOR_STATE_AJAR );
}
bool CBasePropDoor::IsDoorOpening()
{
return m_eDoorState == DOOR_STATE_OPENING;
}
bool CBasePropDoor::IsDoorClosed()
{
return m_eDoorState == DOOR_STATE_CLOSED;
}
bool CBasePropDoor::IsDoorClosing()
{
return m_eDoorState == DOOR_STATE_CLOSING;
}
bool CBasePropDoor::IsDoorLocked()
{
return m_bLocked;
}
CBaseEntity *CBasePropDoor::GetActivator()
{
return m_hActivator;
}
bool CBasePropDoor::IsDoorBlocked() const
{
return ( m_hBlocker != NULL );
}
bool CBasePropDoor::IsNPCOpening( CAI_BaseNPC *pNPC )
{
return ( pNPC == ( CAI_BaseNPC * )GetActivator() );
}
inline bool CBasePropDoor::IsPlayerOpening()
{
return ( GetActivator() && GetActivator()->IsPlayer() );
}
inline bool CBasePropDoor::IsOpener(CBaseEntity *pEnt)
{
return ( GetActivator() == pEnt );
}
#endif // BASEPROPDOOR_H

View File

@@ -0,0 +1,495 @@
#include "cbase.h"
#include "BloodEmitter.h"
#include "soundent.h"
#include "decals.h"
#include "shake.h"
#include "smoke_trail.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "world.h"
#include "BloodDripsGreen.h"
#include "hl2_shareddefs.h"
#include "te_effect_dispatch.h"
#include "IEffects.h"
#define BOLT_SKIN_NORMAL 0
#define BOLT_SKIN_GLOW 1
#define BOLT_MODEL oc_blood_drip_model.GetString() //"models/ShockRifle.mdl"
ConVar oc_blood_drip_model("oc_blood_drip_model", "models/spitball_small.mdl", FCVAR_REPLICATED | FCVAR_ARCHIVE, "Shock rifle projectile model.");
ConVar oc_blood_drip_maxcount("oc_blood_drip_maxcount", "0", FCVAR_ARCHIVE);
extern short g_sModelIndexFireball;
extern short g_sModelIndexWExplosion;
#define SPRITE "particles/particle_glow/particle_glow_03.vmt"
#if 0
LINK_ENTITY_TO_CLASS(blood_emitter, CBloodEmitter);
BEGIN_DATADESC(CBloodEmitter)
// Function Pointers
DEFINE_FUNCTION(BubbleThink),
//DEFINE_FUNCTION(BoltTouch),
// These are recreated on reload, they don't need storage
DEFINE_FIELD(m_hSpitEffectDD, FIELD_EHANDLE),
END_DATADESC()
//IMPLEMENT_SERVERCLASS_ST(CBloodEmitter, DT_BloodEmitter)
//END_SEND_TABLE()
CBloodEmitter *CBloodEmitter::BoltCreate(const Vector &vecOrigin, const QAngle &angAngles, int iDamage, CBasePlayer *pentOwner)
{
// Create a new entity with CShockRifleProjectile private data
CBloodEmitter *pBloodEmitter = (CBloodEmitter *)CreateEntityByName("blood_emitter");
UTIL_SetOrigin(pBloodEmitter, vecOrigin);
pBloodEmitter->SetAbsAngles(angAngles);
pBloodEmitter->Spawn();
pBloodEmitter->SetOwnerEntity(pentOwner);
pBloodEmitter->m_iDamage = iDamage;
return pBloodEmitter;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBloodEmitter::~CBloodEmitter(void)
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
/*bool CBloodEmitter::CreateVPhysics(void)
{
// Create the object in the physics system
VPhysicsInitNormal(SOLID_BBOX, FSOLID_NOT_STANDABLE, false);
return true;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
unsigned int CBloodEmitter::PhysicsSolidMaskForEntity() const
{
return (BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_HITBOX) & ~CONTENTS_GRATE;
}*/
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBloodEmitter::CreateSprites(void)
{
// Create the dust effect in place
m_hSpitEffectDD = (CParticleSystem *)CreateEntityByName("info_particle_system");
if (m_hSpitEffectDD != NULL)
{
// Setup our basic parameters
m_hSpitEffectDD->KeyValue("start_active", "1");
m_hSpitEffectDD->KeyValue("effect_name", "antlion_spit_trail");
m_hSpitEffectDD->SetParent(this);
m_hSpitEffectDD->SetLocalOrigin(vec3_origin);
DispatchSpawn(m_hSpitEffectDD);
if (gpGlobals->curtime > 0.5f)
m_hSpitEffectDD->Activate();
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBloodEmitter::Spawn(void)
{
Precache();
SetSolid(SOLID_NONE);
SetMoveType(MOVETYPE_NONE);
//SetSolidFlags(FSOLID_NOT_STANDABLE);
Vector SizeMin(0.2, 0.2, 0.2), SizeMax(1, 1, 1);
SetModel(BOLT_MODEL);
//SetModelScale(random->RandomFloat(0.01, 1), 0.0f);
UTIL_SetSize(this, SizeMin, SizeMax);
SetUse(&CBaseGrenade::DetonateUse);
SetTouch(&CBloodDripsGreen::BloodDripsGreenTouch);
SetNextThink(gpGlobals->curtime + 0.1f);
m_takedamage = DAMAGE_NO;
m_iHealth = 1;
//SetGravity(UTIL_ScaleForGravity(DRIPS_GRAVITY));
//SetFriction(0.8f);
//SetCollisionGroup(COLLISION_GROUP_NONE);
//AddEFlags(EFL_FORCE_CHECK_TRANSMIT);
// We're self-illuminating, so we don't take or give shadows
//AddEffects(EF_NOSHADOW | EF_NORECEIVESHADOW);
//SetTouch(&CBloodEmitter::BoltTouch);
SetThink(&CBloodEmitter::BubbleThink);
SetNextThink(gpGlobals->curtime + 0.02f);
CreateSprites();
// Make us glow until we've hit the wall
//m_nSkin = BOLT_SKIN_GLOW;
touched = true;
b_count = 0;
}
void CBloodEmitter::Precache(void)
{
PrecacheModel(BOLT_MODEL);
PrecacheParticleSystem("Shockrifle_sparks");
PrecacheParticleSystem("hunter_flechette_trail");
PrecacheModel("models/grenade.mdl");
PrecacheModel("models/spitball_large.mdl");
PrecacheModel("models/spitball_medium.mdl");
PrecacheModel("models/spitball_small.mdl");
PrecacheModel(SPRITE);
PrecacheScriptSound("GrenadeSpit.Hit");
PrecacheParticleSystem("Spore_launcher_acid_glow");
PrecacheParticleSystem("grenade_spit_player");
PrecacheParticleSystem("grenade_spit");
PrecacheParticleSystem("grenade_spit_trail");
PrecacheScriptSound("grenade_strooper_instant.Detonate");
PrecacheScriptSound("Weapon_spore_acid.hit");
PrecacheScriptSound("Weapon_spore_acid.bounce");
PrecacheScriptSound("Weapon_spore_acid.impact");
//BaseClass::Precache();
}
#if 0
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pOther -
//-----------------------------------------------------------------------------
void CBloodEmitter::BoltTouch(CBaseEntity *pOther)
{
if (pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS | FSOLID_TRIGGER))
{
// Some NPCs are triggers that can take damage (like antlion grubs). We should hit them.
if ((pOther->m_takedamage == DAMAGE_NO) || (pOther->m_takedamage == DAMAGE_EVENTS_ONLY))
return;
}
if (pOther->GetCollisionGroup() == HL2COLLISION_GROUP_SPIT)
return;
const trace_t *pTrace = &CBaseEntity::GetTouchTrace();
//bool bHitWater = ((pTrace->contents & CONTENTS_WATER) != 0);
//CBaseEntity *const pTraceEnt = pTrace->m_pEnt;
const Vector tracePlaneNormal = pTrace->plane.normal;
QAngle vecAngles;
VectorAngles(tracePlaneNormal, vecAngles);
touched = true;
//Detonate();
}
void CBloodEmitter::Detonate(void)
{
m_takedamage = DAMAGE_NO;
trace_t tr;
tr = CBaseEntity::GetTouchTrace();
for (int i = 0; i < cvar->FindVar("sk_spore_acid_maxdrips")->GetFloat(); i++)
{
Vector vecSpawn;
vecSpawn = this->WorldSpaceCenter();
/*vecSpawn.x += random->RandomFloat(-0.2, 0.2);
vecSpawn.y += random->RandomFloat(-12.1, 12.4);*/
//vecSpawn.z += 40;// random->RandomFloat(-20.1, 20.2);
Vector vecVelocity;
QAngle angles;
angles.x = random->RandomFloat(-360, 360);
angles.y = random->RandomFloat(-360, 360);
angles.z = random->RandomFloat(-360, 360);
AngleVectors(angles, &vecVelocity);
vecVelocity *= random->RandomFloat(150, 300);
vecVelocity -= GetAbsVelocity() / 14;
CBloodDripsGreen *pGrenade = (CBloodDripsGreen*)CreateEntityByName("BloodDripsGreen");
//pGrenade->SetAbsOrigin(vecTraceDir);
pGrenade->SetLocalOrigin(vecSpawn);
pGrenade->SetAbsAngles(RandomAngle(-360, 360));
DispatchSpawn(pGrenade);
pGrenade->SetOwnerEntity(this);
pGrenade->SetAbsVelocity(vecVelocity);
}
//CSoundEnt::InsertSound ( SOUND_COMBAT, GetAbsOrigin(), BASEGRENADE_EXPLOSION_VOLUME, 3.0 );
RadiusDamage(CTakeDamageInfo(this, this, m_flDamage, DMG_BULLET), GetAbsOrigin(), cvar->FindVar("sk_spore_acid_radius")->GetFloat(), CLASS_NONE, NULL);
CPASAttenuationFilter filter1(this);
EmitSound(filter1, entindex(), "Weapon_spore_acid.hit");
EmitSound(filter1, entindex(), "Weapon_spore_acid.impact");
float Radius = 110;
CPASFilter filter(GetAbsOrigin());
te->DynamicLight(filter, 0.0, &GetAbsOrigin(), random->RandomInt(10, 25), random->RandomInt(190, 255), random->RandomInt(25, 55), 3, Radius, random->RandomInt(0.018, 0.23), Radius / 0.5);//OverCharged
DispatchParticleEffect("grenade_spit", GetAbsOrigin(), GetAbsAngles());
m_hSpitEffectDD->StopParticleSystem();
UTIL_Remove(m_hSpitEffectDD);
StopParticleEffects(this);
UTIL_Remove(this);
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBloodEmitter::BubbleThink(void)
{
//QAngle angNewAngles;
//VectorAngles(GetAbsVelocity(), angNewAngles);
//SetAbsAngles(angNewAngles);
if (false)//(touched)
{
CreateChildDrips();
b_count++;
if (b_count >= oc_blood_drip_maxcount.GetInt())
{
touched = false;
b_count = 0;
UTIL_Remove(this);
}
}
SetNextThink(gpGlobals->curtime + 4.2f);
/*if (GetWaterLevel() == 0)
return;
//DispatchParticleEffect("Shockrifle_sparks", PATTACH_ABSORIGIN, NULL);
UTIL_Remove(this);*/ // BriJee OVR : Little trick to get entity killed in water
}
void CBloodEmitter::CreateChildDrips()
{
Vector vecSpawn;
vecSpawn = this->WorldSpaceCenter();
Vector vecVelocity;
QAngle angles;
angles.x = random->RandomFloat(-360, 360);
angles.y = random->RandomFloat(-360, 360);
angles.z = random->RandomFloat(-360, 360);
AngleVectors(angles, &vecVelocity);
vecVelocity *= random->RandomFloat(150, 300);
vecVelocity -= GetAbsVelocity() / 14;
CBloodDripsGreen *pGrenade = (CBloodDripsGreen*)CreateEntityByName("BloodDripsGreen");
//pGrenade->SetAbsOrigin(vecTraceDir);
pGrenade->SetModelScale(0.01f);
pGrenade->SetLocalOrigin(vecSpawn);
pGrenade->SetAbsAngles(RandomAngle(-360, 360));
DispatchSpawn(pGrenade);
pGrenade->SetOwnerEntity(this);
pGrenade->SetAbsVelocity(vecVelocity);
}
#endif
LINK_ENTITY_TO_CLASS(blood_emitter, CBloodEmitter);
/*BEGIN_DATADESC(CEndPoint)
// Function Pointers
DEFINE_FUNCTION(Spawn),
END_DATADESC()*/
//IMPLEMENT_SERVERCLASS_ST(CEndPoint, DT_EndPoint)
//END_SEND_TABLE()
CBloodEmitter *CBloodEmitter::DispatchImpactSound(const Vector &end)
{
CBloodEmitter *pPoint = (CBloodEmitter *)(CreateEntityByName("blood_emitter"));
UTIL_SetOrigin(pPoint, end);
//pPoint->SetAbsAngles(QAngle(0, 0, 0));
pPoint->Spawn();
//pPoint->SetOwnerEntity(pPoint);
return pPoint;
}
void CBloodEmitter::Precache(void)
{
//PrecacheModel("models/weapons/v_smg1_mmod.mdl");
//PrecacheScriptSound("Weapon_Gluon.Hit");
}
/*bool CBloodEmitter::CreateVPhysics(void)
{
VPhysicsInitNormal(SOLID_BBOX, FSOLID_NOT_STANDABLE, false);
return true;
}*/
void CBloodEmitter::Spawn(void)
{
Precache();
PrecacheModel("models/weapons/MAGS/w_rif_ak47_mag.mdl");
SetModel("models/weapons/MAGS/w_rif_ak47_mag.mdl");
SetMoveType(MOVETYPE_VPHYSICS);
SetSolid(SOLID_VPHYSICS);
SetCollisionGroup(COLLISION_GROUP_DEBRIS);
AddSpawnFlags(SF_PHYSBOX_ASLEEP);
UTIL_SetSize(this, Vector(-3, -3, -3), Vector(3, 3, 3));
SetThink(&CBloodEmitter::BubbleThink);
SetNextThink(gpGlobals->curtime + 0.02f);
//EmitSound("Weapon_Gluon.Hit");
CreateVPhysics();
thisPhysics = VPhysicsGetObject();
//UTIL_Remove(this);
touched = true;
b_count = 0;
}
void CBloodEmitter::BubbleThink(void)
{
if (touched)
{
//CreateChildDrips();
Vector origin = EyePosition();
Vector forward, rt, up;
QAngle angles = GetLocalAngles();
//AngleVectors(angles, &forward, &rt, &up);
GetVectors(&forward, &rt, &up);
origin += forward;
origin += rt;
origin += up;
forward *= 5.f;
CEffectData data;
data.m_vOrigin = origin;
data.m_vNormal = origin + forward;
data.m_vAngles = angles;
data.m_nAttachmentIndex = composeColor;
DispatchEffect("BloodDrips", data);
b_count++;
if (b_count >= oc_blood_drip_maxcount.GetInt())
{
touched = false;
b_count = 0;
UTIL_Remove(this);
}
}
SetNextThink(gpGlobals->curtime + timeThink);
}
void CBloodEmitter::CreateChildDrips()
{
Vector vecVelocity;
QAngle angles;
angles.x = random->RandomFloat(-360, 360);
angles.y = random->RandomFloat(-360, 360);
angles.z = random->RandomFloat(-360, 360);
AngleVectors(angles, &vecVelocity);
vecVelocity *= random->RandomFloat(10, 500);
vecVelocity -= GetAbsVelocity() / 14;
direction = direction * 0.9;
if (composeColor == 0)
{
CBloodDripsGreen *pGrenade = (CBloodDripsGreen*)CreateEntityByName("BloodDrips");
//pGrenade->SetAbsOrigin(vecTraceDir);
pGrenade->SetModelScale(0.01f);
VectorAngles(GetAbsOrigin(), angle);
pGrenade->SetAbsOrigin(GetAbsOrigin());
pGrenade->SetAbsAngles(angle);
DispatchSpawn(pGrenade);
//pGrenade->SetParent(this->GetParent());
//pGrenade->SetOwnerEntity(this->GetParent());
//pGrenade->ApplyLocalVelocityImpulse(this->GetLocalOrigin()*random->RandomInt(15, 35));
pGrenade->ApplyLocalVelocityImpulse(direction*random->RandomInt(15, 35));
}
else if (composeColor == 1 || composeColor == 2)
{
CBloodDripsGreen *pGrenade = (CBloodDripsGreen*)CreateEntityByName("BloodDripsGreen");
pGrenade->SetModelScale(0.01f);
VectorAngles(GetAbsOrigin(), angle);
pGrenade->SetAbsOrigin(GetAbsOrigin());
pGrenade->SetAbsAngles(angle);
DispatchSpawn(pGrenade);
//pGrenade->SetParent(this->GetParent());
//pGrenade->SetOwnerEntity(this->GetParent());
//pGrenade->ApplyLocalVelocityImpulse(this->GetLocalOrigin()*random->RandomInt(15, 35));
pGrenade->ApplyLocalVelocityImpulse(direction*random->RandomInt(15, 35));
}
else if (composeColor >= 3)
{
int rndmInt = random->RandomInt(0, 1);
if (rndmInt)
{
CBloodDripsGreen *pGrenade = (CBloodDripsGreen*)CreateEntityByName("BloodDrips");
//pGrenade->SetAbsOrigin(vecTraceDir);
pGrenade->SetModelScale(0.01f);
VectorAngles(GetAbsOrigin(), angle);
pGrenade->SetAbsOrigin(GetAbsOrigin());
pGrenade->SetAbsAngles(angle);
DispatchSpawn(pGrenade);
//pGrenade->SetParent(this->GetParent());
//pGrenade->SetOwnerEntity(this->GetParent());
//pGrenade->ApplyLocalVelocityImpulse(this->GetLocalOrigin()*random->RandomInt(15, 35));
pGrenade->ApplyLocalVelocityImpulse(direction*random->RandomInt(15, 35));
}
else
{
CBloodDripsGreen *pGrenade = (CBloodDripsGreen*)CreateEntityByName("BloodDripsGreen");
pGrenade->SetModelScale(0.01f);
VectorAngles(GetAbsOrigin(), angle);
pGrenade->SetAbsOrigin(GetAbsOrigin());
pGrenade->SetAbsAngles(angle);
DispatchSpawn(pGrenade);
//pGrenade->SetParent(this->GetParent());
//pGrenade->SetOwnerEntity(this->GetParent());
//pGrenade->ApplyLocalVelocityImpulse(this->GetLocalOrigin()*random->RandomInt(15, 35));
pGrenade->ApplyLocalVelocityImpulse(direction*random->RandomInt(15, 35));
}
}
}

View File

@@ -0,0 +1,76 @@
#ifndef BLOODEMITTER_H
#define BLOODEMITTER_H
//#include "items.h"
#include "sprite.h"
#include "particle_system.h"
#include "physobj.h"
class SmokeTrail;
#if 0
class CBloodEmitter : public CBaseEntity
{
DECLARE_CLASS(CBloodEmitter, CBaseCombatCharacter);
public:
CBloodEmitter() { };
~CBloodEmitter();
Class_T Classify(void) { return CLASS_NONE; }
public:
void Spawn(void);
void Precache(void);
void BubbleThink(void); // changed
//void BoltTouch(CBaseEntity *pOther);
void CreateChildDrips(void);
//virtual unsigned int PhysicsSolidMaskForEntity(void) const { return (BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_WATER); }
//bool CreateVPhysics(void);
//unsigned int PhysicsSolidMaskForEntity() const;
CBloodEmitter *BoltCreate(const Vector &vecOrigin, const QAngle &angAngles, int iDamage, CBasePlayer *pentOwner = NULL);
protected:
//void Detonate(void);
bool CreateSprites(void);
CHandle< CParticleSystem > m_hSpitEffectDD;
bool touched;
int b_count;
int m_iDamage;
float m_flDamage;
DECLARE_DATADESC();
//DECLARE_SERVERCLASS();
};
//#endif
#endif
class CBloodEmitter : public CBaseEntity
{
DECLARE_CLASS(CBloodEmitter, CBaseEntity);
//Class_T Classify(void) { return CLASS_NONE; }
public:
CBloodEmitter() { };
~CBloodEmitter() { };
void Precache(void);
//bool CreateVPhysics();
void Spawn(void);
void BubbleThink(void);
void CreateChildDrips(void);
CBloodEmitter *DispatchImpactSound(const Vector &end);
bool touched;
int b_count;
int composeColor;
float timeThink;
QAngle angle;
Vector spawn;
Vector normal;
Vector direction;
IPhysicsObject *thisPhysics;
/*protected:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();*/
};
#endif

View File

@@ -0,0 +1,222 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "game.h"
#include "CRagdollMagnet.h"
#include "cplane.h"
ConVar ai_debug_ragdoll_magnets( "ai_debug_ragdoll_magnets", "0");
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( phys_ragdollmagnet, CRagdollMagnet );
BEGIN_DATADESC( CRagdollMagnet )
DEFINE_KEYFIELD( m_radius, FIELD_FLOAT, "radius" ),
DEFINE_KEYFIELD( m_force, FIELD_FLOAT, "force" ),
DEFINE_KEYFIELD( m_axis, FIELD_VECTOR, "axis" ),
DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CRagdollMagnet::InputEnable( inputdata_t &inputdata )
{
Enable( true );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CRagdollMagnet::InputDisable( inputdata_t &inputdata )
{
Enable( false );
}
//-----------------------------------------------------------------------------
// Purpose: Find the ragdoll magnet entity that should pull this entity's ragdoll
// Input : *pNPC - the npc that's dying
// Output : CRagdollMagnet - the magnet that's best to use.
//
// NOTES:
//
// The nearest ragdoll magnet pulls me in IF:
// - Present
// - I'm within the magnet's RADIUS
// - LATER: There is clear line of sight from my center to the magnet
// - LATER: I'm not flagged to ignore ragdoll magnets
// - LATER: The magnet is not turned OFF
//-----------------------------------------------------------------------------
CRagdollMagnet *CRagdollMagnet::FindBestMagnet( CBaseEntity *pNPC )
{
CRagdollMagnet *pMagnet = NULL;
CRagdollMagnet *pBestMagnet;
float flClosestDist;
// Assume we won't find one.
pBestMagnet = NULL;
flClosestDist = FLT_MAX;
do
{
pMagnet = (CRagdollMagnet *)gEntList.FindEntityByClassname( pMagnet, "phys_ragdollmagnet" );
if( pMagnet && pMagnet->IsEnabled() )
{
if( pMagnet->m_target != NULL_STRING )
{
// if this magnet has a target, only affect that target!
if( pNPC->GetEntityName() == pMagnet->m_target )
{
return pMagnet;
}
else
{
continue;
}
}
float flDist;
flDist = pMagnet->DistToPoint( pNPC->WorldSpaceCenter() );
if( flDist < flClosestDist && flDist <= pMagnet->GetRadius() )
{
// This is the closest magnet that can pull this npc.
flClosestDist = flDist;
pBestMagnet = pMagnet;
}
}
} while( pMagnet );
return pBestMagnet;
}
//-----------------------------------------------------------------------------
// Purpose: Get the force that we should add to this NPC's ragdoll.
// Input : *pNPC -
// Output : Vector
//
// NOTE: This function assumes pNPC is within this magnet's radius.
//-----------------------------------------------------------------------------
Vector CRagdollMagnet::GetForceVector( CBaseEntity *pNPC )
{
Vector vecForceToApply;
if( IsBarMagnet() )
{
CPlane axis;
Vector vecForceDir;
Vector vecClosest;
CalcClosestPointOnLineSegment( pNPC->WorldSpaceCenter(), GetAbsOrigin(), m_axis, vecClosest, NULL );
vecForceDir = (vecClosest - pNPC->WorldSpaceCenter() );
VectorNormalize( vecForceDir );
vecForceToApply = vecForceDir * m_force;
}
else
{
Vector vecForce;
vecForce = GetAbsOrigin() - pNPC->WorldSpaceCenter();
VectorNormalize( vecForce );
vecForceToApply = vecForce * m_force;
}
if( ai_debug_ragdoll_magnets.GetBool() )
{
IPhysicsObject *pPhysObject;
pPhysObject = pNPC->VPhysicsGetObject();
if( pPhysObject )
{
Msg("Ragdoll magnet adding %f inches/sec to %s\n", m_force/pPhysObject->GetMass(), pNPC->GetClassname() );
}
}
return vecForceToApply;
}
//-----------------------------------------------------------------------------
// Purpose: How far away is this point? This is different for point and bar magnets
// Input : &vecPoint - the point
// Output : float - the dist
//-----------------------------------------------------------------------------
float CRagdollMagnet::DistToPoint( const Vector &vecPoint )
{
if( IsBarMagnet() )
{
// I'm a bar magnet, so the point's distance is really the plane constant.
// A bar magnet is a cylinder who's length is AbsOrigin() to m_axis, and whose
// diameter is m_radius.
// first we build two planes. The TOP and BOTTOM planes.
// the idea is that vecPoint must be on the right side of both
// planes to be affected by this particular magnet.
// TOP and BOTTOM planes can be visualized as the 'caps' of the cylinder
// that describes the bar magnet, and they point towards each other.
// We're making sure vecPoint is between the caps.
Vector vecAxis;
vecAxis = GetAxisVector();
VectorNormalize( vecAxis );
CPlane top, bottom;
bottom.InitializePlane( -vecAxis, m_axis );
top.InitializePlane( vecAxis, GetAbsOrigin() );
if( top.PointInFront( vecPoint ) && bottom.PointInFront( vecPoint ) )
{
// This point is between the two caps, so calculate the distance
// of vecPoint from the axis of the bar magnet
CPlane axis;
Vector vecUp;
Vector vecRight;
// Horizontal and Vertical distances.
float hDist, vDist;
// Need to get a vector that's right-hand to m_axis
VectorVectors( vecAxis, vecRight, vecUp );
//CrossProduct( vecAxis, vecUp, vecRight );
//VectorNormalize( vecRight );
//VectorNormalize( vecUp );
// Set up the plane to measure horizontal dist.
axis.InitializePlane( vecRight, GetAbsOrigin() );
hDist = fabs( axis.PointDist( vecPoint ) );
axis.InitializePlane( vecUp, GetAbsOrigin() );
vDist = fabs( axis.PointDist( vecPoint ) );
return MAX( hDist, vDist );
}
else
{
return FLT_MAX;
}
}
else
{
// I'm a point magnet. Just return dist
return ( GetAbsOrigin() - vecPoint ).Length();
}
}

View File

@@ -0,0 +1,45 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Used to influence the initial force for a dying NPC's ragdoll.
// Passive entity. Just represents position in the world, radius, force
//
// $NoKeywords: $
//=============================================================================//
#pragma once
#ifndef CRAGDOLLMAGNET_H
#define CRAGDOLLMAGNET_H
#define SF_RAGDOLLMAGNET_BAR 0x00000002 // this is a bar magnet.
class CRagdollMagnet : public CPointEntity
{
public:
DECLARE_CLASS( CRagdollMagnet, CPointEntity );
DECLARE_DATADESC();
Vector GetForceVector( CBaseEntity *pNPC );
float GetRadius( void ) { return m_radius; }
Vector GetAxisVector( void ) { return m_axis - GetAbsOrigin(); }
float DistToPoint( const Vector &vecPoint );
bool IsEnabled( void ) { return !m_bDisabled; }
int IsBarMagnet( void ) { return (m_spawnflags & SF_RAGDOLLMAGNET_BAR); }
static CRagdollMagnet *FindBestMagnet( CBaseEntity *pNPC );
void Enable( bool bEnable ) { m_bDisabled = !bEnable; }
// Inputs
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
private:
bool m_bDisabled;
float m_radius;
float m_force;
Vector m_axis;
};
#endif //CRAGDOLLMAGNET_H

View File

@@ -0,0 +1,314 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "Cguard_Sphere.h"
#include "soundent.h"
#include "decals.h"
#include "smoke_trail.h"
#include "hl2_shareddefs.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "particle_parse.h"
#include "particle_system.h"
#include "soundenvelope.h"
#include "ai_utils.h"
#include "te_effect_dispatch.h"
#include "OverCharged/weapon_cguard.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
ConVar oc_weapon_cguard_sphere_model("oc_weapon_cguard_sphere_model", "models/ballsphere.mdl", FCVAR_REPLICATED | FCVAR_ARCHIVE, "Shock rifle projectile model.");
ConVar oc_weapon_cguard_minscale("oc_weapon_cguard_minscale", "2", FCVAR_ARCHIVE);
#define SPHERE_MODEL oc_weapon_cguard_sphere_model.GetString() //"models/ShockRifle.mdl"
LINK_ENTITY_TO_CLASS(cguard_sphere, CCguard_Sphere);
BEGIN_DATADESC(CCguard_Sphere)
DEFINE_FIELD(Scale, FIELD_TIME),
DEFINE_FIELD(RevScale, FIELD_BOOLEAN),
DEFINE_THINKFUNC(Think),
END_DATADESC()
CCguard_Sphere *CCguard_Sphere::SphereCreate(const Vector &vecOrigin, const QAngle &angAngles, int iDamage, CBaseViewModel *pentOwner)
{
// Create a new entity with CShockRifleProjectile private data
CCguard_Sphere *Sphere = (CCguard_Sphere *)CreateEntityByName("cguard_sphere");
/*CBaseViewModel *vm = pentOwner->GetViewModel();
if (!vm)
Sphere->FollowEntity(pentOwner);
else
Sphere->FollowEntity(vm);*/
UTIL_SetOrigin(Sphere, vecOrigin);
Sphere->SetAbsAngles(angAngles);
Sphere->Spawn();
Sphere->SetOwnerEntity(pentOwner);
//Sphere->FollowEntity(pentOwner);
//Sphere->m_iDamage = iDamage;
return Sphere;
}
CCguard_Sphere::CCguard_Sphere(void)
{
Scale = 0.0f;
RevScale = false;
}
void CCguard_Sphere::Precache(void)
{
// m_nSquidSpitSprite = PrecacheModel("sprites/greenglow1.vmt");// client side spittle.
PrecacheModel(SPHERE_MODEL);
PrecacheModel("models/ballsphere.mdl");
PrecacheModel("models/spitball_medium.mdl");
PrecacheModel("models/spitball_small.mdl");
PrecacheScriptSound("GrenadeSpit.Hit");
PrecacheParticleSystem("grenade_spit_player");
PrecacheParticleSystem("grenade_spit");
PrecacheParticleSystem("grenade_spit_trail");
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCguard_Sphere::Spawn(void)
{
Precache();
SetMoveType(MOVETYPE_FLY, MOVECOLLIDE_FLY_CUSTOM);
UTIL_SetSize(this, -Vector(10, 10, 10), Vector(10, 10, 10));
SetSolid(SOLID_NONE);
//SetSolidFlags(FSOLID_NOT_SOLID);
//Vector SizeMin(0.2, 0.2, 0.2), SizeMax(1, 1, 1);
Scale = 0.0f;
RevScale = false;
//SetModel("models/spitball_large.mdl");
SetModel(SPHERE_MODEL);
//UTIL_SetSize(this, SizeMin, SizeMax);
SetModelScale(cvar->FindVar("oc_weapon_cguard_minscale")->GetFloat(), 0.0f);
//SetUse(&CBaseGrenade::DetonateUse);
//SetTouch(&CCguard_Sphere::SphereTouch);
SetThink(&CCguard_Sphere::Think);
SetNextThink(gpGlobals->curtime + 0.001f);
//m_takedamage = DAMAGE_NO;
//m_iHealth = 1;
//DevMsg("SphereInit");
//SetGravity(UTIL_ScaleForGravity(SPIT_GRAVITY));
//SetFriction(0.8f);
//SetCollisionGroup(HL2COLLISION_GROUP_SPIT);
//AddEFlags(EFL_FORCE_CHECK_TRANSMIT);
// We're self-illuminating, so we don't take or give shadows
//AddEffects(EF_NOSHADOW | EF_NORECEIVESHADOW);
/*DispatchParticleEffect("grenade_spit_trail", PATTACH_ABSORIGIN_FOLLOW, this);
// Create the dust effect in place
m_hSphereEffect = (CParticleSystem *)CreateEntityByName("info_particle_system");
if (m_hSphereEffect != NULL)
{
// Setup our basic parameters
m_hSphereEffect->KeyValue("start_active", "1");
m_hSphereEffect->KeyValue("effect_name", "antlion_spit_trail");
m_hSphereEffect->SetParent(this);
m_hSphereEffect->SetLocalOrigin(vec3_origin);
DispatchSpawn(m_hSphereEffect);
if (gpGlobals->curtime > 0.5f)
m_hSphereEffect->Activate();
}*/
}
void CCguard_Sphere::Event_Killed(const CTakeDamageInfo &info)
{
Detonate();
}
//-----------------------------------------------------------------------------
// Purpose: Handle spitting
//-----------------------------------------------------------------------------
/*void CCguard_Sphere::SphereTouch(CBaseEntity *pOther)
{
if (pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS | FSOLID_TRIGGER))
{
// Some NPCs are triggers that can take damage (like antlion grubs). We should hit them.
if ((pOther->m_takedamage == DAMAGE_NO) || (pOther->m_takedamage == DAMAGE_EVENTS_ONLY))
return;
}
// Don't hit other spit
if (pOther->GetCollisionGroup() == HL2COLLISION_GROUP_SPIT)
return;
// We want to collide with water
const trace_t *pTrace = &CBaseEntity::GetTouchTrace();
// copy out some important things about this trace, because the first TakeDamage
// call below may cause another trace that overwrites the one global pTrace points
// at.
bool bHitWater = ((pTrace->contents & CONTENTS_WATER) != 0);
CBaseEntity *const pTraceEnt = pTrace->m_pEnt;
const Vector tracePlaneNormal = pTrace->plane.normal;
if (bHitWater)
{
// Splash!
CEffectData data;
data.m_fFlags = 0;
data.m_vOrigin = pTrace->endpos;
data.m_vNormal = Vector(0, 0, 1);
data.m_flScale = 8.0f;
DispatchEffect("watersplash", data);
}
else
{
// Make a splat decal
trace_t *pNewTrace = const_cast<trace_t*>(pTrace);
UTIL_DecalTrace(pNewTrace, "SpitSplat");
}
QAngle vecAngles;
VectorAngles(tracePlaneNormal, vecAngles);
if (pOther->IsPlayer() || bHitWater)
{
// Do a lighter-weight effect if we just hit a player
DispatchParticleEffect("grenade_spit_player", GetAbsOrigin(), vecAngles);
}
else
{
DispatchParticleEffect("grenade_spit", GetAbsOrigin(), vecAngles);
}
Detonate();
}*/
void CCguard_Sphere::Detonate(void)
{
/*m_takedamage = DAMAGE_NO;
EmitSound("GrenadeSpit.Hit");
// Stop our hissing sound
if (m_pHissSound != NULL)
{
CSoundEnvelopeController::GetController().SoundDestroy(m_pHissSound);
m_pHissSound = NULL;
}
*/
UTIL_Remove(this);
}
ConVar oc_weapon_cguard_maxscale("oc_weapon_cguard_maxscale", "6", FCVAR_ARCHIVE);
ConVar oc_weapon_cguard_increment_scale("oc_weapon_cguard_increment_scale", "0.1", FCVAR_ARCHIVE);
ConVar oc_weapon_cguard_decrement_scale("oc_weapon_cguard_decrement_scale", "0.9", FCVAR_ARCHIVE);
ConVar oc_weapon_cguard_sphere_pos_x("oc_weapon_cguard_sphere_pos_x", "5", FCVAR_ARCHIVE);
ConVar oc_weapon_cguard_sphere_pos_y("oc_weapon_cguard_sphere_pos_y", "0.1", FCVAR_ARCHIVE);
ConVar oc_weapon_cguard_sphere_pos_z("oc_weapon_cguard_sphere_pos_z", "0.9", FCVAR_ARCHIVE);
void CCguard_Sphere::Think(void)
{
// Add a doppler effect to the balls as they travel
CBaseEntity *pPlayer = AI_GetSinglePlayer();
if (pPlayer != NULL)
{
if (Scale <= cvar->FindVar("oc_weapon_cguard_maxscale")->GetFloat() && !RevScale)
{
Scale = Scale + (cvar->FindVar("oc_weapon_cguard_increment_scale")->GetFloat() * gpGlobals->frametime);
if (Scale >= cvar->FindVar("oc_weapon_cguard_maxscale")->GetFloat())
RevScale = true;
}
else if (RevScale)
{
Scale = 0.0f;
Detonate();
/*if (Scale > 0.0f && RevScale)
Scale = Scale - (cvar->FindVar("oc_weapon_cguard_decrement_scale")->GetFloat() * gpGlobals->frametime);
else
{
Scale = 0.0f;
Detonate();
}*/
}
//SetParent(pPlayer, 1);
SetModelScale(Scale, 0.0f);
//DevMsg("Scale: %.2f \n", Scale);
CWeaponCGuard *pParentWeapon = (CWeaponCGuard*)GetParent();
if (pParentWeapon)
{
Vector MuzzleS;
MuzzleS = pParentWeapon->GetClientMuzzleVector();
QAngle MuzzleAngle;
MuzzleAngle = pParentWeapon->GetClientMuzzleAngles();
/*MuzzleAngle.x = cvar->FindVar("oc_muzzle_angle_x")->GetFloat();
MuzzleAngle.y = cvar->FindVar("oc_muzzle_angle_y")->GetFloat();
MuzzleAngle.z = cvar->FindVar("oc_muzzle_angle_z")->GetFloat();*/
MuzzleAngle.x = MuzzleAngle.x - 90.0f;
Vector forward(1, 0, 0), right(0, 1, 0), up(0, 0, 1);
/*MuzzleS.x = cvar->FindVar("oc_muzzle_vector_x")->GetFloat();
MuzzleS.y = cvar->FindVar("oc_muzzle_vector_y")->GetFloat();
MuzzleS.z = cvar->FindVar("oc_muzzle_vector_z")->GetFloat();*/
AngleVectors(MuzzleAngle, &forward, &right, &up);
MuzzleS += forward * oc_weapon_cguard_sphere_pos_x.GetFloat();
MuzzleS += right * oc_weapon_cguard_sphere_pos_y.GetFloat();
MuzzleS += up * oc_weapon_cguard_sphere_pos_z.GetFloat();
UTIL_SetOrigin(this, MuzzleS);
this->SetAbsAngles(MuzzleAngle);
}
}
else
{
Detonate();
}
// Set us up to think again shortly
SetNextThink(gpGlobals->curtime + 0.001f);
}

View File

@@ -0,0 +1,47 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Projectile shot by bullsquid
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef CGUARD_SPHERE_H
#define CGUARD_SPHERE_H
#include "basegrenade_shared.h"
class CParticleSystem;
#define SPIT_GRAVITY 0
class CCguard_Sphere : public CBaseCombatCharacter
{
DECLARE_CLASS(CCguard_Sphere, CBaseCombatCharacter);
public:
CCguard_Sphere(void);
static CCguard_Sphere *SphereCreate(const Vector &vecOrigin, const QAngle &angAngles, int iDamage, CBaseViewModel *pentOwner = NULL);
virtual void Spawn(void);
virtual void Precache(void);
virtual void Event_Killed(const CTakeDamageInfo &info);
virtual unsigned int PhysicsSolidMaskForEntity(void) const { return (BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_WATER); }
void Detonate(void);
void Think(void);
float Scale;
bool RevScale;
private:
DECLARE_DATADESC();
};
#endif

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram />

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
#TargetFrameworkVersion=v4.0:PlatformToolSet=v120:EnableManagedIncrementalBuild=false:VCToolArchitecture=Native32Bit
Debug|Win32|D:\SourceCodes\project_overcharged_build_10_rtt\src_RTT\|

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,198 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Utility code.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "te.h"
#include "shake.h"
#include "decals.h"
#include "IEffects.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern short g_sModelIndexSmoke; // (in combatweapon.cpp) holds the index for the smoke cloud
extern short g_sModelIndexBloodDrop; // (in combatweapon.cpp) holds the sprite index for the initial blood
extern short g_sModelIndexBloodSpray; // (in combatweapon.cpp) holds the sprite index for splattered blood
//-----------------------------------------------------------------------------
// Client-server neutral effects interface
//-----------------------------------------------------------------------------
class CEffectsServer : public IEffects
{
public:
CEffectsServer();
virtual ~CEffectsServer();
// Members of the IEffect interface
virtual void Beam( const Vector &Start, const Vector &End, int nModelIndex,
int nHaloIndex, unsigned char frameStart, unsigned char frameRate,
float flLife, unsigned char width, unsigned char endWidth, unsigned char fadeLength,
unsigned char noise, unsigned char red, unsigned char green,
unsigned char blue, unsigned char brightness, unsigned char speed);
virtual void Smoke( const Vector &origin, int mModel, float flScale, float flFramerate );
virtual void Sparks( const Vector &position, int nMagnitude = 1, int nTrailLength = 1, const Vector *pvecDir = NULL );
virtual void Dust( const Vector &pos, const Vector &dir, float size, float speed );
virtual void MuzzleFlash( const Vector &origin, const QAngle &angles, float scale, int type );
virtual void MetalSparks( const Vector &position, const Vector &direction );
virtual void EnergySplash( const Vector &position, const Vector &direction, bool bExplosive = false );
virtual void Ricochet( const Vector &position, const Vector &direction );
// FIXME: Should these methods remain in this interface? Or go in some
// other client-server neutral interface?
virtual float Time();
virtual bool IsServer();
virtual void SuppressEffectsSounds( bool bSuppress ) { Assert(0); }
private:
//-----------------------------------------------------------------------------
// Purpose: Returning true means don't even call TE func
// Input : filter -
// *suppress_host -
// Output : static bool
//-----------------------------------------------------------------------------
bool SuppressTE( CRecipientFilter& filter )
{
if ( GetSuppressHost() )
{
if ( !filter.IgnorePredictionCull() )
{
filter.RemoveRecipient( (CBasePlayer *)GetSuppressHost() );
}
if ( !filter.GetRecipientCount() )
{
// Suppress it
return true;
}
}
// There's at least one recipient
return false;
}
};
//-----------------------------------------------------------------------------
// Client-server neutral effects interface accessor
//-----------------------------------------------------------------------------
static CEffectsServer s_EffectServer;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CEffectsServer, IEffects, IEFFECTS_INTERFACE_VERSION, s_EffectServer);
IEffects *g_pEffects = &s_EffectServer;
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CEffectsServer::CEffectsServer()
{
}
CEffectsServer::~CEffectsServer()
{
}
//-----------------------------------------------------------------------------
// Generates a beam
//-----------------------------------------------------------------------------
void CEffectsServer::Beam( const Vector &vecStart, const Vector &vecEnd, int nModelIndex,
int nHaloIndex, unsigned char frameStart, unsigned char frameRate,
float flLife, unsigned char width, unsigned char endWidth, unsigned char fadeLength,
unsigned char noise, unsigned char red, unsigned char green,
unsigned char blue, unsigned char brightness, unsigned char speed)
{
CBroadcastRecipientFilter filter;
if ( !SuppressTE( filter ) )
{
te->BeamPoints( filter, 0.0,
&vecStart, &vecEnd, nModelIndex, nHaloIndex, frameStart, frameRate, flLife,
width, endWidth, fadeLength, noise, red, green, blue, brightness, speed );
}
}
//-----------------------------------------------------------------------------
// Generates various tempent effects
//-----------------------------------------------------------------------------
void CEffectsServer::Smoke( const Vector &origin, int mModel, float flScale, float flFramerate )
{
CPVSFilter filter( origin );
if ( !SuppressTE( filter ) )
{
te->Smoke( filter, 0.0, &origin, mModel, flScale * 0.1f, flFramerate );
}
}
void CEffectsServer::Sparks( const Vector &position, int nMagnitude, int nTrailLength, const Vector *pvecDir )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->Sparks( filter, 0.0, &position, nMagnitude, nTrailLength, pvecDir );
}
}
void CEffectsServer::Dust( const Vector &pos, const Vector &dir, float size, float speed )
{
CPVSFilter filter( pos );
if ( !SuppressTE( filter ) )
{
te->Dust( filter, 0.0, pos, dir, size, speed );
}
}
void CEffectsServer::MuzzleFlash( const Vector &origin, const QAngle &angles, float scale, int type )
{
CPVSFilter filter( origin );
if ( !SuppressTE( filter ) )
{
te->MuzzleFlash( filter, 0.0f, origin, angles, scale, type );
}
}
void CEffectsServer::MetalSparks( const Vector &position, const Vector &direction )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->MetalSparks( filter, 0.0, &position, &direction );
}
}
void CEffectsServer::EnergySplash( const Vector &position, const Vector &direction, bool bExplosive )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->EnergySplash( filter, 0.0, &position, &direction, bExplosive );
}
}
void CEffectsServer::Ricochet( const Vector &position, const Vector &direction )
{
CPVSFilter filter( position );
if ( !SuppressTE( filter ) )
{
te->ArmorRicochet( filter, 0.0, &position, &direction );
}
}
//-----------------------------------------------------------------------------
// FIXME: Should these methods remain in this interface? Or go in some
// other client-server neutral interface?
//-----------------------------------------------------------------------------
float CEffectsServer::Time()
{
return gpGlobals->curtime;
}
bool CEffectsServer::IsServer()
{
return true;
}

View File

@@ -0,0 +1,388 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Dissolve entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "EntityDissolve.h"
#include "baseanimating.h"
#include "physics_prop_ragdoll.h"
#include "ai_basenpc.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
static const char *s_pElectroThinkContext = "ElectroThinkContext";
//-----------------------------------------------------------------------------
// Lifetime
//-----------------------------------------------------------------------------
#define DISSOLVE_FADE_IN_START_TIME 0.0f
#define DISSOLVE_FADE_IN_END_TIME 1.0f
#define DISSOLVE_FADE_OUT_MODEL_START_TIME 1.9f
#define DISSOLVE_FADE_OUT_MODEL_END_TIME 2.0f
#define DISSOLVE_FADE_OUT_START_TIME 2.0f
#define DISSOLVE_FADE_OUT_END_TIME 2.0f
//-----------------------------------------------------------------------------
// Model
//-----------------------------------------------------------------------------
#define DISSOLVE_SPRITE_NAME "sprites/blueglow1.vmt"
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CEntityDissolve )
DEFINE_FIELD( m_flStartTime, FIELD_TIME ),
DEFINE_FIELD( m_flFadeInStart, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeInLength, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutModelStart, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutModelLength, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutStart, FIELD_FLOAT ),
DEFINE_FIELD( m_flFadeOutLength, FIELD_FLOAT ),
DEFINE_KEYFIELD( m_nDissolveType, FIELD_INTEGER, "dissolvetype" ),
DEFINE_FIELD( m_vDissolverOrigin, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_nMagnitude, FIELD_INTEGER, "magnitude" ),
DEFINE_FUNCTION( DissolveThink ),
DEFINE_FUNCTION( ElectrocuteThink ),
DEFINE_INPUTFUNC( FIELD_STRING, "Dissolve", InputDissolve ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST( CEntityDissolve, DT_EntityDissolve )
SendPropTime( SENDINFO( m_flStartTime ) ),
SendPropFloat( SENDINFO( m_flFadeInStart ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeInLength ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutModelStart ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutModelLength ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutStart ), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO( m_flFadeOutLength ), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO( m_nDissolveType ), ENTITY_DISSOLVE_BITS, SPROP_UNSIGNED ),
SendPropVector (SENDINFO(m_vDissolverOrigin), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO( m_nMagnitude ), 8, SPROP_UNSIGNED ),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( env_entity_dissolver, CEntityDissolve );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEntityDissolve::CEntityDissolve( void )
{
m_flStartTime = 0.0f;
m_nMagnitude = 250;
}
CEntityDissolve::~CEntityDissolve( void )
{
}
//-----------------------------------------------------------------------------
// Precache
//-----------------------------------------------------------------------------
void CEntityDissolve::Precache()
{
if ( NULL_STRING == GetModelName() )
{
PrecacheModel( DISSOLVE_SPRITE_NAME );
}
else
{
PrecacheModel( STRING( GetModelName() ) );
}
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEntityDissolve::Spawn()
{
BaseClass::Spawn();
Precache();
UTIL_SetModel( this, STRING( GetModelName() ) );
if ( (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
{
if ( dynamic_cast< CRagdollProp* >( GetMoveParent() ) )
{
SetContextThink( &CEntityDissolve::ElectrocuteThink, gpGlobals->curtime + 0.01f, s_pElectroThinkContext );
}
}
// Setup our times
m_flFadeInStart = DISSOLVE_FADE_IN_START_TIME;
m_flFadeInLength = DISSOLVE_FADE_IN_END_TIME - DISSOLVE_FADE_IN_START_TIME;
m_flFadeOutModelStart = DISSOLVE_FADE_OUT_MODEL_START_TIME;
m_flFadeOutModelLength = DISSOLVE_FADE_OUT_MODEL_END_TIME - DISSOLVE_FADE_OUT_MODEL_START_TIME;
m_flFadeOutStart = DISSOLVE_FADE_OUT_START_TIME;
m_flFadeOutLength = DISSOLVE_FADE_OUT_END_TIME - DISSOLVE_FADE_OUT_START_TIME;
if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
{
m_flFadeInStart = 0.0f;
m_flFadeOutStart = CORE_DISSOLVE_FADE_START;
m_flFadeOutModelStart = CORE_DISSOLVE_MODEL_FADE_START;
m_flFadeOutModelLength = CORE_DISSOLVE_MODEL_FADE_LENGTH;
m_flFadeInLength = CORE_DISSOLVE_FADEIN_LENGTH;
}
m_nRenderMode = kRenderTransColor;
SetRenderColor( 255, 255, 255, 255 );
m_nRenderFX = kRenderFxNone;
SetThink( &CEntityDissolve::DissolveThink );
if ( gpGlobals->curtime > m_flStartTime )
{
// Necessary for server-side ragdolls
DissolveThink();
}
else
{
SetNextThink( gpGlobals->curtime + 0.01f );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CEntityDissolve::InputDissolve( inputdata_t &inputdata )
{
string_t strTarget = inputdata.value.StringID();
if (strTarget == NULL_STRING)
{
strTarget = m_target;
}
CBaseEntity *pTarget = NULL;
while ((pTarget = gEntList.FindEntityGeneric(pTarget, STRING(strTarget), this, inputdata.pActivator)) != NULL)
{
CBaseAnimating *pBaseAnim = pTarget->GetBaseAnimating();
if (pBaseAnim)
{
pBaseAnim->Dissolve( NULL, gpGlobals->curtime, false, m_nDissolveType, GetAbsOrigin(), m_nMagnitude );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CEntityDissolve *CEntityDissolve::Create( CBaseEntity *pTarget, const char *pMaterialName,
float flStartTime, int nDissolveType, bool *pRagdollCreated )
{
if ( pRagdollCreated )
{
*pRagdollCreated = false;
}
if ( !pMaterialName )
{
pMaterialName = DISSOLVE_SPRITE_NAME;
}
if ( pTarget->IsPlayer() )
{
// Simply immediately kill the player.
CBasePlayer *pPlayer = assert_cast< CBasePlayer* >( pTarget );
pPlayer->SetArmorValue( 0 );
CTakeDamageInfo info( pPlayer, pPlayer, pPlayer->GetHealth(), DMG_GENERIC | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
pPlayer->TakeDamage( info );
return NULL;
}
CEntityDissolve *pDissolve = (CEntityDissolve *) CreateEntityByName( "env_entity_dissolver" );
if ( pDissolve == NULL )
return NULL;
pDissolve->m_nDissolveType = nDissolveType;
if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
{
if ( pTarget->IsNPC() && pTarget->MyNPCPointer()->CanBecomeRagdoll() )
{
CTakeDamageInfo info;
CBaseEntity *pRagdoll = CreateServerRagdoll(pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_DEBRIS, true, pTarget->MyNPCPointer()->BloodColor());
pRagdoll->SetCollisionBounds( pTarget->CollisionProp()->OBBMins(), pTarget->CollisionProp()->OBBMaxs() );
// Necessary to cause it to do the appropriate death cleanup
if ( pTarget->m_lifeState == LIFE_ALIVE )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
CTakeDamageInfo ragdollInfo( pPlayer, pPlayer, 10000.0, DMG_SHOCK | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE );
pTarget->TakeDamage( ragdollInfo );
}
if ( pRagdollCreated )
{
*pRagdollCreated = true;
}
UTIL_Remove( pTarget );
pTarget = pRagdoll;
}
}
pDissolve->SetModelName( AllocPooledString(pMaterialName) );
pDissolve->AttachToEntity( pTarget );
pDissolve->SetStartTime( flStartTime );
pDissolve->Spawn();
// Send to the client even though we don't have a model
pDissolve->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
// Play any appropriate noises when we start to dissolve
if ( (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) )
{
pTarget->DispatchResponse( "TLK_ELECTROCUTESCREAM" );
}
else
{
pTarget->DispatchResponse( "TLK_DISSOLVESCREAM" );
}
return pDissolve;
}
//-----------------------------------------------------------------------------
// What type of dissolve?
//-----------------------------------------------------------------------------
CEntityDissolve *CEntityDissolve::Create( CBaseEntity *pTarget, CBaseEntity *pSource )
{
// Look for other boogies on the ragdoll + kill them
for ( CBaseEntity *pChild = pSource->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
{
CEntityDissolve *pDissolve = dynamic_cast<CEntityDissolve*>(pChild);
if ( !pDissolve )
continue;
return Create( pTarget, STRING( pDissolve->GetModelName() ), pDissolve->m_flStartTime, pDissolve->m_nDissolveType );
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Attaches the flame to an entity and moves with it
// Input : pTarget - target entity to attach to
//-----------------------------------------------------------------------------
void CEntityDissolve::AttachToEntity( CBaseEntity *pTarget )
{
// So our dissolver follows the entity around on the server.
SetParent( pTarget );
SetLocalOrigin( vec3_origin );
SetLocalAngles( vec3_angle );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CEntityDissolve::SetStartTime( float flStartTime )
{
m_flStartTime = flStartTime;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityDissolve::DissolveThink( void )
{
CBaseAnimating *pTarget = ( GetMoveParent() ) ? GetMoveParent()->GetBaseAnimating() : NULL;
if ( GetModelName() == NULL_STRING && pTarget == NULL )
return;
if ( pTarget == NULL )
{
UTIL_Remove( this );
return;
}
// Turn them into debris
pTarget->SetCollisionGroup( COLLISION_GROUP_DISSOLVING );
if ( pTarget && pTarget->GetFlags() & FL_TRANSRAGDOLL )
{
SetRenderColorA( 0 );
}
float dt = gpGlobals->curtime - m_flStartTime;
if ( dt < m_flFadeInStart )
{
SetNextThink( m_flStartTime + m_flFadeInStart );
return;
}
// If we're done fading, then kill our target entity and us
if ( dt >= m_flFadeOutStart + m_flFadeOutLength )
{
// Necessary to cause it to do the appropriate death cleanup
// Yeah, the player may have nothing to do with it, but
// passing NULL to TakeDamage causes bad things to happen
CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 );
int iNoPhysicsDamage = g_pGameRules->Damage_GetNoPhysicsForce();
CTakeDamageInfo info( pPlayer, pPlayer, 10000.0, DMG_GENERIC | DMG_REMOVENORAGDOLL | iNoPhysicsDamage );
pTarget->TakeDamage( info );
if ( pTarget != pPlayer )
{
UTIL_Remove( pTarget );
}
UTIL_Remove( this );
return;
}
SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityDissolve::ElectrocuteThink( void )
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( GetMoveParent() );
if ( !pRagdoll )
return;
ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll( );
for ( int j = 0; j < pRagdollPhys->listCount; ++j )
{
Vector vecForce;
vecForce = RandomVector( -2400.0f, 2400.0f );
pRagdollPhys->list[j].pObject->ApplyForceCenter( vecForce );
}
SetContextThink( &CEntityDissolve::ElectrocuteThink, gpGlobals->curtime + random->RandomFloat( 0.1, 0.2f ),
s_pElectroThinkContext );
}

View File

@@ -0,0 +1,63 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYDISSOLVE_H
#define ENTITYDISSOLVE_H
#ifdef _WIN32
#pragma once
#endif
class CEntityDissolve : public CBaseEntity
{
public:
DECLARE_SERVERCLASS();
DECLARE_CLASS( CEntityDissolve, CBaseEntity );
CEntityDissolve( void );
~CEntityDissolve( void );
static CEntityDissolve *Create( CBaseEntity *pTarget, const char *pMaterialName,
float flStartTime, int nDissolveType = 0, bool *pRagdollCreated = NULL );
static CEntityDissolve *Create( CBaseEntity *pTarget, CBaseEntity *pSource );
void Precache();
void Spawn();
void AttachToEntity( CBaseEntity *pTarget );
void SetStartTime( float flStartTime );
void SetDissolverOrigin( Vector vOrigin ) { m_vDissolverOrigin = vOrigin; }
void SetMagnitude( int iMagnitude ){ m_nMagnitude = iMagnitude; }
void SetDissolveType( int iType ) { m_nDissolveType = iType; }
Vector GetDissolverOrigin( void )
{
Vector vReturn = m_vDissolverOrigin;
return vReturn;
}
int GetMagnitude( void ) { return m_nMagnitude; }
int GetDissolveType( void ) { return m_nDissolveType; }
DECLARE_DATADESC();
CNetworkVar( float, m_flStartTime );
CNetworkVar( float, m_flFadeInStart );
CNetworkVar( float, m_flFadeInLength );
CNetworkVar( float, m_flFadeOutModelStart );
CNetworkVar( float, m_flFadeOutModelLength );
CNetworkVar( float, m_flFadeOutStart );
CNetworkVar( float, m_flFadeOutLength );
protected:
void InputDissolve( inputdata_t &inputdata );
void DissolveThink( void );
void ElectrocuteThink( void );
CNetworkVar( int, m_nDissolveType );
CNetworkVector( m_vDissolverOrigin );
CNetworkVar( int, m_nMagnitude );
};
#endif // ENTITYDISSOLVE_H

View File

@@ -0,0 +1,505 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Dissolve entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "EntityDissolveEgon.h"
#include "baseanimating.h"
#include "physics_prop_ragdoll.h"
#include "ai_basenpc.h"
#include "RagdollEgonBoogie.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
static const char *s_pElectroThinkContext = "ElectroThinkContext";
//-----------------------------------------------------------------------------
// Lifetime
//-----------------------------------------------------------------------------
#define DISSOLVE_FADE_IN_START_TIME 0.0f
#define DISSOLVE_FADE_IN_END_TIME 0.7f
#define DISSOLVE_FADE_OUT_MODEL_START_TIME 1.9f
#define DISSOLVE_FADE_OUT_MODEL_END_TIME 2.0f
#define DISSOLVE_FADE_OUT_START_TIME 1.5f
#define DISSOLVE_FADE_OUT_END_TIME 1.5f
//-----------------------------------------------------------------------------
// Model
//-----------------------------------------------------------------------------
#define DISSOLVE_SPRITE_NAME "sprites/blueglowE.vmt"
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC(CEntityDissolveEgon)
DEFINE_FIELD(m_flStartTime, FIELD_TIME),
DEFINE_FIELD(m_flFadeInStart, FIELD_FLOAT),
DEFINE_FIELD(m_flFadeInLength, FIELD_FLOAT),
DEFINE_FIELD(m_flFadeOutModelStart, FIELD_FLOAT),
DEFINE_FIELD(m_flFadeOutModelLength, FIELD_FLOAT),
DEFINE_FIELD(m_flFadeOutStart, FIELD_FLOAT),
DEFINE_FIELD(m_flFadeOutLength, FIELD_FLOAT),
DEFINE_KEYFIELD(m_nDissolveType, FIELD_INTEGER, "dissolvetype"),
DEFINE_FIELD(m_vDissolverOrigin, FIELD_VECTOR),
DEFINE_KEYFIELD(m_nMagnitude, FIELD_INTEGER, "magnitude"),
DEFINE_FUNCTION(DissolveThink),
DEFINE_FUNCTION(ElectrocuteThink),
DEFINE_INPUTFUNC(FIELD_STRING, "Dissolve", InputDissolve),
END_DATADESC()
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST(CEntityDissolveEgon, DT_EntityDissolveEgon)
SendPropTime(SENDINFO(m_flStartTime)),
SendPropFloat(SENDINFO(m_flFadeInStart), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_flFadeInLength), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_flFadeOutModelStart), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_flFadeOutModelLength), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_flFadeOutStart), 0, SPROP_NOSCALE),
SendPropFloat(SENDINFO(m_flFadeOutLength), 0, SPROP_NOSCALE),
SendPropInt(SENDINFO(m_nDissolveType), ENTITY_DISSOLVE_BITS, SPROP_UNSIGNED),
SendPropVector(SENDINFO(m_vDissolverOrigin), 0, SPROP_NOSCALE),
SendPropInt(SENDINFO(m_nMagnitude), 8, SPROP_UNSIGNED),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS(env_entity_dissolver_egon, CEntityDissolveEgon);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEntityDissolveEgon::CEntityDissolveEgon(void)
{
m_flStartTime = 0.0f;
m_nMagnitude = 250;
}
CEntityDissolveEgon::~CEntityDissolveEgon(void)
{
}
//-----------------------------------------------------------------------------
// Precache
//-----------------------------------------------------------------------------
void CEntityDissolveEgon::Precache()
{
if (NULL_STRING == GetModelName())
{
PrecacheModel(DISSOLVE_SPRITE_NAME);
}
else
{
PrecacheModel(STRING(GetModelName()));
}
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEntityDissolveEgon::Spawn()
{
BaseClass::Spawn();
Precache();
UTIL_SetModel(this, STRING(GetModelName()));
if ((m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) || (m_nDissolveType == ENTITY_DISSOLVE_NORMAL))
{
if (dynamic_cast< CRagdollProp* >(GetMoveParent()))
{
SetContextThink(&CEntityDissolveEgon::ElectrocuteThink, gpGlobals->curtime + 0.01f, s_pElectroThinkContext);
}
}
// Setup our times
m_flFadeInStart = DISSOLVE_FADE_IN_START_TIME;
m_flFadeInLength = DISSOLVE_FADE_IN_END_TIME - DISSOLVE_FADE_IN_START_TIME;
m_flFadeOutModelStart = DISSOLVE_FADE_OUT_MODEL_START_TIME;
m_flFadeOutModelLength = DISSOLVE_FADE_OUT_MODEL_END_TIME - DISSOLVE_FADE_OUT_MODEL_START_TIME;
m_flFadeOutStart = DISSOLVE_FADE_OUT_START_TIME;
m_flFadeOutLength = DISSOLVE_FADE_OUT_END_TIME - DISSOLVE_FADE_OUT_START_TIME;
if (m_nDissolveType == ENTITY_DISSOLVE_CORE)
{
m_flFadeInStart = 0.0f;
m_flFadeOutStart = CORE_DISSOLVE_FADE_START;
m_flFadeOutModelStart = CORE_DISSOLVE_MODEL_FADE_START;
m_flFadeOutModelLength = CORE_DISSOLVE_MODEL_FADE_LENGTH;
m_flFadeInLength = CORE_DISSOLVE_FADEIN_LENGTH;
}
m_nRenderMode = kRenderTransColor;
SetRenderColor(255, 255, 255, 255);
m_nRenderFX = kRenderFxNone;
SetThink(&CEntityDissolveEgon::DissolveThink);
if (gpGlobals->curtime > m_flStartTime)
{
// Necessary for server-side ragdolls
DissolveThink();
}
else
{
SetNextThink(gpGlobals->curtime + 0.01f);
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CEntityDissolveEgon::InputDissolve(inputdata_t &inputdata)
{
string_t strTarget = inputdata.value.StringID();
if (strTarget == NULL_STRING)
{
strTarget = m_target;
}
CBaseEntity *pTarget = NULL;
while ((pTarget = gEntList.FindEntityGeneric(pTarget, STRING(strTarget), this, inputdata.pActivator)) != NULL)
{
CBaseAnimating *pBaseAnim = pTarget->GetBaseAnimating();
if (pBaseAnim)
{
pBaseAnim->Dissolve(NULL, gpGlobals->curtime, false, m_nDissolveType, GetAbsOrigin(), m_nMagnitude);
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CEntityDissolveEgon *CEntityDissolveEgon::Create(CBaseEntity *pTarget, const char *pMaterialName,
float flStartTime, int nDissolveType, bool *pRagdollCreated)
{
if (pRagdollCreated)
{
*pRagdollCreated = false;
}
if (!pMaterialName)
{
pMaterialName = DISSOLVE_SPRITE_NAME;
}
if (pTarget->IsPlayer())
{
// Simply immediately kill the player.
CBasePlayer *pPlayer = assert_cast< CBasePlayer* >(pTarget);
pPlayer->SetArmorValue(0);
CTakeDamageInfo info(pPlayer, pPlayer, pPlayer->GetHealth(), DMG_GENERIC | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE);
pPlayer->TakeDamage(info);
return NULL;
}
CEntityDissolveEgon *pDissolve = (CEntityDissolveEgon *)CreateEntityByName("env_entity_dissolver_egon");
if (pDissolve == NULL)
return NULL;
pDissolve->m_nDissolveType = nDissolveType;
if ((nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) || (nDissolveType == ENTITY_DISSOLVE_NORMAL))
{
if (pTarget->IsNPC() && pTarget->MyNPCPointer()->CanBecomeRagdoll())
{
CTakeDamageInfo info;
if (cvar->FindVar("oc_ragdoll_serverside")->GetInt())
{
bool createGradollConstrainted = cvar->FindVar("oc_ragdoll_death_weapon_holding")->GetBool();
CBaseCombatCharacter *pChar = static_cast<CBaseCombatCharacter*>(pTarget->MyNPCPointer());//pTarget->MyNPCPointer()->GetActiveWeapon();
CBaseCombatWeapon *pWeapon = NULL;
if (pChar)
pWeapon = pChar->pDroppedWeapon;
if (createGradollConstrainted)
createGradollConstrainted = (bool)(pWeapon != NULL);
const char *pAttachmentName = createGradollConstrainted ? "anim_attachment_RH" : "NULL";
const char *pWeaponName = createGradollConstrainted ? pWeapon->GetClassname() : "NULL";
if (cvar->FindVar("oc_ragdoll_serverside_collision_group")->GetInt() == 0)
{
CBaseEntity *pRagdoll = createGradollConstrainted ? CreateServerRagdoll(pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, pWeapon, pAttachmentName, pWeaponName, true, true, pTarget->MyNPCPointer()->BloodColor()) :
CreateServerRagdoll(pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_INTERACTIVE_DEBRIS, true, pTarget->MyNPCPointer()->BloodColor());
pRagdoll->SetCollisionBounds(pTarget->CollisionProp()->OBBMins(), pTarget->CollisionProp()->OBBMaxs());
// Necessary to cause it to do the appropriate death cleanup
if (pTarget->m_lifeState == LIFE_ALIVE)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
CTakeDamageInfo ragdollInfo(pPlayer, pPlayer, 10000.0, DMG_SHOCK | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE);
pTarget->TakeDamage(ragdollInfo);
}
if (pRagdollCreated)
{
*pRagdollCreated = true;
}
UTIL_Remove(pTarget);
pTarget = pRagdoll;
}
if (cvar->FindVar("oc_ragdoll_serverside_collision_group")->GetInt() == 1)
{
CBaseEntity *pRagdoll = createGradollConstrainted ? CreateServerRagdoll(pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_INTERACTIVE, pWeapon, pAttachmentName, pWeaponName, true, true, pTarget->MyNPCPointer()->BloodColor()) :
CreateServerRagdoll(pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_INTERACTIVE, true, pTarget->MyNPCPointer()->BloodColor());
pRagdoll->SetCollisionBounds(pTarget->CollisionProp()->OBBMins(), pTarget->CollisionProp()->OBBMaxs());
// Necessary to cause it to do the appropriate death cleanup
if (pTarget->m_lifeState == LIFE_ALIVE)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
CTakeDamageInfo ragdollInfo(pPlayer, pPlayer, 10000.0, DMG_SHOCK | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE);
pTarget->TakeDamage(ragdollInfo);
}
if (pRagdollCreated)
{
*pRagdollCreated = true;
}
UTIL_Remove(pTarget);
pTarget = pRagdoll;
}
if (cvar->FindVar("oc_ragdoll_serverside_collision_group")->GetInt() == 2)
{
CBaseEntity *pRagdoll = createGradollConstrainted ? CreateServerRagdoll(pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_NPC, pWeapon, pAttachmentName, pWeaponName, true, true, pTarget->MyNPCPointer()->BloodColor()) :
CreateServerRagdoll(pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_NPC, true, pTarget->MyNPCPointer()->BloodColor());
pRagdoll->SetCollisionBounds(pTarget->CollisionProp()->OBBMins(), pTarget->CollisionProp()->OBBMaxs());
// Necessary to cause it to do the appropriate death cleanup
if (pTarget->m_lifeState == LIFE_ALIVE)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
CTakeDamageInfo ragdollInfo(pPlayer, pPlayer, 10000.0, DMG_SHOCK | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE);
pTarget->TakeDamage(ragdollInfo);
}
if (pRagdollCreated)
{
*pRagdollCreated = true;
}
UTIL_Remove(pTarget);
pTarget = pRagdoll;
}
}
else
{
CBaseEntity *pRagdoll = CreateServerRagdoll(pTarget->MyNPCPointer(), 0, info, COLLISION_GROUP_DEBRIS, true, pTarget->MyNPCPointer()->BloodColor());
pRagdoll->SetCollisionBounds(pTarget->CollisionProp()->OBBMins(), pTarget->CollisionProp()->OBBMaxs());
// Necessary to cause it to do the appropriate death cleanup
if (pTarget->m_lifeState == LIFE_ALIVE)
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
CTakeDamageInfo ragdollInfo(pPlayer, pPlayer, 10000.0, DMG_SHOCK | DMG_REMOVENORAGDOLL | DMG_PREVENT_PHYSICS_FORCE);
pTarget->TakeDamage(ragdollInfo);
}
if (pRagdollCreated)
{
*pRagdollCreated = true;
}
UTIL_Remove(pTarget);
pTarget = pRagdoll;
}
}
}
pDissolve->SetModelName(AllocPooledString(pMaterialName));
pDissolve->AttachToEntity(pTarget);
pDissolve->SetStartTime(flStartTime);
pDissolve->Spawn();
// Send to the client even though we don't have a model
pDissolve->AddEFlags(EFL_FORCE_CHECK_TRANSMIT);
// Play any appropriate noises when we start to dissolve
if ((nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) || (nDissolveType == ENTITY_DISSOLVE_NORMAL))
{
pTarget->DispatchResponse("TLK_ELECTROCUTESCREAM");
}
else
{
pTarget->DispatchResponse("TLK_DISSOLVESCREAM");
}
return pDissolve;
}
//-----------------------------------------------------------------------------
// What type of dissolve?
//-----------------------------------------------------------------------------
CEntityDissolveEgon *CEntityDissolveEgon::Create(CBaseEntity *pTarget, CBaseEntity *pSource)
{
// Look for other boogies on the ragdoll + kill them
for (CBaseEntity *pChild = pSource->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer())
{
CEntityDissolveEgon *pDissolve = dynamic_cast<CEntityDissolveEgon*>(pChild);
if (!pDissolve)
continue;
return Create(pTarget, STRING(pDissolve->GetModelName()), pDissolve->m_flStartTime, pDissolve->m_nDissolveType);
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Attaches the flame to an entity and moves with it
// Input : pTarget - target entity to attach to
//-----------------------------------------------------------------------------
void CEntityDissolveEgon::AttachToEntity(CBaseEntity *pTarget)
{
// So our dissolver follows the entity around on the server.
SetParent(pTarget);
SetLocalOrigin(vec3_origin);
SetLocalAngles(vec3_angle);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CEntityDissolveEgon::SetStartTime(float flStartTime)
{
m_flStartTime = flStartTime;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityDissolveEgon::DissolveThink(void)
{
CBaseAnimating *pTarget = (GetMoveParent()) ? GetMoveParent()->GetBaseAnimating() : NULL;
if (GetModelName() == NULL_STRING && pTarget == NULL)
return;
if (pTarget == NULL)
{
UTIL_Remove(this);
return;
}
if (cvar->FindVar("oc_ragdoll_serverside")->GetInt())
{
if (cvar->FindVar("oc_ragdoll_serverside_collision_group")->GetInt() == 0)
{
// Turn them into debris
pTarget->SetCollisionGroup(COLLISION_GROUP_INTERACTIVE_DEBRIS); //COLLISION_GROUP_DISSOLVING
}
if (cvar->FindVar("oc_ragdoll_serverside_collision_group")->GetInt() == 1)
{
// Turn them into debris
pTarget->SetCollisionGroup(COLLISION_GROUP_INTERACTIVE); //COLLISION_GROUP_DISSOLVING
}
if (cvar->FindVar("oc_ragdoll_serverside_collision_group")->GetInt() == 0)
{
// Turn them into debris
pTarget->SetCollisionGroup(COLLISION_GROUP_NPC); //COLLISION_GROUP_DISSOLVING
}
}
else
{
pTarget->SetCollisionGroup(COLLISION_GROUP_DISSOLVING);
}
if (pTarget && pTarget->GetFlags() & FL_TRANSRAGDOLL)
{
SetRenderColorA(0);
}
float dt = gpGlobals->curtime - m_flStartTime;
if (dt < m_flFadeInStart)
{
SetNextThink(m_flStartTime + m_flFadeInStart);
return;
}
// If we're done fading, then kill our target entity and us
if (dt >= m_flFadeOutStart + m_flFadeOutLength)
{
// Necessary to cause it to do the appropriate death cleanup
// Yeah, the player may have nothing to do with it, but
// passing NULL to TakeDamage causes bad things to happen
CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
int iNoPhysicsDamage = g_pGameRules->Damage_GetNoPhysicsForce();
CTakeDamageInfo info(pPlayer, pPlayer, 10000.0, DMG_GENERIC | DMG_REMOVENORAGDOLL | iNoPhysicsDamage);
pTarget->TakeDamage(info);
if (pTarget != pPlayer)
{
pTarget->SetRenderColor(95,65,125);
//UTIL_Remove(pTarget);
}
UTIL_Remove(this);
return;
}
SetNextThink(gpGlobals->curtime + TICK_INTERVAL);
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityDissolveEgon::ElectrocuteThink(void)
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >(GetMoveParent());
if (!pRagdoll)
return;
CRagdollEgonBoogie::Create(pRagdoll, 20, gpGlobals->curtime, 2.0, SF_RAGDOLL_EGON_BOOGIE_ELECTRICAL);
ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll();
for (int j = 0; j < pRagdollPhys->listCount; ++j)
{
Vector vecForce;
vecForce = RandomVector(-20.0f, 20.0f);
pRagdollPhys->list[j].pObject->ApplyForceCenter(vecForce);
}
SetContextThink(&CEntityDissolveEgon::ElectrocuteThink, gpGlobals->curtime + random->RandomFloat(0.1, 0.2f),
s_pElectroThinkContext);
}

View File

@@ -0,0 +1,64 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "baseentity.h"
#include "baseentity_shared.h"
#ifndef ENTITYDISSOLVEEGON_H
#define ENTITYDISSOLVEEGON_H
#ifdef _WIN32
#pragma once
#endif
class CEntityDissolveEgon : public CBaseEntity
{
public:
DECLARE_SERVERCLASS();
DECLARE_CLASS(CEntityDissolveEgon, CBaseEntity);
CEntityDissolveEgon(void);
~CEntityDissolveEgon(void);
static CEntityDissolveEgon *Create(CBaseEntity *pTarget, const char *pMaterialName,
float flStartTime, int nDissolveType = 0, bool *pRagdollCreated = NULL);
static CEntityDissolveEgon *Create(CBaseEntity *pTarget, CBaseEntity *pSource);
void Precache();
void Spawn();
void AttachToEntity(CBaseEntity *pTarget);
void SetStartTime(float flStartTime);
void SetDissolverOrigin(Vector vOrigin) { m_vDissolverOrigin = vOrigin; }
void SetMagnitude(int iMagnitude){ m_nMagnitude = iMagnitude; }
void SetDissolveType(int iType) { m_nDissolveType = iType; }
Vector GetDissolverOrigin(void)
{
Vector vReturn = m_vDissolverOrigin;
return vReturn;
}
int GetMagnitude(void) { return m_nMagnitude; }
int GetDissolveType(void) { return m_nDissolveType; }
DECLARE_DATADESC();
CNetworkVar(float, m_flStartTime);
CNetworkVar(float, m_flFadeInStart);
CNetworkVar(float, m_flFadeInLength);
CNetworkVar(float, m_flFadeOutModelStart);
CNetworkVar(float, m_flFadeOutModelLength);
CNetworkVar(float, m_flFadeOutStart);
CNetworkVar(float, m_flFadeOutLength);
protected:
void InputDissolve(inputdata_t &inputdata);
void DissolveThink(void);
void ElectrocuteThink(void);
CNetworkVar(int, m_nDissolveType);
CNetworkVector(m_vDissolverOrigin);
CNetworkVar(int, m_nMagnitude);
};
#endif // ENTITYDISSOLVE_H

335
game/server/EntityFlame.cpp Normal file
View File

@@ -0,0 +1,335 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Flame entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "EntityFlame.h"
#include "ai_basenpc.h"
#include "fire.h"
#include "shareddefs.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CEntityFlame )
DEFINE_KEYFIELD( m_flLifetime, FIELD_FLOAT, "lifetime" ),
DEFINE_FIELD( m_flSize, FIELD_FLOAT ),
DEFINE_FIELD( m_hEntAttached, FIELD_EHANDLE ),
DEFINE_FIELD( m_bUseHitboxes, FIELD_BOOLEAN ),
DEFINE_FIELD( m_iNumHitboxFires, FIELD_INTEGER ),
DEFINE_FIELD( m_flHitboxFireScale, FIELD_FLOAT ),
// DEFINE_FIELD( m_bPlayingSound, FIELD_BOOLEAN ),
DEFINE_FUNCTION( FlameThink ),
DEFINE_INPUTFUNC( FIELD_VOID, "Ignite", InputIgnite ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CEntityFlame, DT_EntityFlame )
SendPropEHandle( SENDINFO( m_hEntAttached ) ),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( entityflame, CEntityFlame );
LINK_ENTITY_TO_CLASS( env_entity_igniter, CEntityFlame );
PRECACHE_REGISTER(entityflame);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CEntityFlame::CEntityFlame( void )
{
m_flSize = 0.0f;
m_iNumHitboxFires = 10;
m_flHitboxFireScale = 1.0f;
m_flLifetime = 0.0f;
m_bPlayingSound = false;
}
void CEntityFlame::UpdateOnRemove()
{
// Sometimes the entity I'm burning gets destroyed by other means,
// which kills me. Make sure to stop the burning sound.
if ( m_bPlayingSound )
{
EmitSound( "General.StopBurning" );
m_bPlayingSound = false;
}
BaseClass::UpdateOnRemove();
}
void CEntityFlame::Precache()
{
BaseClass::Precache();
PrecacheScriptSound( "General.StopBurning" );
PrecacheScriptSound( "General.BurningFlesh" );
PrecacheScriptSound( "General.BurningObject" );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : inputdata -
//-----------------------------------------------------------------------------
void CEntityFlame::InputIgnite( inputdata_t &inputdata )
{
if (m_target != NULL_STRING)
{
CBaseEntity *pTarget = NULL;
while ((pTarget = gEntList.FindEntityGeneric(pTarget, STRING(m_target), this, inputdata.pActivator)) != NULL)
{
// Combat characters know how to catch themselves on fire.
CBaseCombatCharacter *pBCC = pTarget->MyCombatCharacterPointer();
if (pBCC)
{
// DVS TODO: consider promoting Ignite to CBaseEntity and doing everything here
pBCC->Ignite(m_flLifetime);
}
// Everything else, we handle here.
else
{
CEntityFlame *pFlame = CEntityFlame::Create(pTarget);
if (pFlame)
{
pFlame->SetLifetime(m_flLifetime);
}
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CEntityFlame *CEntityFlame::Create( CBaseEntity *pTarget, bool useHitboxes )
{
CEntityFlame *pFlame = (CEntityFlame *) CreateEntityByName( "entityflame" );
if ( pFlame == NULL )
return NULL;
float xSize = pTarget->CollisionProp()->OBBMaxs().x - pTarget->CollisionProp()->OBBMins().x;
float ySize = pTarget->CollisionProp()->OBBMaxs().y - pTarget->CollisionProp()->OBBMins().y;
float size = ( xSize + ySize ) * 0.5f;
if ( size < 16.0f )
{
size = 16.0f;
}
UTIL_SetOrigin( pFlame, pTarget->GetAbsOrigin() );
pFlame->m_flSize = size;
pFlame->SetThink( &CEntityFlame::FlameThink );
pFlame->SetNextThink( gpGlobals->curtime + 0.1f );
pFlame->AttachToEntity( pTarget );
pFlame->SetLifetime( 2.0f );
//Send to the client even though we don't have a model
pFlame->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
pFlame->SetUseHitboxes( useHitboxes );
return pFlame;
}
//-----------------------------------------------------------------------------
// Purpose: Attaches the flame to an entity and moves with it
// Input : pTarget - target entity to attach to
//-----------------------------------------------------------------------------
void CEntityFlame::AttachToEntity( CBaseEntity *pTarget )
{
// For networking to the client.
m_hEntAttached = pTarget;
if( pTarget->IsNPC() )
{
EmitSound( "General.BurningFlesh" );
}
else
{
EmitSound( "General.BurningObject" );
}
m_bPlayingSound = true;
// So our heat emitter follows the entity around on the server.
SetParent( pTarget );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CEntityFlame::SetLifetime( float lifetime )
{
m_flLifetime = gpGlobals->curtime + lifetime;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : use -
//-----------------------------------------------------------------------------
void CEntityFlame::SetUseHitboxes( bool use )
{
m_bUseHitboxes = use;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : iNumHitBoxFires -
//-----------------------------------------------------------------------------
void CEntityFlame::SetNumHitboxFires( int iNumHitboxFires )
{
m_iNumHitboxFires = iNumHitboxFires;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flHitboxFireScale -
//-----------------------------------------------------------------------------
void CEntityFlame::SetHitboxFireScale( float flHitboxFireScale )
{
m_flHitboxFireScale = flHitboxFireScale;
}
float CEntityFlame::GetRemainingLife( void )
{
return m_flLifetime - gpGlobals->curtime;
}
int CEntityFlame::GetNumHitboxFires( void )
{
return m_iNumHitboxFires;
}
float CEntityFlame::GetHitboxFireScale( void )
{
return m_flHitboxFireScale;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityFlame::FlameThink( void )
{
// Assure that this function will be ticked again even if we early-out in the if below.
SetNextThink( gpGlobals->curtime + FLAME_DAMAGE_INTERVAL );
if ( m_hEntAttached )
{
if ( m_hEntAttached->GetFlags() & FL_TRANSRAGDOLL )
{
SetRenderColorA( 0 );
return;
}
CAI_BaseNPC *pNPC = m_hEntAttached->MyNPCPointer();
if ( pNPC && !pNPC->IsAlive() )
{
UTIL_Remove( this );
// Notify the NPC that it's no longer burning!
pNPC->Extinguish();
return;
}
if( m_hEntAttached->GetWaterLevel() > 0 )
{
Vector mins, maxs;
mins = m_hEntAttached->WorldSpaceCenter();
maxs = mins;
maxs.z = m_hEntAttached->WorldSpaceCenter().z;
maxs.x += 32;
maxs.y += 32;
mins.z -= 32;
mins.x -= 32;
mins.y -= 32;
UTIL_Bubbles( mins, maxs, 12 );
}
}
else
{
UTIL_Remove( this );
return;
}
// See if we're done burning, or our attached ent has vanished
if ( m_flLifetime < gpGlobals->curtime || m_hEntAttached == NULL )
{
EmitSound( "General.StopBurning" );
m_bPlayingSound = false;
SetThink( &CEntityFlame::SUB_Remove );
SetNextThink( gpGlobals->curtime + 0.5f );
// Notify anything we're attached to
if ( m_hEntAttached )
{
CBaseCombatCharacter *pAttachedCC = m_hEntAttached->MyCombatCharacterPointer();
if( pAttachedCC )
{
// Notify the NPC that it's no longer burning!
pAttachedCC->Extinguish();
}
}
return;
}
if ( m_hEntAttached )
{
// Do radius damage ignoring the entity I'm attached to. This will harm things around me.
RadiusDamage( CTakeDamageInfo( this, this, 4.0f, DMG_BURN ), GetAbsOrigin(), m_flSize/2, CLASS_NONE, m_hEntAttached );
// Directly harm the entity I'm attached to. This is so we can precisely control how much damage the entity
// that is on fire takes without worrying about the flame's position relative to the bodytarget (which is the
// distance that the radius damage code uses to determine how much damage to inflict)
m_hEntAttached->TakeDamage( CTakeDamageInfo( this, this, FLAME_DIRECT_DAMAGE, DMG_BURN | DMG_DIRECT ) );
if( !m_hEntAttached->IsNPC() && hl2_episodic.GetBool() )
{
const float ENTITYFLAME_MOVE_AWAY_DIST = 24.0f;
// Make a sound near my origin, and up a little higher (in case I'm on the ground, so NPC's still hear it)
CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin(), ENTITYFLAME_MOVE_AWAY_DIST, 0.1f, this, SOUNDENT_CHANNEL_REPEATED_DANGER );
CSoundEnt::InsertSound( SOUND_MOVE_AWAY, GetAbsOrigin() + Vector( 0, 0, 48.0f ), ENTITYFLAME_MOVE_AWAY_DIST, 0.1f, this, SOUNDENT_CHANNEL_REPEATING );
}
}
else
{
RadiusDamage( CTakeDamageInfo( this, this, FLAME_RADIUS_DAMAGE, DMG_BURN ), GetAbsOrigin(), m_flSize/2, CLASS_NONE, NULL );
}
FireSystem_AddHeatInRadius( GetAbsOrigin(), m_flSize/2, 2.0f );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pEnt -
//-----------------------------------------------------------------------------
void CreateEntityFlame(CBaseEntity *pEnt)
{
CEntityFlame::Create( pEnt );
}

66
game/server/EntityFlame.h Normal file
View File

@@ -0,0 +1,66 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYFLAME_H
#define ENTITYFLAME_H
#ifdef _WIN32
#pragma once
#endif
#define FLAME_DAMAGE_INTERVAL 0.2f // How often to deal damage.
#define FLAME_DIRECT_DAMAGE_PER_SEC 5.0f
#define FLAME_RADIUS_DAMAGE_PER_SEC 4.0f
#define FLAME_DIRECT_DAMAGE ( FLAME_DIRECT_DAMAGE_PER_SEC * FLAME_DAMAGE_INTERVAL )
#define FLAME_RADIUS_DAMAGE ( FLAME_RADIUS_DAMAGE_PER_SEC * FLAME_DAMAGE_INTERVAL )
#define FLAME_MAX_LIFETIME_ON_DEAD_NPCS 10.0f
class CEntityFlame : public CBaseEntity
{
public:
DECLARE_SERVERCLASS();
DECLARE_CLASS( CEntityFlame, CBaseEntity );
CEntityFlame( void );
static CEntityFlame *Create( CBaseEntity *pTarget, bool useHitboxes = true );
void AttachToEntity( CBaseEntity *pTarget );
void SetLifetime( float lifetime );
void SetUseHitboxes( bool use );
void SetNumHitboxFires( int iNumHitBoxFires );
void SetHitboxFireScale( float flHitboxFireScale );
float GetRemainingLife( void );
int GetNumHitboxFires( void );
float GetHitboxFireScale( void );
virtual void Precache();
virtual void UpdateOnRemove();
void SetSize( float size ) { m_flSize = size; }
DECLARE_DATADESC();
protected:
void InputIgnite( inputdata_t &inputdata );
void FlameThink( void );
CNetworkHandle( CBaseEntity, m_hEntAttached ); // The entity that we are burning (attached to).
CNetworkVar( float, m_flSize );
CNetworkVar( bool, m_bUseHitboxes );
CNetworkVar( int, m_iNumHitboxFires );
CNetworkVar( float, m_flHitboxFireScale );
CNetworkVar( float, m_flLifetime );
bool m_bPlayingSound;
};
#endif // ENTITYFLAME_H

View File

@@ -0,0 +1,207 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Drops particles where the entity was.
//
//=============================================================================//
#include "cbase.h"
#include "EntityParticleTrail.h"
#include "networkstringtable_gamedll.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Used to retire the entity
//-----------------------------------------------------------------------------
static const char *s_pRetireContext = "RetireContext";
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CEntityParticleTrail )
DEFINE_FIELD( m_iMaterialName, FIELD_MATERIALINDEX ),
DEFINE_EMBEDDED( m_Info ),
DEFINE_FIELD( m_hConstraintEntity, FIELD_EHANDLE ),
// Think this should be handled by StartTouch/etc.
// DEFINE_FIELD( m_nRefCount, FIELD_INTEGER ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Networking
//-----------------------------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST( CEntityParticleTrail, DT_EntityParticleTrail )
SendPropInt(SENDINFO(m_iMaterialName), MAX_MATERIAL_STRING_BITS, SPROP_UNSIGNED ),
SendPropDataTable( SENDINFO_DT( m_Info ), &REFERENCE_SEND_TABLE( DT_EntityParticleTrailInfo ) ),
SendPropEHandle(SENDINFO(m_hConstraintEntity)),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( env_particle_trail, CEntityParticleTrail );
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CEntityParticleTrail *CEntityParticleTrail::Create( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info, CBaseEntity *pConstraintEntity )
{
int iMaterialName = GetMaterialIndex( STRING(info.m_strMaterialName) );
// Look for other particle trails on the entity + copy state to the new entity
CEntityParticleTrail *pTrail;
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
pTrail = dynamic_cast<CEntityParticleTrail*>(pChild);
if ( pTrail && (pTrail->m_iMaterialName == iMaterialName) )
{
// Prevent destruction if it re-enters the field
pTrail->IncrementRefCount();
return pTrail;
}
}
pTrail = (CEntityParticleTrail *)CreateEntityByName( "env_particle_trail" );
if ( pTrail == NULL )
return NULL;
pTrail->m_hConstraintEntity = pConstraintEntity;
pTrail->m_iMaterialName = iMaterialName;
pTrail->m_Info.CopyFrom(info);
pTrail->m_nRefCount = 1;
pTrail->AttachToEntity( pTarget );
pTrail->Spawn();
return pTrail;
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEntityParticleTrail::Spawn()
{
BaseClass::Spawn();
/*
SetThink( &CEntityParticleTrail::BoogieThink );
SetNextThink( gpGlobals->curtime + 0.01f );
if ( HasSpawnFlags( SF_RAGDOLL_BOOGIE_ELECTRICAL ) )
{
SetContextThink( ZapThink, gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ), s_pZapContext );
}
*/
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CEntityParticleTrail::UpdateOnRemove()
{
g_pNotify->ClearEntity( this );
BaseClass::UpdateOnRemove();
}
//-----------------------------------------------------------------------------
// Force our constraint entity to be trasmitted
//-----------------------------------------------------------------------------
void CEntityParticleTrail::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
{
// Are we already marked for transmission?
if ( pInfo->m_pTransmitEdict->Get( entindex() ) )
return;
BaseClass::SetTransmit( pInfo, bAlways );
// Force our constraint entity to be sent too.
if ( m_hConstraintEntity )
{
m_hConstraintEntity->SetTransmit( pInfo, bAlways );
}
}
//-----------------------------------------------------------------------------
// Retire
//-----------------------------------------------------------------------------
void CEntityParticleTrail::IncrementRefCount()
{
if ( m_nRefCount == 0 )
{
SetContextThink( NULL, gpGlobals->curtime, s_pRetireContext );
}
++m_nRefCount;
}
void CEntityParticleTrail::DecrementRefCount()
{
--m_nRefCount;
Assert( m_nRefCount >= 0 );
if ( m_nRefCount == 0 )
{
FollowEntity( NULL );
g_pNotify->ClearEntity( this );
SetContextThink( &CEntityParticleTrail::SUB_Remove, gpGlobals->curtime + m_Info.m_flLifetime, s_pRetireContext );
}
}
//-----------------------------------------------------------------------------
// Clean up when the entity goes away.
//-----------------------------------------------------------------------------
void CEntityParticleTrail::NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t &params )
{
BaseClass::NotifySystemEvent( pNotify, eventType, params );
Assert( pNotify == GetMoveParent() );
if ( eventType == NOTIFY_EVENT_DESTROY )
{
FollowEntity( NULL );
g_pNotify->ClearEntity( this );
if ( m_nRefCount != 0 )
{
m_nRefCount = 0;
SetContextThink( &CEntityParticleTrail::SUB_Remove, gpGlobals->curtime + m_Info.m_flLifetime, s_pRetireContext );
}
}
}
//-----------------------------------------------------------------------------
// Suppression count
//-----------------------------------------------------------------------------
void CEntityParticleTrail::Destroy( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info )
{
int iMaterialName = GetMaterialIndex( STRING(info.m_strMaterialName) );
// Look for the particle trail attached to this entity + decrease refcount
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
CEntityParticleTrail *pTrail = dynamic_cast<CEntityParticleTrail*>(pChild);
if ( !pTrail || (pTrail->m_iMaterialName != iMaterialName) )
continue;
pTrail->DecrementRefCount();
}
}
//-----------------------------------------------------------------------------
// Attach to an entity
//-----------------------------------------------------------------------------
void CEntityParticleTrail::AttachToEntity( CBaseEntity *pTarget )
{
FollowEntity( pTarget );
g_pNotify->AddEntity( this, pTarget );
}

View File

@@ -0,0 +1,52 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ENTITYPARTICLETRAIL_H
#define ENTITYPARTICLETRAIL_H
#ifdef _WIN32
#pragma once
#endif
#include "baseparticleentity.h"
#include "entityparticletrail_shared.h"
//-----------------------------------------------------------------------------
// Spawns particles after the entity
//-----------------------------------------------------------------------------
class CEntityParticleTrail : public CBaseParticleEntity
{
DECLARE_DATADESC();
DECLARE_CLASS( CEntityParticleTrail, CBaseParticleEntity );
DECLARE_SERVERCLASS();
public:
static CEntityParticleTrail *Create( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info, CBaseEntity *pConstraint );
static void Destroy( CBaseEntity *pTarget, const EntityParticleTrailInfo_t &info );
void Spawn();
virtual void UpdateOnRemove();
// Force our constraint entity to be trasmitted
virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
// Clean up when the entity goes away.
virtual void NotifySystemEvent( CBaseEntity *pNotify, notify_system_event_t eventType, const notify_system_event_params_t &params );
private:
void AttachToEntity( CBaseEntity *pTarget );
void IncrementRefCount();
void DecrementRefCount();
CNetworkVar( int, m_iMaterialName );
CNetworkVarEmbedded( EntityParticleTrailInfo_t, m_Info );
CNetworkHandle( CBaseEntity, m_hConstraintEntity );
int m_nRefCount;
};
#endif // ENTITYPARTICLETRAIL_H

762
game/server/EnvBeam.cpp Normal file
View File

@@ -0,0 +1,762 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "beam_shared.h"
#include "ndebugoverlay.h"
#include "filters.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Keeps us from doing strcmps in the tracefilter.
string_t g_iszPhysicsPropClassname;
enum Touch_t
{
touch_none = 0,
touch_player_only,
touch_npc_only,
touch_player_or_npc,
touch_player_or_npc_or_physicsprop,
};
class CEnvBeam : public CBeam
{
public:
DECLARE_CLASS( CEnvBeam, CBeam );
void Spawn( void );
void Precache( void );
void Activate( void );
void StrikeThink( void );
void UpdateThink( void );
void RandomArea( void );
void RandomPoint( const Vector &vecSrc );
void Zap( const Vector &vecSrc, const Vector &vecDest );
void Strike( void );
bool PassesTouchFilters(CBaseEntity *pOther);
void InputTurnOn( inputdata_t &inputdata );
void InputTurnOff( inputdata_t &inputdata );
void InputToggle( inputdata_t &inputdata );
void InputStrikeOnce( inputdata_t &inputdata );
void TurnOn( void );
void TurnOff( void );
void Toggle( void );
const char *GetDecalName( void ){ return STRING( m_iszDecal );}
inline bool ServerSide( void )
{
if ( m_life == 0 && !HasSpawnFlags(SF_BEAM_RING) )
return true;
return false;
}
DECLARE_DATADESC();
void BeamUpdateVars( void );
int m_active;
int m_spriteTexture;
string_t m_iszStartEntity;
string_t m_iszEndEntity;
float m_life;
float m_boltWidth;
float m_noiseAmplitude;
int m_speed;
float m_restrike;
string_t m_iszSpriteName;
int m_frameStart;
float m_radius;
Touch_t m_TouchType;
string_t m_iFilterName;
EHANDLE m_hFilter;
string_t m_iszDecal;
COutputEvent m_OnTouchedByEntity;
};
LINK_ENTITY_TO_CLASS( env_beam, CEnvBeam );
BEGIN_DATADESC( CEnvBeam )
DEFINE_FIELD( m_active, FIELD_INTEGER ),
DEFINE_FIELD( m_spriteTexture, FIELD_INTEGER ),
DEFINE_KEYFIELD( m_iszStartEntity, FIELD_STRING, "LightningStart" ),
DEFINE_KEYFIELD( m_iszEndEntity, FIELD_STRING, "LightningEnd" ),
DEFINE_KEYFIELD( m_life, FIELD_FLOAT, "life" ),
DEFINE_KEYFIELD( m_boltWidth, FIELD_FLOAT, "BoltWidth" ),
DEFINE_KEYFIELD( m_noiseAmplitude, FIELD_FLOAT, "NoiseAmplitude" ),
DEFINE_KEYFIELD( m_speed, FIELD_INTEGER, "TextureScroll" ),
DEFINE_KEYFIELD( m_restrike, FIELD_FLOAT, "StrikeTime" ),
DEFINE_KEYFIELD( m_iszSpriteName, FIELD_STRING, "texture" ),
DEFINE_KEYFIELD( m_frameStart, FIELD_INTEGER, "framestart" ),
DEFINE_KEYFIELD( m_radius, FIELD_FLOAT, "Radius" ),
DEFINE_KEYFIELD( m_TouchType, FIELD_INTEGER, "TouchType" ),
DEFINE_KEYFIELD( m_iFilterName, FIELD_STRING, "filtername" ),
DEFINE_KEYFIELD( m_iszDecal, FIELD_STRING, "decalname" ),
DEFINE_FIELD( m_hFilter, FIELD_EHANDLE ),
// Function Pointers
DEFINE_FUNCTION( StrikeThink ),
DEFINE_FUNCTION( UpdateThink ),
// Input functions
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
DEFINE_INPUTFUNC( FIELD_VOID, "StrikeOnce", InputStrikeOnce ),
DEFINE_OUTPUT( m_OnTouchedByEntity, "OnTouchedByEntity" ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::Spawn( void )
{
if ( !m_iszSpriteName )
{
SetThink( &CEnvBeam::SUB_Remove );
return;
}
BaseClass::Spawn();
m_noiseAmplitude = MIN(MAX_BEAM_NOISEAMPLITUDE, m_noiseAmplitude);
// Check for tapering
if ( HasSpawnFlags( SF_BEAM_TAPEROUT ) )
{
SetWidth( m_boltWidth );
SetEndWidth( 0 );
}
else
{
SetWidth( m_boltWidth );
SetEndWidth( GetWidth() ); // Note: EndWidth is not scaled
}
if ( ServerSide() )
{
SetThink( &CEnvBeam::UpdateThink );
SetNextThink( gpGlobals->curtime );
SetFireTime( gpGlobals->curtime );
if ( GetEntityName() != NULL_STRING )
{
if ( !(m_spawnflags & SF_BEAM_STARTON) )
{
AddEffects( EF_NODRAW );
m_active = 0;
SetNextThink( TICK_NEVER_THINK );
}
else
{
m_active = 1;
}
}
}
else
{
m_active = 0;
if ( !GetEntityName() || FBitSet(m_spawnflags, SF_BEAM_STARTON) )
{
SetThink( &CEnvBeam::StrikeThink );
SetNextThink( gpGlobals->curtime + 1.0f );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::Precache( void )
{
if ( !Q_stristr( STRING(m_iszSpriteName), ".vmt" ) )
{
// HACK/YWB: This was almost always the laserbeam.spr, so alloc'ing the name a second time with the proper extension isn't going to
// kill us on memrory.
//Warning( "Level Design Error: %s (%i:%s) Sprite name (%s) missing .vmt extension!\n",
// STRING( m_iClassname ), entindex(), GetEntityName(), STRING(m_iszSpriteName) );
char fixedname[ 512 ];
Q_strncpy( fixedname, STRING( m_iszSpriteName ), sizeof( fixedname ) );
Q_SetExtension( fixedname, ".vmt", sizeof( fixedname ) );
m_iszSpriteName = AllocPooledString( fixedname );
}
g_iszPhysicsPropClassname = AllocPooledString( "prop_physics" );
m_spriteTexture = PrecacheModel( STRING(m_iszSpriteName) );
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::Activate( void )
{
// Get a handle to my filter entity if there is one
if (m_iFilterName != NULL_STRING)
{
m_hFilter = dynamic_cast<CBaseFilter *>(gEntList.FindEntityByName( NULL, m_iFilterName ));
}
BaseClass::Activate();
if ( ServerSide() )
BeamUpdateVars();
}
//-----------------------------------------------------------------------------
// Purpose: Input handler to turn the lightning on either continually or for
// interval refiring.
//-----------------------------------------------------------------------------
void CEnvBeam::InputTurnOn( inputdata_t &inputdata )
{
if ( !m_active )
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler to turn the lightning off.
//-----------------------------------------------------------------------------
void CEnvBeam::InputTurnOff( inputdata_t &inputdata )
{
if ( m_active )
{
TurnOff();
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler to toggle the lightning on/off.
//-----------------------------------------------------------------------------
void CEnvBeam::InputToggle( inputdata_t &inputdata )
{
if ( m_active )
{
TurnOff();
}
else
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for making the beam strike once. This will not affect
// any interval refiring that might be going on. If the lifetime is set
// to zero (infinite) it will turn on and stay on.
//-----------------------------------------------------------------------------
void CEnvBeam::InputStrikeOnce( inputdata_t &inputdata )
{
Strike();
}
//-----------------------------------------------------------------------------
// Purpose: Turns the lightning on. If it is set for interval refiring, it will
// begin doing so. If it is set to be continually on, it will do so.
//-----------------------------------------------------------------------------
void CEnvBeam::TurnOn( void )
{
m_active = 1;
if ( ServerSide() )
{
RemoveEffects( EF_NODRAW );
DoSparks( GetAbsStartPos(), GetAbsEndPos() );
SetThink( &CEnvBeam::UpdateThink );
SetNextThink( gpGlobals->curtime );
SetFireTime( gpGlobals->curtime );
}
else
{
SetThink( &CEnvBeam::StrikeThink );
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::TurnOff( void )
{
m_active = 0;
if ( ServerSide() )
{
AddEffects( EF_NODRAW );
}
SetNextThink( TICK_NEVER_THINK );
SetThink( NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Think function for striking at intervals.
//-----------------------------------------------------------------------------
void CEnvBeam::StrikeThink( void )
{
if ( m_life != 0 )
{
if ( m_spawnflags & SF_BEAM_RANDOM )
SetNextThink( gpGlobals->curtime + m_life + random->RandomFloat( 0, m_restrike ) );
else
SetNextThink( gpGlobals->curtime + m_life + m_restrike );
}
m_active = 1;
if (!m_iszEndEntity)
{
if (!m_iszStartEntity)
{
RandomArea( );
}
else
{
CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) );
if (pStart != NULL)
{
RandomPoint( pStart->GetAbsOrigin() );
}
else
{
Msg( "env_beam: unknown entity \"%s\"\n", STRING(m_iszStartEntity) );
}
}
return;
}
Strike();
}
//-----------------------------------------------------------------------------
// Purpose: Strikes once for its configured lifetime.
//-----------------------------------------------------------------------------
void CEnvBeam::Strike( void )
{
CBroadcastRecipientFilter filter;
CBaseEntity *pStart = RandomTargetname( STRING(m_iszStartEntity) );
CBaseEntity *pEnd = RandomTargetname( STRING(m_iszEndEntity) );
if ( pStart == NULL || pEnd == NULL )
return;
m_speed = clamp( (int) m_speed, 0, (int) MAX_BEAM_SCROLLSPEED );
int pointStart = IsStaticPointEntity( pStart );
int pointEnd = IsStaticPointEntity( pEnd );
if ( pointStart || pointEnd )
{
if ( m_spawnflags & SF_BEAM_RING )
{
// don't work
return;
}
te->BeamEntPoint( filter, 0.0,
pointStart ? 0 : pStart->entindex(),
pointStart ? &pStart->GetAbsOrigin() : NULL,
pointEnd ? 0 : pEnd->entindex(),
pointEnd ? &pEnd->GetAbsOrigin() : NULL,
m_spriteTexture,
0, // No halo
m_frameStart,
(int)m_flFrameRate,
m_life,
m_boltWidth,
m_boltWidth, // End width
0, // No fade
m_noiseAmplitude,
m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a,
m_speed );
}
else
{
if ( m_spawnflags & SF_BEAM_RING)
{
te->BeamRing( filter, 0.0,
pStart->entindex(),
pEnd->entindex(),
m_spriteTexture,
0, // No halo
m_frameStart,
(int)m_flFrameRate,
m_life,
m_boltWidth,
0, // No spread
m_noiseAmplitude,
m_clrRender->r,
m_clrRender->g,
m_clrRender->b,
m_clrRender->a,
m_speed );
}
else
{
te->BeamEnts( filter, 0.0,
pStart->entindex(),
pEnd->entindex(),
m_spriteTexture,
0, // No halo
m_frameStart,
(int)m_flFrameRate,
m_life,
m_boltWidth,
m_boltWidth, // End width
0, // No fade
m_noiseAmplitude,
m_clrRender->r,
m_clrRender->g,
m_clrRender->b,
m_clrRender->a,
m_speed );
}
}
DoSparks( pStart->GetAbsOrigin(), pEnd->GetAbsOrigin() );
if ( m_flDamage > 0 )
{
trace_t tr;
UTIL_TraceLine( pStart->GetAbsOrigin(), pEnd->GetAbsOrigin(), MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
BeamDamageInstant( &tr, m_flDamage );
}
}
class CTraceFilterPlayersNPCs : public ITraceFilter
{
public:
bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
{
CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
if ( pEntity )
{
if ( pEntity->IsPlayer() || pEntity->MyNPCPointer() )
return true;
}
return false;
}
virtual TraceType_t GetTraceType() const
{
return TRACE_ENTITIES_ONLY;
}
};
class CTraceFilterPlayersNPCsPhysicsProps : public ITraceFilter
{
public:
bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
{
CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
if ( pEntity )
{
if ( pEntity->IsPlayer() || pEntity->MyNPCPointer() || pEntity->m_iClassname == g_iszPhysicsPropClassname )
return true;
}
return false;
}
virtual TraceType_t GetTraceType() const
{
return TRACE_ENTITIES_ONLY;
}
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CEnvBeam::PassesTouchFilters(CBaseEntity *pOther)
{
bool fPassedSoFar = false;
// Touched some player or NPC!
if( m_TouchType != touch_npc_only )
{
if( pOther->IsPlayer() )
{
fPassedSoFar = true;
}
}
if( m_TouchType != touch_player_only )
{
if( pOther->IsNPC() )
{
fPassedSoFar = true;
}
}
if( m_TouchType == touch_player_or_npc_or_physicsprop )
{
if( pOther->m_iClassname == g_iszPhysicsPropClassname )
{
fPassedSoFar = true;
}
}
if( fPassedSoFar )
{
CBaseFilter* pFilter = (CBaseFilter*)(m_hFilter.Get());
return (!pFilter) ? true : pFilter->PassesFilter( this, pOther );
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::UpdateThink( void )
{
// Apply damage every 1/10th of a second.
if ( ( m_flDamage > 0 ) && ( gpGlobals->curtime >= m_flFireTime + 0.1 ) )
{
trace_t tr;
UTIL_TraceLine( GetAbsStartPos(), GetAbsEndPos(), MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
BeamDamage( &tr );
// BeamDamage calls RelinkBeam, so no need to call it again.
}
else
{
RelinkBeam();
}
if( m_TouchType != touch_none )
{
trace_t tr;
Ray_t ray;
ray.Init( GetAbsStartPos(), GetAbsEndPos() );
if( m_TouchType == touch_player_or_npc_or_physicsprop )
{
CTraceFilterPlayersNPCsPhysicsProps traceFilter;
enginetrace->TraceRay( ray, MASK_SHOT, &traceFilter, &tr );
}
else
{
CTraceFilterPlayersNPCs traceFilter;
enginetrace->TraceRay( ray, MASK_SHOT, &traceFilter, &tr );
}
if( tr.fraction != 1.0 && PassesTouchFilters( tr.m_pEnt ) )
{
m_OnTouchedByEntity.FireOutput( tr.m_pEnt, this, 0 );
return;
}
}
SetNextThink( gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &vecSrc -
// &vecDest -
//-----------------------------------------------------------------------------
void CEnvBeam::Zap( const Vector &vecSrc, const Vector &vecDest )
{
CBroadcastRecipientFilter filter;
te->BeamPoints( filter, 0.0,
&vecSrc,
&vecDest,
m_spriteTexture,
0, // No halo
m_frameStart,
(int)m_flFrameRate,
m_life,
m_boltWidth,
m_boltWidth, // End width
0, // No fade
m_noiseAmplitude,
m_clrRender->r,
m_clrRender->g,
m_clrRender->b,
m_clrRender->a,
m_speed );
DoSparks( vecSrc, vecDest );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::RandomArea( void )
{
int iLoops = 0;
for (iLoops = 0; iLoops < 10; iLoops++)
{
Vector vecSrc = GetAbsOrigin();
Vector vecDir1 = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) );
VectorNormalize( vecDir1 );
trace_t tr1;
UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr1 );
if (tr1.fraction == 1.0)
continue;
Vector vecDir2;
do {
vecDir2 = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) );
} while (DotProduct(vecDir1, vecDir2 ) > 0);
VectorNormalize( vecDir2 );
trace_t tr2;
UTIL_TraceLine( vecSrc, vecSrc + vecDir2 * m_radius, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr2 );
if (tr2.fraction == 1.0)
continue;
if ((tr1.endpos - tr2.endpos).Length() < m_radius * 0.1)
continue;
UTIL_TraceLine( tr1.endpos, tr2.endpos, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr2 );
if (tr2.fraction != 1.0)
continue;
Zap( tr1.endpos, tr2.endpos );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : vecSrc -
//-----------------------------------------------------------------------------
void CEnvBeam::RandomPoint( const Vector &vecSrc )
{
int iLoops = 0;
for (iLoops = 0; iLoops < 10; iLoops++)
{
Vector vecDir1 = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) );
VectorNormalize( vecDir1 );
trace_t tr1;
UTIL_TraceLine( vecSrc, vecSrc + vecDir1 * m_radius, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr1 );
if ((tr1.endpos - vecSrc).Length() < m_radius * 0.1)
continue;
if (tr1.fraction == 1.0)
continue;
Zap( vecSrc, tr1.endpos );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvBeam::BeamUpdateVars( void )
{
CBaseEntity *pStart = gEntList.FindEntityByName( NULL, m_iszStartEntity );
CBaseEntity *pEnd = gEntList.FindEntityByName( NULL, m_iszEndEntity );
if (( pStart == NULL ) || ( pEnd == NULL ))
{
return;
}
m_nNumBeamEnts = 2;
m_speed = clamp( (int) m_speed, 0, (int) MAX_BEAM_SCROLLSPEED );
// NOTE: If the end entity is the beam itself (and the start entity
// isn't *also* the beam itself, we've got problems. This is a problem
// because SetAbsStartPos actually sets the entity's origin.
if ( ( pEnd == this ) && ( pStart != this ) )
{
DevMsg("env_beams cannot have the end entity be the beam itself\n"
"unless the start entity is also the beam itself!\n" );
Assert(0);
}
SetModelName( m_iszSpriteName );
SetTexture( m_spriteTexture );
SetType( BEAM_ENTPOINT );
if ( IsStaticPointEntity( pStart ) )
{
SetAbsStartPos( pStart->GetAbsOrigin() );
}
else
{
SetStartEntity( pStart );
}
if ( IsStaticPointEntity( pEnd ) )
{
SetAbsEndPos( pEnd->GetAbsOrigin() );
}
else
{
SetEndEntity( pEnd );
}
RelinkBeam();
SetWidth( MIN(MAX_BEAM_WIDTH, m_boltWidth) );
SetNoise( MIN(MAX_BEAM_NOISEAMPLITUDE, m_noiseAmplitude) );
SetFrame( m_frameStart );
SetScrollRate( m_speed );
if ( m_spawnflags & SF_BEAM_SHADEIN )
{
SetBeamFlags( FBEAM_SHADEIN );
}
else if ( m_spawnflags & SF_BEAM_SHADEOUT )
{
SetBeamFlags( FBEAM_SHADEOUT );
}
}

200
game/server/EnvFade.cpp Normal file
View File

@@ -0,0 +1,200 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "shake.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CEnvFade : public CLogicalEntity
{
private:
float m_Duration;
float m_HoldTime;
COutputEvent m_OnBeginFade;
DECLARE_DATADESC();
public:
DECLARE_CLASS( CEnvFade, CLogicalEntity );
virtual void Spawn( void );
inline float Duration( void ) { return m_Duration; }
inline float HoldTime( void ) { return m_HoldTime; }
inline void SetDuration( float duration ) { m_Duration = duration; }
inline void SetHoldTime( float hold ) { m_HoldTime = hold; }
int DrawDebugTextOverlays(void);
// Inputs
void InputFade( inputdata_t &inputdata );
};
LINK_ENTITY_TO_CLASS( env_fade, CEnvFade );
BEGIN_DATADESC( CEnvFade )
DEFINE_KEYFIELD( m_Duration, FIELD_FLOAT, "duration" ),
DEFINE_KEYFIELD( m_HoldTime, FIELD_FLOAT, "holdtime" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Fade", InputFade ),
DEFINE_OUTPUT( m_OnBeginFade, "OnBeginFade"),
END_DATADESC()
#define SF_FADE_IN 0x0001 // Fade in, not out
#define SF_FADE_MODULATE 0x0002 // Modulate, don't blend
#define SF_FADE_ONLYONE 0x0004
#define SF_FADE_STAYOUT 0x0008
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvFade::Spawn( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Input handler that does the screen fade.
//-----------------------------------------------------------------------------
void CEnvFade::InputFade( inputdata_t &inputdata )
{
int fadeFlags = 0;
if ( m_spawnflags & SF_FADE_IN )
{
fadeFlags |= FFADE_IN;
}
else
{
fadeFlags |= FFADE_OUT;
}
if ( m_spawnflags & SF_FADE_MODULATE )
{
fadeFlags |= FFADE_MODULATE;
}
if ( m_spawnflags & SF_FADE_STAYOUT )
{
fadeFlags |= FFADE_STAYOUT;
}
if ( m_spawnflags & SF_FADE_ONLYONE )
{
if ( inputdata.pActivator && inputdata.pActivator->IsNetClient() )
{
UTIL_ScreenFade( inputdata.pActivator, m_clrRender, Duration(), HoldTime(), fadeFlags );
}
}
else
{
UTIL_ScreenFadeAll( m_clrRender, Duration(), HoldTime(), fadeFlags|FFADE_PURGE );
}
m_OnBeginFade.FireOutput( inputdata.pActivator, this );
}
//-----------------------------------------------------------------------------
// Purpose: Fetches the arguments from the command line for the fadein and fadeout
// console commands.
// Input : flTime - Returns the fade time in seconds (the time to fade in or out)
// clrFade - Returns the color to fade to or from.
//-----------------------------------------------------------------------------
static void GetFadeParms( const CCommand &args, float &flTime, color32 &clrFade)
{
flTime = 2.0f;
if ( args.ArgC() > 1 )
{
flTime = atof( args[1] );
}
clrFade.r = 0;
clrFade.g = 0;
clrFade.b = 0;
clrFade.a = 255;
if ( args.ArgC() > 4 )
{
clrFade.r = atoi( args[2] );
clrFade.g = atoi( args[3] );
clrFade.b = atoi( args[4] );
if ( args.ArgC() == 5 )
{
clrFade.a = atoi( args[5] );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Console command to fade out to a given color.
//-----------------------------------------------------------------------------
static void CC_FadeOut( const CCommand &args )
{
float flTime;
color32 clrFade;
GetFadeParms( args, flTime, clrFade );
CBasePlayer *pPlayer = UTIL_GetCommandClient();
UTIL_ScreenFade( pPlayer, clrFade, flTime, 0, FFADE_OUT | FFADE_PURGE | FFADE_STAYOUT );
}
static ConCommand fadeout("fadeout", CC_FadeOut, "fadeout {time r g b}: Fades the screen to black or to the specified color over the given number of seconds.", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose: Console command to fade in from a given color.
//-----------------------------------------------------------------------------
static void CC_FadeIn( const CCommand &args )
{
float flTime;
color32 clrFade;
GetFadeParms( args, flTime, clrFade );
CBasePlayer *pPlayer = UTIL_GetCommandClient();
UTIL_ScreenFade( pPlayer, clrFade, flTime, 0, FFADE_IN | FFADE_PURGE );
}
static ConCommand fadein("fadein", CC_FadeIn, "fadein {time r g b}: Fades the screen in from black or from the specified color over the given number of seconds.", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose: Draw any debug text overlays
// Output : Current text offset from the top
//-----------------------------------------------------------------------------
int CEnvFade::DrawDebugTextOverlays( void )
{
int text_offset = BaseClass::DrawDebugTextOverlays();
if (m_debugOverlays & OVERLAY_TEXT_BIT)
{
char tempstr[512];
// print duration
Q_snprintf(tempstr,sizeof(tempstr)," duration: %f", m_Duration);
EntityText(text_offset,tempstr,0);
text_offset++;
// print hold time
Q_snprintf(tempstr,sizeof(tempstr)," hold time: %f", m_HoldTime);
EntityText(text_offset,tempstr,0);
text_offset++;
}
return text_offset;
}

142
game/server/EnvHudHint.cpp Normal file
View File

@@ -0,0 +1,142 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "engine/IEngineSound.h"
#include "baseentity.h"
#include "entityoutput.h"
#include "recipientfilter.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define SF_HUDHINT_ALLPLAYERS 0x0001
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CEnvHudHint : public CPointEntity
{
public:
DECLARE_CLASS( CEnvHudHint, CPointEntity );
void Spawn( void );
void Precache( void );
private:
inline bool AllPlayers( void ) { return (m_spawnflags & SF_HUDHINT_ALLPLAYERS) != 0; }
void InputShowHudHint( inputdata_t &inputdata );
void InputHideHudHint( inputdata_t &inputdata );
string_t m_iszMessage;
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( env_hudhint, CEnvHudHint );
BEGIN_DATADESC( CEnvHudHint )
DEFINE_KEYFIELD( m_iszMessage, FIELD_STRING, "message" ),
DEFINE_INPUTFUNC( FIELD_VOID, "ShowHudHint", InputShowHudHint ),
DEFINE_INPUTFUNC( FIELD_VOID, "HideHudHint", InputHideHudHint ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvHudHint::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvHudHint::Precache( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for showing the message and/or playing the sound.
//-----------------------------------------------------------------------------
void CEnvHudHint::InputShowHudHint( inputdata_t &inputdata )
{
if ( AllPlayers() )
{
CReliableBroadcastRecipientFilter user;
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(m_iszMessage) );
MessageEnd();
}
else
{
CBaseEntity *pPlayer = NULL;
if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
{
pPlayer = inputdata.pActivator;
}
else
{
pPlayer = UTIL_GetLocalPlayer();
}
if ( !pPlayer || !pPlayer->IsNetClient() )
return;
CSingleUserRecipientFilter user( (CBasePlayer *)pPlayer );
user.MakeReliable();
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(m_iszMessage) );
MessageEnd();
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvHudHint::InputHideHudHint( inputdata_t &inputdata )
{
if ( AllPlayers() )
{
CReliableBroadcastRecipientFilter user;
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(NULL_STRING) );
MessageEnd();
}
else
{
CBaseEntity *pPlayer = NULL;
if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
{
pPlayer = inputdata.pActivator;
}
else
{
pPlayer = UTIL_GetLocalPlayer();
}
if ( !pPlayer || !pPlayer->IsNetClient() )
return;
CSingleUserRecipientFilter user( (CBasePlayer *)pPlayer );
user.MakeReliable();
UserMessageBegin( user, "KeyHintText" );
WRITE_BYTE( 1 ); // one message
WRITE_STRING( STRING(NULL_STRING) );
MessageEnd();
}
}

250
game/server/EnvLaser.cpp Normal file
View File

@@ -0,0 +1,250 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A special kind of beam effect that traces from its start position to
// its end position and stops if it hits anything.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "EnvLaser.h"
#include "Sprite.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( env_laser, CEnvLaser );
BEGIN_DATADESC( CEnvLaser )
DEFINE_KEYFIELD( m_iszLaserTarget, FIELD_STRING, "LaserTarget" ),
DEFINE_FIELD( m_pSprite, FIELD_CLASSPTR ),
DEFINE_KEYFIELD( m_iszSpriteName, FIELD_STRING, "EndSprite" ),
DEFINE_FIELD( m_firePosition, FIELD_VECTOR ),
DEFINE_KEYFIELD( m_flStartFrame, FIELD_FLOAT, "framestart" ),
// Function Pointers
DEFINE_FUNCTION( StrikeThink ),
// Input functions
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::Spawn( void )
{
if ( !GetModelName() )
{
SetThink( &CEnvLaser::SUB_Remove );
return;
}
SetSolid( SOLID_NONE ); // Remove model & collisions
SetThink( &CEnvLaser::StrikeThink );
SetEndWidth( GetWidth() ); // Note: EndWidth is not scaled
PointsInit( GetLocalOrigin(), GetLocalOrigin() );
Precache( );
if ( !m_pSprite && m_iszSpriteName != NULL_STRING )
{
m_pSprite = CSprite::SpriteCreate( STRING(m_iszSpriteName), GetAbsOrigin(), TRUE );
}
else
{
m_pSprite = NULL;
}
if ( m_pSprite )
{
m_pSprite->SetParent( GetMoveParent() );
m_pSprite->SetTransparency( kRenderGlow, m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a, m_nRenderFX );
}
if ( GetEntityName() != NULL_STRING && !(m_spawnflags & SF_BEAM_STARTON) )
{
TurnOff();
}
else
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::Precache( void )
{
SetModelIndex( PrecacheModel( STRING( GetModelName() ) ) );
if ( m_iszSpriteName != NULL_STRING )
PrecacheModel( STRING(m_iszSpriteName) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CEnvLaser::KeyValue( const char *szKeyName, const char *szValue )
{
if (FStrEq(szKeyName, "width"))
{
SetWidth( atof(szValue) );
}
else if (FStrEq(szKeyName, "NoiseAmplitude"))
{
SetNoise( atoi(szValue) );
}
else if (FStrEq(szKeyName, "TextureScroll"))
{
SetScrollRate( atoi(szValue) );
}
else if (FStrEq(szKeyName, "texture"))
{
SetModelName( AllocPooledString(szValue) );
}
else
{
BaseClass::KeyValue( szKeyName, szValue );
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether the laser is currently active.
//-----------------------------------------------------------------------------
int CEnvLaser::IsOn( void )
{
if ( IsEffectActive( EF_NODRAW ) )
return 0;
return 1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::InputTurnOn( inputdata_t &inputdata )
{
if (!IsOn())
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::InputTurnOff( inputdata_t &inputdata )
{
if (IsOn())
{
TurnOff();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::InputToggle( inputdata_t &inputdata )
{
if ( IsOn() )
{
TurnOff();
}
else
{
TurnOn();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::TurnOff( void )
{
AddEffects( EF_NODRAW );
if ( m_pSprite )
m_pSprite->TurnOff();
SetNextThink( TICK_NEVER_THINK );
SetThink( NULL );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::TurnOn( void )
{
RemoveEffects( EF_NODRAW );
if ( m_pSprite )
m_pSprite->TurnOn();
m_flFireTime = gpGlobals->curtime;
SetThink( &CEnvLaser::StrikeThink );
//
// Call StrikeThink here to update the end position, otherwise we will see
// the beam in the wrong place for one frame since we cleared the nodraw flag.
//
StrikeThink();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::FireAtPoint( trace_t &tr )
{
SetAbsEndPos( tr.endpos );
if ( m_pSprite )
{
UTIL_SetOrigin( m_pSprite, tr.endpos );
}
// Apply damage and do sparks every 1/10th of a second.
if ( gpGlobals->curtime >= m_flFireTime + 0.1 )
{
BeamDamage( &tr );
DoSparks( GetAbsStartPos(), tr.endpos );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvLaser::StrikeThink( void )
{
CBaseEntity *pEnd = RandomTargetname( STRING( m_iszLaserTarget ) );
Vector vecFireAt = GetAbsEndPos();
if ( pEnd )
{
vecFireAt = pEnd->GetAbsOrigin();
}
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), vecFireAt, MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
FireAtPoint( tr );
SetNextThink( gpGlobals->curtime );
}

51
game/server/EnvLaser.h Normal file
View File

@@ -0,0 +1,51 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ENVLASER_H
#define ENVLASER_H
#ifdef _WIN32
#pragma once
#endif
#include "baseentity.h"
#include "beam_shared.h"
#include "entityoutput.h"
class CSprite;
class CEnvLaser : public CBeam
{
DECLARE_CLASS( CEnvLaser, CBeam );
public:
void Spawn( void );
void Precache( void );
bool KeyValue( const char *szKeyName, const char *szValue );
void TurnOn( void );
void TurnOff( void );
int IsOn( void );
void FireAtPoint( trace_t &point );
void StrikeThink( void );
void InputTurnOn( inputdata_t &inputdata );
void InputTurnOff( inputdata_t &inputdata );
void InputToggle( inputdata_t &inputdata );
DECLARE_DATADESC();
string_t m_iszLaserTarget; // Name of entity or entities to strike at, randomly picked if more than one match.
CSprite *m_pSprite;
string_t m_iszSpriteName;
Vector m_firePosition;
float m_flStartFrame;
};
#endif // ENVLASER_H

278
game/server/EnvMessage.cpp Normal file
View File

@@ -0,0 +1,278 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements visual effects entities: sprites, beams, bubbles, etc.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "EnvMessage.h"
#include "engine/IEngineSound.h"
#include "KeyValues.h"
#include "filesystem.h"
#include "Color.h"
#include "gamestats.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( env_message, CMessage );
BEGIN_DATADESC( CMessage )
DEFINE_KEYFIELD( m_iszMessage, FIELD_STRING, "message" ),
DEFINE_KEYFIELD( m_sNoise, FIELD_SOUNDNAME, "messagesound" ),
DEFINE_KEYFIELD( m_MessageAttenuation, FIELD_INTEGER, "messageattenuation" ),
DEFINE_KEYFIELD( m_MessageVolume, FIELD_FLOAT, "messagevolume" ),
DEFINE_FIELD( m_Radius, FIELD_FLOAT ),
DEFINE_INPUTFUNC( FIELD_VOID, "ShowMessage", InputShowMessage ),
DEFINE_OUTPUT(m_OnShowMessage, "OnShowMessage"),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMessage::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
switch( m_MessageAttenuation )
{
case 1: // Medium radius
m_Radius = ATTN_STATIC;
break;
case 2: // Large radius
m_Radius = ATTN_NORM;
break;
case 3: //EVERYWHERE
m_Radius = ATTN_NONE;
break;
default:
case 0: // Small radius
m_Radius = SNDLVL_IDLE;
break;
}
m_MessageAttenuation = 0;
// Remap volume from [0,10] to [0,1].
m_MessageVolume *= 0.1;
// No volume, use normal
if ( m_MessageVolume <= 0 )
{
m_MessageVolume = 1.0;
}
}
void CMessage::Precache( void )
{
if ( m_sNoise != NULL_STRING )
{
PrecacheScriptSound( STRING(m_sNoise) );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for showing the message and/or playing the sound.
//-----------------------------------------------------------------------------
void CMessage::InputShowMessage( inputdata_t &inputdata )
{
CBaseEntity *pPlayer = NULL;
if ( m_spawnflags & SF_MESSAGE_ALL )
{
UTIL_ShowMessageAll( STRING( m_iszMessage ) );
}
else
{
if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
{
pPlayer = inputdata.pActivator;
}
else
{
pPlayer = (gpGlobals->maxClients > 1) ? NULL : UTIL_GetLocalPlayer();
}
if ( pPlayer && pPlayer->IsPlayer() )
{
UTIL_ShowMessage( STRING( m_iszMessage ), ToBasePlayer( pPlayer ) );
}
}
if ( m_sNoise != NULL_STRING )
{
CPASAttenuationFilter filter( this );
EmitSound_t ep;
ep.m_nChannel = CHAN_BODY;
ep.m_pSoundName = (char*)STRING(m_sNoise);
ep.m_flVolume = m_MessageVolume;
ep.m_SoundLevel = ATTN_TO_SNDLVL( m_Radius );
EmitSound( filter, entindex(), ep );
}
if ( m_spawnflags & SF_MESSAGE_ONCE )
{
UTIL_Remove( this );
}
m_OnShowMessage.FireOutput( inputdata.pActivator, this );
}
void CMessage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
inputdata_t inputdata;
inputdata.pActivator = NULL;
inputdata.pCaller = NULL;
InputShowMessage( inputdata );
}
class CCredits : public CPointEntity
{
public:
DECLARE_CLASS( CMessage, CPointEntity );
DECLARE_DATADESC();
void Spawn( void );
void InputRollCredits( inputdata_t &inputdata );
void InputRollOutroCredits( inputdata_t &inputdata );
void InputShowLogo( inputdata_t &inputdata );
void InputSetLogoLength( inputdata_t &inputdata );
COutputEvent m_OnCreditsDone;
virtual void OnRestore();
private:
void RollOutroCredits();
bool m_bRolledOutroCredits;
float m_flLogoLength;
};
LINK_ENTITY_TO_CLASS( env_credits, CCredits );
BEGIN_DATADESC( CCredits )
DEFINE_INPUTFUNC( FIELD_VOID, "RollCredits", InputRollCredits ),
DEFINE_INPUTFUNC( FIELD_VOID, "RollOutroCredits", InputRollOutroCredits ),
DEFINE_INPUTFUNC( FIELD_VOID, "ShowLogo", InputShowLogo ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "SetLogoLength", InputSetLogoLength ),
DEFINE_OUTPUT( m_OnCreditsDone, "OnCreditsDone"),
DEFINE_FIELD( m_bRolledOutroCredits, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flLogoLength, FIELD_FLOAT )
END_DATADESC()
void CCredits::Spawn( void )
{
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
}
static void CreditsDone_f( void )
{
CCredits *pCredits = (CCredits*)gEntList.FindEntityByClassname( NULL, "env_credits" );
if ( pCredits )
{
pCredits->m_OnCreditsDone.FireOutput( pCredits, pCredits );
}
}
static ConCommand creditsdone("creditsdone", CreditsDone_f );
extern ConVar sv_unlockedchapters;
void CCredits::OnRestore()
{
BaseClass::OnRestore();
if ( m_bRolledOutroCredits )
{
// Roll them again so that the client .dll will send the "creditsdone" message and we'll
// actually get back to the main menu
RollOutroCredits();
}
}
void CCredits::RollOutroCredits()
{
sv_unlockedchapters.SetValue( "26" );
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 3 );
MessageEnd();
}
void CCredits::InputRollOutroCredits( inputdata_t &inputdata )
{
RollOutroCredits();
// In case we save restore
m_bRolledOutroCredits = true;
gamestats->Event_Credits();
}
void CCredits::InputShowLogo( inputdata_t &inputdata )
{
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
if ( m_flLogoLength )
{
UserMessageBegin( user, "LogoTimeMsg" );
WRITE_FLOAT( m_flLogoLength );
MessageEnd();
}
else
{
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 1 );
MessageEnd();
}
}
void CCredits::InputSetLogoLength( inputdata_t &inputdata )
{
m_flLogoLength = inputdata.value.Float();
}
void CCredits::InputRollCredits( inputdata_t &inputdata )
{
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
UserMessageBegin( user, "CreditsMsg" );
WRITE_BYTE( 2 );
MessageEnd();
}

48
game/server/EnvMessage.h Normal file
View File

@@ -0,0 +1,48 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef ENVMESSAGE_H
#define ENVMESSAGE_H
#ifdef _WIN32
#pragma once
#endif
#include "baseentity.h"
#include "entityoutput.h"
#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out
#define SF_MESSAGE_ALL 0x0002 // Send to all clients
class CMessage : public CPointEntity
{
public:
DECLARE_CLASS( CMessage, CPointEntity );
void Spawn( void );
void Precache( void );
inline void SetMessage( string_t iszMessage ) { m_iszMessage = iszMessage; }
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
private:
void InputShowMessage( inputdata_t &inputdata );
string_t m_iszMessage; // Message to display.
float m_MessageVolume;
int m_MessageAttenuation;
float m_Radius;
DECLARE_DATADESC();
string_t m_sNoise;
COutputEvent m_OnShowMessage;
};
#endif // ENVMESSAGE_H

413
game/server/EnvShake.cpp Normal file
View File

@@ -0,0 +1,413 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements a screen shake effect that can also shake physics objects.
//
// NOTE: UTIL_ScreenShake() will only shake players who are on the ground
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "shake.h"
#include "physics_saverestore.h"
#include "rope.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class CPhysicsShake : public IMotionEvent
{
DECLARE_SIMPLE_DATADESC();
public:
virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
{
Vector contact;
if ( !pObject->GetContactPoint( &contact, NULL ) )
return SIM_NOTHING;
// fudge the force a bit to make it more dramatic
pObject->CalculateForceOffset( m_force * (1.0f + pObject->GetMass()*0.4f), contact, &linear, &angular );
return SIM_LOCAL_FORCE;
}
Vector m_force;
};
BEGIN_SIMPLE_DATADESC( CPhysicsShake )
DEFINE_FIELD( m_force, FIELD_VECTOR ),
END_DATADESC()
class CEnvShake : public CPointEntity
{
private:
float m_Amplitude;
float m_Frequency;
float m_Duration;
float m_Radius; // radius of 0 means all players
float m_stopTime;
float m_nextShake;
float m_currentAmp;
Vector m_maxForce;
IPhysicsMotionController *m_pShakeController;
CPhysicsShake m_shakeCallback;
DECLARE_DATADESC();
public:
DECLARE_CLASS( CEnvShake, CPointEntity );
~CEnvShake( void );
virtual void Spawn( void );
virtual void OnRestore( void );
inline float Amplitude( void ) { return m_Amplitude; }
inline float Frequency( void ) { return m_Frequency; }
inline float Duration( void ) { return m_Duration; }
float Radius( bool bPlayers = true );
inline void SetAmplitude( float amplitude ) { m_Amplitude = amplitude; }
inline void SetFrequency( float frequency ) { m_Frequency = frequency; }
inline void SetDuration( float duration ) { m_Duration = duration; }
inline void SetRadius( float radius ) { m_Radius = radius; }
int DrawDebugTextOverlays(void);
// Input handlers
void InputStartShake( inputdata_t &inputdata );
void InputStopShake( inputdata_t &inputdata );
void InputAmplitude( inputdata_t &inputdata );
void InputFrequency( inputdata_t &inputdata );
// Causes the camera/physics shakes to happen:
void ApplyShake( ShakeCommand_t command );
void Think( void );
};
LINK_ENTITY_TO_CLASS( env_shake, CEnvShake );
BEGIN_DATADESC( CEnvShake )
DEFINE_KEYFIELD( m_Amplitude, FIELD_FLOAT, "amplitude" ),
DEFINE_KEYFIELD( m_Frequency, FIELD_FLOAT, "frequency" ),
DEFINE_KEYFIELD( m_Duration, FIELD_FLOAT, "duration" ),
DEFINE_KEYFIELD( m_Radius, FIELD_FLOAT, "radius" ),
DEFINE_FIELD( m_stopTime, FIELD_TIME ),
DEFINE_FIELD( m_nextShake, FIELD_TIME ),
DEFINE_FIELD( m_currentAmp, FIELD_FLOAT ),
DEFINE_FIELD( m_maxForce, FIELD_VECTOR ),
DEFINE_PHYSPTR( m_pShakeController ),
DEFINE_EMBEDDED( m_shakeCallback ),
DEFINE_INPUTFUNC( FIELD_VOID, "StartShake", InputStartShake ),
DEFINE_INPUTFUNC( FIELD_VOID, "StopShake", InputStopShake ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "Amplitude", InputAmplitude ),
DEFINE_INPUTFUNC( FIELD_FLOAT, "Frequency", InputFrequency ),
END_DATADESC()
#define SF_SHAKE_EVERYONE 0x0001 // Don't check radius
#define SF_SHAKE_INAIR 0x0004 // Shake players in air
#define SF_SHAKE_PHYSICS 0x0008 // Shake physically (not just camera)
#define SF_SHAKE_ROPES 0x0010 // Shake ropes too.
#define SF_SHAKE_NO_VIEW 0x0020 // DON'T shake the view (only ropes and/or physics objects)
#define SF_SHAKE_NO_RUMBLE 0x0040 // DON'T Rumble the XBox Controller
//-----------------------------------------------------------------------------
// Purpose: Destructor.
//-----------------------------------------------------------------------------
CEnvShake::~CEnvShake( void )
{
if ( m_pShakeController )
{
physenv->DestroyMotionController( m_pShakeController );
}
}
float CEnvShake::Radius(bool bPlayers)
{
// The radius for players is zero if SF_SHAKE_EVERYONE is set
if ( bPlayers && HasSpawnFlags(SF_SHAKE_EVERYONE))
return 0;
return m_Radius;
}
//-----------------------------------------------------------------------------
// Purpose: Sets default member values when spawning.
//-----------------------------------------------------------------------------
void CEnvShake::Spawn( void )
{
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
if ( GetSpawnFlags() & SF_SHAKE_EVERYONE )
{
m_Radius = 0;
}
if ( HasSpawnFlags( SF_SHAKE_NO_VIEW ) && !HasSpawnFlags( SF_SHAKE_PHYSICS ) && !HasSpawnFlags( SF_SHAKE_ROPES ) )
{
DevWarning( "env_shake %s with \"Don't shake view\" spawnflag set without \"Shake physics\" or \"Shake ropes\" spawnflags set.", GetDebugName() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Restore the motion controller
//-----------------------------------------------------------------------------
void CEnvShake::OnRestore( void )
{
BaseClass::OnRestore();
if ( m_pShakeController )
{
m_pShakeController->SetEventHandler( &m_shakeCallback );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvShake::ApplyShake( ShakeCommand_t command )
{
if ( !HasSpawnFlags( SF_SHAKE_NO_VIEW ) || !HasSpawnFlags( SF_SHAKE_NO_RUMBLE ) )
{
bool air = (GetSpawnFlags() & SF_SHAKE_INAIR) ? true : false;
UTIL_ScreenShake( GetAbsOrigin(), Amplitude(), Frequency(), Duration(), Radius(), command, air );
}
if ( GetSpawnFlags() & SF_SHAKE_ROPES )
{
CRopeKeyframe::ShakeRopes( GetAbsOrigin(), Radius(false), Frequency() );
}
if ( GetSpawnFlags() & SF_SHAKE_PHYSICS )
{
if ( !m_pShakeController )
{
m_pShakeController = physenv->CreateMotionController( &m_shakeCallback );
}
// do physics shake
switch( command )
{
case SHAKE_START:
case SHAKE_START_NORUMBLE:
case SHAKE_START_RUMBLEONLY:
{
m_stopTime = gpGlobals->curtime + Duration();
m_nextShake = 0;
m_pShakeController->ClearObjects();
SetNextThink( gpGlobals->curtime );
m_currentAmp = Amplitude();
CBaseEntity *list[1024];
float radius = Radius(false);
// probably checked "Shake Everywhere" do a big radius
if ( !radius )
{
radius = 512;
}
Vector extents = Vector(radius, radius, radius);
extents.z = MAX(extents.z, 100);
Vector mins = GetAbsOrigin() - extents;
Vector maxs = GetAbsOrigin() + extents;
int count = UTIL_EntitiesInBox( list, 1024, mins, maxs, 0 );
for ( int i = 0; i < count; i++ )
{
//
// Only shake physics entities that players can see. This is one frame out of date
// so it's possible that we could miss objects if a player changed PVS this frame.
//
if ( ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS ) )
{
IPhysicsObject *pPhys = list[i]->VPhysicsGetObject();
if ( pPhys && pPhys->IsMoveable() )
{
m_pShakeController->AttachObject( pPhys, false );
pPhys->Wake();
}
}
}
}
break;
case SHAKE_STOP:
m_pShakeController->ClearObjects();
break;
case SHAKE_AMPLITUDE:
m_currentAmp = Amplitude();
case SHAKE_FREQUENCY:
m_pShakeController->WakeObjects();
break;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler that starts the screen shake.
//-----------------------------------------------------------------------------
void CEnvShake::InputStartShake( inputdata_t &inputdata )
{
if ( HasSpawnFlags( SF_SHAKE_NO_RUMBLE ) )
{
ApplyShake( SHAKE_START_NORUMBLE );
}
else if ( HasSpawnFlags( SF_SHAKE_NO_VIEW ) )
{
ApplyShake( SHAKE_START_RUMBLEONLY );
}
else
{
ApplyShake( SHAKE_START );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler that stops the screen shake.
//-----------------------------------------------------------------------------
void CEnvShake::InputStopShake( inputdata_t &inputdata )
{
ApplyShake( SHAKE_STOP );
}
//-----------------------------------------------------------------------------
// Purpose: Handles changes to the shake amplitude from an external source.
//-----------------------------------------------------------------------------
void CEnvShake::InputAmplitude( inputdata_t &inputdata )
{
SetAmplitude( inputdata.value.Float() );
ApplyShake( SHAKE_AMPLITUDE );
}
//-----------------------------------------------------------------------------
// Purpose: Handles changes to the shake frequency from an external source.
//-----------------------------------------------------------------------------
void CEnvShake::InputFrequency( inputdata_t &inputdata )
{
SetFrequency( inputdata.value.Float() );
ApplyShake( SHAKE_FREQUENCY );
}
//-----------------------------------------------------------------------------
// Purpose: Calculates the physics shake values
//-----------------------------------------------------------------------------
void CEnvShake::Think( void )
{
int i;
if ( gpGlobals->curtime > m_nextShake )
{
// Higher frequency means we recalc the extents more often and perturb the display again
m_nextShake = gpGlobals->curtime + (1.0f / Frequency());
// Compute random shake extents (the shake will settle down from this)
for (i = 0; i < 2; i++ )
{
m_maxForce[i] = random->RandomFloat( -1, 1 );
}
// make the force it point mostly up
m_maxForce.z = 4;
VectorNormalize( m_maxForce );
m_maxForce *= m_currentAmp * 400; // amplitude is the acceleration of a 100kg object
}
float fraction = ( m_stopTime - gpGlobals->curtime ) / Duration();
if ( fraction < 0 )
{
m_pShakeController->ClearObjects();
return;
}
float freq = 0;
// Ramp up frequency over duration
if ( fraction )
{
freq = (Frequency() / fraction);
}
// square fraction to approach zero more quickly
fraction *= fraction;
// Sine wave that slowly settles to zero
fraction = fraction * sin( gpGlobals->curtime * freq );
// Add to view origin
for ( i = 0; i < 3; i++ )
{
// store the force in the controller callback
m_shakeCallback.m_force[i] = m_maxForce[i] * fraction;
}
// Drop amplitude a bit, less for higher frequency shakes
m_currentAmp -= m_currentAmp * ( gpGlobals->frametime / (Duration() * Frequency()) );
SetNextThink( gpGlobals->curtime );
}
//------------------------------------------------------------------------------
// Purpose: Console command to cause a screen shake.
//------------------------------------------------------------------------------
void CC_Shake( void )
{
CBasePlayer *pPlayer = UTIL_GetCommandClient();
if (pPlayer)
{
UTIL_ScreenShake( pPlayer->WorldSpaceCenter(), 25.0, 150.0, 1.0, 750, SHAKE_START );
}
}
//-----------------------------------------------------------------------------
// Purpose: Draw any debug text overlays
// Returns current text offset from the top
//-----------------------------------------------------------------------------
int CEnvShake::DrawDebugTextOverlays( void )
{
int text_offset = BaseClass::DrawDebugTextOverlays();
if (m_debugOverlays & OVERLAY_TEXT_BIT)
{
char tempstr[512];
// print amplitude
Q_snprintf(tempstr,sizeof(tempstr)," magnitude: %f", m_Amplitude);
EntityText(text_offset,tempstr,0);
text_offset++;
// print frequency
Q_snprintf(tempstr,sizeof(tempstr)," frequency: %f", m_Frequency);
EntityText(text_offset,tempstr,0);
text_offset++;
// print duration
Q_snprintf(tempstr,sizeof(tempstr)," duration: %f", m_Duration);
EntityText(text_offset,tempstr,0);
text_offset++;
// print radius
Q_snprintf(tempstr,sizeof(tempstr)," radius: %f", m_Radius);
EntityText(text_offset,tempstr,0);
text_offset++;
}
return text_offset;
}
static ConCommand shake("shake", CC_Shake, "Shake the screen.", FCVAR_CHEAT );

195
game/server/EnvSpark.cpp Normal file
View File

@@ -0,0 +1,195 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A point entity that periodically emits sparks and "bzzt" sounds.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "IEffects.h"
#include "engine/IEngineSound.h"
#include "envspark.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Purpose: Emits sparks from the given location and plays a random spark sound.
// Input : pev -
// location -
//-----------------------------------------------------------------------------
void DoSpark( CBaseEntity *ent, const Vector &location, int nMagnitude, int nTrailLength, bool bPlaySound, const Vector &vecDir )
{
g_pEffects->Sparks( location, nMagnitude, nTrailLength, &vecDir );
if ( bPlaySound )
{
ent->EmitSound( "DoSpark" );
}
}
const int SF_SPARK_START_ON = 64;
const int SF_SPARK_GLOW = 128;
const int SF_SPARK_SILENT = 256;
const int SF_SPARK_DIRECTIONAL = 512;
BEGIN_DATADESC( CEnvSpark )
DEFINE_KEYFIELD( m_flDelay, FIELD_FLOAT, "MaxDelay" ),
DEFINE_FIELD( m_nGlowSpriteIndex, FIELD_INTEGER ),
DEFINE_KEYFIELD( m_nMagnitude, FIELD_INTEGER, "Magnitude" ),
DEFINE_KEYFIELD( m_nTrailLength, FIELD_INTEGER, "TrailLength" ),
// Function Pointers
DEFINE_FUNCTION( SparkThink ),
DEFINE_INPUTFUNC( FIELD_VOID, "StartSpark", InputStartSpark ),
DEFINE_INPUTFUNC( FIELD_VOID, "StopSpark", InputStopSpark ),
DEFINE_INPUTFUNC( FIELD_VOID, "ToggleSpark", InputToggleSpark ),
DEFINE_INPUTFUNC( FIELD_VOID, "SparkOnce", InputSparkOnce ),
DEFINE_OUTPUT( m_OnSpark, "OnSpark" ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_spark, CEnvSpark );
//-----------------------------------------------------------------------------
// Purpose: Constructor! Exciting, isn't it?
//-----------------------------------------------------------------------------
CEnvSpark::CEnvSpark( void )
{
m_nMagnitude = 1;
m_nTrailLength = 1;
}
//-----------------------------------------------------------------------------
// Purpose: Called when spawning, after keyvalues have been handled.
//-----------------------------------------------------------------------------
void CEnvSpark::Spawn(void)
{
SetThink( NULL );
SetUse( NULL );
if ( FBitSet(m_spawnflags, SF_SPARK_START_ON ) )
{
SetThink( &CEnvSpark::SparkThink ); // start sparking
}
SetNextThink( gpGlobals->curtime + 0.1 + random->RandomFloat( 0, 1.5 ) );
// Negative delays are not allowed
if ( m_flDelay < 0 )
{
m_flDelay = 0;
}
#ifdef HL1_DLL
// Don't allow 0 delays in HL1 Port. Enforce a default
if( m_flDelay == 0 )
{
m_flDelay = 1.0f;
}
#endif//HL1_DLL
Precache( );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvSpark::Precache(void)
{
m_nGlowSpriteIndex = PrecacheModel( "sprites/glow01.vmt" );
PrecacheScriptSound( "DoSpark" );
}
extern ConVar phys_pushscale;
//-----------------------------------------------------------------------------
// Purpose: Emits sparks at random intervals.
//-----------------------------------------------------------------------------
void CEnvSpark::SparkThink(void)
{
SetNextThink( gpGlobals->curtime + 0.1 + random->RandomFloat(0, m_flDelay) );
Vector vecDir = vec3_origin;
if ( FBitSet( m_spawnflags, SF_SPARK_DIRECTIONAL ) )
{
AngleVectors( GetAbsAngles(), &vecDir );
}
DoSpark( this, WorldSpaceCenter(), m_nMagnitude, m_nTrailLength, !( m_spawnflags & SF_SPARK_SILENT ), vecDir );
m_OnSpark.FireOutput( this, this );
if (FBitSet(m_spawnflags, SF_SPARK_GLOW))
{
CPVSFilter filter( GetAbsOrigin() );
te->GlowSprite( filter, 0.0, &GetAbsOrigin(), m_nGlowSpriteIndex, 0.2, 1.5, 25 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for starting the sparks.
//-----------------------------------------------------------------------------
void CEnvSpark::InputStartSpark( inputdata_t &inputdata )
{
StartSpark();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvSpark::StartSpark( void )
{
SetThink( &CEnvSpark::SparkThink );
SetNextThink( gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Purpose: Shoot one spark.
//-----------------------------------------------------------------------------
void CEnvSpark::InputSparkOnce( inputdata_t &inputdata )
{
SparkThink();
SetNextThink( TICK_NEVER_THINK );
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for starting the sparks.
//-----------------------------------------------------------------------------
void CEnvSpark::InputStopSpark( inputdata_t &inputdata )
{
StopSpark();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CEnvSpark::StopSpark( void )
{
SetThink( NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for toggling the on/off state of the sparks.
//-----------------------------------------------------------------------------
void CEnvSpark::InputToggleSpark( inputdata_t &inputdata )
{
if ( GetNextThink() == TICK_NEVER_THINK )
{
InputStartSpark( inputdata );
}
else
{
InputStopSpark( inputdata );
}
}

257
game/server/EventLog.cpp Normal file
View File

@@ -0,0 +1,257 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "EventLog.h"
#include "team.h"
#include "KeyValues.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CEventLog::CEventLog()
{
}
CEventLog::~CEventLog()
{
}
void CEventLog::FireGameEvent( IGameEvent *event )
{
PrintEvent ( event );
}
bool CEventLog::PrintEvent( IGameEvent *event )
{
const char * name = event->GetName();
if ( Q_strncmp(name, "server_", strlen("server_")) == 0 )
{
return true; // we don't care about server events (engine does)
}
else if ( Q_strncmp(name, "player_", strlen("player_")) == 0 )
{
return PrintPlayerEvent( event );
}
else if ( Q_strncmp(name, "team_", strlen("team_")) == 0 )
{
return PrintTeamEvent( event );
}
else if ( Q_strncmp(name, "game_", strlen("game_")) == 0 )
{
return PrintGameEvent( event );
}
else
{
return PrintOtherEvent( event ); // bomb_, round_, et al
}
}
bool CEventLog::PrintGameEvent( IGameEvent *event )
{
// const char * name = event->GetName() + Q_strlen("game_"); // remove prefix
return false;
}
bool CEventLog::PrintPlayerEvent( IGameEvent *event )
{
const char * eventName = event->GetName();
const int userid = event->GetInt( "userid" );
if ( !Q_strncmp( eventName, "player_connect", Q_strlen("player_connect") ) ) // player connect is before the CBasePlayer pointer is setup
{
const char *name = event->GetString( "name" );
const char *address = event->GetString( "address" );
const char *networkid = event->GetString("networkid" );
UTIL_LogPrintf( "\"%s<%i><%s><>\" connected, address \"%s\"\n", name, userid, networkid, address);
return true;
}
else if ( !Q_strncmp( eventName, "player_disconnect", Q_strlen("player_disconnect") ) )
{
const char *reason = event->GetString("reason" );
const char *name = event->GetString("name" );
const char *networkid = event->GetString("networkid" );
CTeam *team = NULL;
CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid );
if ( pPlayer )
{
team = pPlayer->GetTeam();
}
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" disconnected (reason \"%s\")\n", name, userid, networkid, team ? team->GetName() : "", reason );
return true;
}
CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid );
if ( !pPlayer)
{
DevMsg( "CEventLog::PrintPlayerEvent: Failed to find player (userid: %i, event: %s)\n", userid, eventName );
return false;
}
if ( !Q_strncmp( eventName, "player_team", Q_strlen("player_team") ) )
{
const bool bDisconnecting = event->GetBool( "disconnect" );
if ( !bDisconnecting )
{
const int newTeam = event->GetInt( "team" );
const int oldTeam = event->GetInt( "oldteam" );
CTeam *team = GetGlobalTeam( newTeam );
CTeam *oldteam = GetGlobalTeam( oldTeam );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" joined team \"%s\"\n",
pPlayer->GetPlayerName(),
pPlayer->GetUserID(),
pPlayer->GetNetworkIDString(),
oldteam->GetName(),
team->GetName() );
}
return true;
}
else if ( !Q_strncmp( eventName, "player_death", Q_strlen("player_death") ) )
{
const int attackerid = event->GetInt("attacker" );
#ifdef HL2MP
const char *weapon = event->GetString( "weapon" );
#endif
CBasePlayer *pAttacker = UTIL_PlayerByUserId( attackerid );
CTeam *team = pPlayer->GetTeam();
CTeam *attackerTeam = NULL;
if ( pAttacker )
{
attackerTeam = pAttacker->GetTeam();
}
if ( pPlayer == pAttacker && pPlayer )
{
#ifdef HL2MP
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
weapon
);
#else
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
pAttacker->GetClassname()
);
#endif
}
else if ( pAttacker )
{
CTeam *attackerTeam = pAttacker->GetTeam();
#ifdef HL2MP
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n",
pAttacker->GetPlayerName(),
attackerid,
pAttacker->GetNetworkIDString(),
attackerTeam ? attackerTeam->GetName() : "",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
weapon
);
#else
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\"\n",
pAttacker->GetPlayerName(),
attackerid,
pAttacker->GetNetworkIDString(),
attackerTeam ? attackerTeam->GetName() : "",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : ""
);
#endif
}
else
{
// killed by the world
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"world\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : ""
);
}
return true;
}
else if ( !Q_strncmp( eventName, "player_activate", Q_strlen("player_activate") ) )
{
UTIL_LogPrintf( "\"%s<%i><%s><>\" entered the game\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString()
);
return true;
}
else if ( !Q_strncmp( eventName, "player_changename", Q_strlen("player_changename") ) )
{
const char *newName = event->GetString( "newname" );
const char *oldName = event->GetString( "oldname" );
CTeam *team = pPlayer->GetTeam();
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed name to \"%s\"\n",
oldName,
userid,
pPlayer->GetNetworkIDString(),
team ? team->GetName() : "",
newName
);
return true;
}
// ignored events
//player_hurt
return false;
}
bool CEventLog::PrintTeamEvent( IGameEvent *event )
{
// const char * name = event->GetName() + Q_strlen("team_"); // remove prefix
return false;
}
bool CEventLog::PrintOtherEvent( IGameEvent *event )
{
return false;
}
bool CEventLog::Init()
{
ListenForGameEvent( "player_changename" );
ListenForGameEvent( "player_activate" );
ListenForGameEvent( "player_death" );
ListenForGameEvent( "player_team" );
ListenForGameEvent( "player_disconnect" );
ListenForGameEvent( "player_connect" );
return true;
}
void CEventLog::Shutdown()
{
StopListeningForAllEvents();
}

46
game/server/EventLog.h Normal file
View File

@@ -0,0 +1,46 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#if !defined EVENTLOG_H
#define EVENTLOG_H
#ifdef _WIN32
#pragma once
#endif
#include "GameEventListener.h"
#include <igamesystem.h>
class CEventLog : public CGameEventListener, public CBaseGameSystem
{
public:
CEventLog();
virtual ~CEventLog();
public: // IGameEventListener Interface
virtual void FireGameEvent( IGameEvent * event );
public: // CBaseGameSystem overrides
virtual bool Init();
virtual void Shutdown();
protected:
virtual bool PrintEvent( IGameEvent * event );
virtual bool PrintGameEvent( IGameEvent * event );
virtual bool PrintPlayerEvent( IGameEvent * event );
virtual bool PrintTeamEvent( IGameEvent * event );
virtual bool PrintOtherEvent( IGameEvent * event );
};
extern IGameSystem* GameLogSystem();
#endif // EVENTLOG_H

1099
game/server/GameStats.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,183 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "cbase.h"
#include "gamestats.h"
void BasicGameStatsRecord_t::Clear()
{
m_nCount = 0;
m_nSeconds = 0;
m_nCommentary = 0;
m_nHDR = 0;
m_nCaptions = 0;
m_bSteam = true;
m_bCyberCafe = false;
Q_memset( m_nSkill, 0, sizeof( m_nSkill ) );
m_nDeaths = 0;
}
void BasicGameStatsRecord_t::SaveToBuffer( CUtlBuffer &buf )
{
buf.PutInt( m_nCount );
buf.PutInt( m_nSeconds );
buf.PutInt( m_nCommentary );
buf.PutInt( m_nHDR );
buf.PutInt( m_nCaptions );
for ( int i = 0; i < 3; ++i )
{
buf.PutInt( m_nSkill[ i ] );
}
buf.PutChar( m_bSteam ? 1 : 0 );
buf.PutChar( m_bCyberCafe ? 1 : 0 );
buf.PutInt( m_nDeaths );
}
bool BasicGameStatsRecord_t::ParseFromBuffer( CUtlBuffer &buf, int iBufferStatsVersion )
{
bool bret = true;
m_nCount = buf.GetInt();
if ( m_nCount > 100000 || m_nCount < 0 )
{
bret = false;
}
m_nSeconds = buf.GetInt();
// Note, don't put the buf.GetInt() in the macro since it'll get evaluated twice!!!
m_nSeconds = MAX( m_nSeconds, 0 );
m_nCommentary = buf.GetInt();
if ( m_nCommentary < 0 || m_nCommentary > 100000 )
{
bret = false;
}
m_nHDR = buf.GetInt();
if ( m_nHDR < 0 || m_nHDR > 100000 )
{
bret = false;
}
m_nCaptions = buf.GetInt();
if ( m_nCaptions < 0 || m_nCaptions > 100000 )
{
bret = false;
}
for ( int i = 0; i < 3; ++i )
{
m_nSkill[ i ] = buf.GetInt();
if ( m_nSkill[ i ] < 0 || m_nSkill[ i ] > 100000 )
{
bret = false;
}
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD )
{
m_bSteam = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD2 )
{
m_bCyberCafe = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD5 )
{
m_nDeaths = buf.GetInt();
}
return bret;
}
void BasicGameStats_t::Clear()
{
m_nSecondsToCompleteGame = 0;
m_Summary.Clear();
m_MapTotals.Purge();
}
void BasicGameStats_t::SaveToBuffer( CUtlBuffer& buf )
{
buf.PutInt( m_nSecondsToCompleteGame );
m_Summary.SaveToBuffer( buf );
int c = m_MapTotals.Count();
buf.PutInt( c );
for ( int i = m_MapTotals.First(); i != m_MapTotals.InvalidIndex(); i = m_MapTotals.Next( i ) )
{
char const *name = m_MapTotals.GetElementName( i );
BasicGameStatsRecord_t &rec = m_MapTotals[ i ];
buf.PutString( name );
rec.SaveToBuffer( buf );
}
buf.PutChar( (char)m_nHL2ChaptureUnlocked );
buf.PutChar( m_bSteam ? 1 : 0 );
buf.PutChar( m_bCyberCafe ? 1 : 0 );
buf.PutShort( (short)m_nDXLevel );
}
BasicGameStatsRecord_t *BasicGameStats_t::FindOrAddRecordForMap( char const *mapname )
{
int idx = m_MapTotals.Find( mapname );
if ( idx == m_MapTotals.InvalidIndex() )
{
idx = m_MapTotals.Insert( mapname );
}
return &m_MapTotals[ idx ];
}
bool BasicGameStats_t::ParseFromBuffer( CUtlBuffer& buf, int iBufferStatsVersion )
{
bool bret = true;
m_nSecondsToCompleteGame = buf.GetInt();
if ( m_nSecondsToCompleteGame < 0 || m_nSecondsToCompleteGame > 10000000 )
{
bret = false;
}
m_Summary.ParseFromBuffer( buf, iBufferStatsVersion );
int c = buf.GetInt();
if ( c > 1024 || c < 0 )
{
bret = false;
}
for ( int i = 0; i < c; ++i )
{
char mapname[ 256 ];
buf.GetString( mapname, sizeof( mapname ) );
BasicGameStatsRecord_t *rec = FindOrAddRecordForMap( mapname );
bool valid= rec->ParseFromBuffer( buf, iBufferStatsVersion );
if ( !valid )
{
bret = false;
}
}
if ( iBufferStatsVersion >= GAMESTATS_FILE_VERSION_OLD2 )
{
m_nHL2ChaptureUnlocked = (int)buf.GetChar();
m_bSteam = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD2 )
{
m_bCyberCafe = buf.GetChar() ? true : false;
}
if ( iBufferStatsVersion > GAMESTATS_FILE_VERSION_OLD3 )
{
m_nDXLevel = (int)buf.GetShort();
}
return bret;
}

View File

@@ -0,0 +1,289 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Material modify control entity.
//
//=============================================================================//
#include "cbase.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//------------------------------------------------------------------------------
// FIXME: This really should inherit from something more lightweight.
//------------------------------------------------------------------------------
#define MATERIAL_MODIFY_STRING_SIZE 255
#define MATERIAL_MODIFY_ANIMATION_UNSET -1
// Must match C_MaterialModifyControl.cpp
enum MaterialModifyMode_t
{
MATERIAL_MODIFY_MODE_NONE = 0,
MATERIAL_MODIFY_MODE_SETVAR = 1,
MATERIAL_MODIFY_MODE_ANIM_SEQUENCE = 2,
MATERIAL_MODIFY_MODE_FLOAT_LERP = 3,
};
ConVar debug_materialmodifycontrol( "debug_materialmodifycontrol", "0" );
class CMaterialModifyControl : public CBaseEntity
{
public:
DECLARE_CLASS( CMaterialModifyControl, CBaseEntity );
CMaterialModifyControl();
void Spawn( void );
bool KeyValue( const char *szKeyName, const char *szValue );
int UpdateTransmitState();
int ShouldTransmit( const CCheckTransmitInfo *pInfo );
void SetMaterialVar( inputdata_t &inputdata );
void SetMaterialVarToCurrentTime( inputdata_t &inputdata );
void InputStartAnimSequence( inputdata_t &inputdata );
void InputStartFloatLerp( inputdata_t &inputdata );
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
private:
CNetworkString( m_szMaterialName, MATERIAL_MODIFY_STRING_SIZE );
CNetworkString( m_szMaterialVar, MATERIAL_MODIFY_STRING_SIZE );
CNetworkString( m_szMaterialVarValue, MATERIAL_MODIFY_STRING_SIZE );
CNetworkVar( int, m_iFrameStart );
CNetworkVar( int, m_iFrameEnd );
CNetworkVar( bool, m_bWrap );
CNetworkVar( float, m_flFramerate );
CNetworkVar( bool, m_bNewAnimCommandsSemaphore );
CNetworkVar( float, m_flFloatLerpStartValue );
CNetworkVar( float, m_flFloatLerpEndValue );
CNetworkVar( float, m_flFloatLerpTransitionTime );
CNetworkVar( int, m_nModifyMode );
};
LINK_ENTITY_TO_CLASS(material_modify_control, CMaterialModifyControl);
BEGIN_DATADESC( CMaterialModifyControl )
// Variables.
DEFINE_AUTO_ARRAY( m_szMaterialName, FIELD_CHARACTER ),
DEFINE_AUTO_ARRAY( m_szMaterialVar, FIELD_CHARACTER ),
DEFINE_AUTO_ARRAY( m_szMaterialVarValue, FIELD_CHARACTER ),
DEFINE_FIELD( m_iFrameStart, FIELD_INTEGER ),
DEFINE_FIELD( m_iFrameEnd, FIELD_INTEGER ),
DEFINE_FIELD( m_bWrap, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flFramerate, FIELD_FLOAT ),
DEFINE_FIELD( m_bNewAnimCommandsSemaphore, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flFloatLerpStartValue, FIELD_FLOAT ),
DEFINE_FIELD( m_flFloatLerpEndValue, FIELD_FLOAT ),
DEFINE_FIELD( m_flFloatLerpTransitionTime, FIELD_FLOAT ),
DEFINE_FIELD( m_nModifyMode, FIELD_INTEGER ),
// Inputs.
DEFINE_INPUTFUNC( FIELD_STRING, "SetMaterialVar", SetMaterialVar ),
DEFINE_INPUTFUNC( FIELD_VOID, "SetMaterialVarToCurrentTime", SetMaterialVarToCurrentTime ),
DEFINE_INPUTFUNC( FIELD_STRING, "StartAnimSequence", InputStartAnimSequence ),
DEFINE_INPUTFUNC( FIELD_STRING, "StartFloatLerp", InputStartFloatLerp ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST(CMaterialModifyControl, DT_MaterialModifyControl)
SendPropString( SENDINFO( m_szMaterialName ) ),
SendPropString( SENDINFO( m_szMaterialVar ) ),
SendPropString( SENDINFO( m_szMaterialVarValue ) ),
SendPropInt( SENDINFO(m_iFrameStart), 8 ),
SendPropInt( SENDINFO(m_iFrameEnd), 8 ),
SendPropInt( SENDINFO(m_bWrap), 1, SPROP_UNSIGNED ),
SendPropFloat( SENDINFO(m_flFramerate), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO(m_bNewAnimCommandsSemaphore), 1, SPROP_UNSIGNED ),
SendPropFloat( SENDINFO(m_flFloatLerpStartValue), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO(m_flFloatLerpEndValue), 0, SPROP_NOSCALE ),
SendPropFloat( SENDINFO(m_flFloatLerpTransitionTime), 0, SPROP_NOSCALE ),
SendPropInt( SENDINFO(m_nModifyMode), 2, SPROP_UNSIGNED ),
END_SEND_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CMaterialModifyControl::CMaterialModifyControl()
{
m_iFrameStart = MATERIAL_MODIFY_ANIMATION_UNSET;
m_iFrameEnd = MATERIAL_MODIFY_ANIMATION_UNSET;
m_nModifyMode = MATERIAL_MODIFY_MODE_NONE;
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
void CMaterialModifyControl::Spawn( void )
{
Precache();
SetSolid( SOLID_NONE );
}
//------------------------------------------------------------------------------
// Purpose :
//------------------------------------------------------------------------------
bool CMaterialModifyControl::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "materialName" ) )
{
Q_strncpy( m_szMaterialName.GetForModify(), szValue, MATERIAL_MODIFY_STRING_SIZE );
return true;
}
if ( FStrEq( szKeyName, "materialVar" ) )
{
Q_strncpy( m_szMaterialVar.GetForModify(), szValue, MATERIAL_MODIFY_STRING_SIZE );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
//------------------------------------------------------------------------------
// Purpose : Send even though we don't have a model.
//------------------------------------------------------------------------------
int CMaterialModifyControl::UpdateTransmitState()
{
// ALWAYS transmit to all clients.
return SetTransmitState( FL_EDICT_FULLCHECK );
}
//-----------------------------------------------------------------------------
// Send if the parent is being sent:
//-----------------------------------------------------------------------------
int CMaterialModifyControl::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
CBaseEntity *pEnt = GetMoveParent();
if ( pEnt )
{
return pEnt->ShouldTransmit( pInfo );
}
return FL_EDICT_DONTSEND;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::SetMaterialVar( inputdata_t &inputdata )
{
//if( debug_materialmodifycontrol.GetBool() && Q_stristr( GetDebugName(), "alyx" ) )
//{
//DevMsg( 1, "CMaterialModifyControl::SetMaterialVar %s %s %s=\"%s\"\n",
//GetDebugName(), m_szMaterialName.Get(), m_szMaterialVar.Get(), inputdata.value.String() );
//}
Q_strncpy( m_szMaterialVarValue.GetForModify(), inputdata.value.String(), MATERIAL_MODIFY_STRING_SIZE );
m_nModifyMode = MATERIAL_MODIFY_MODE_SETVAR;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::SetMaterialVarToCurrentTime( inputdata_t &inputdata )
{
char temp[32];
Q_snprintf( temp, 32, "%f", gpGlobals->curtime );
Q_strncpy( m_szMaterialVarValue.GetForModify(), temp, MATERIAL_MODIFY_STRING_SIZE );
m_nModifyMode = MATERIAL_MODIFY_MODE_SETVAR;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::InputStartAnimSequence( inputdata_t &inputdata )
{
char parseString[255];
Q_strncpy(parseString, inputdata.value.String(), sizeof(parseString));
// Get the start & end frames
char *pszParam = strtok(parseString," ");
if ( pszParam && pszParam[0] )
{
int iFrameStart = atoi(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
int iFrameEnd = atoi(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
float flFramerate = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
bool bWrap = atoi(pszParam) != 0;
// Got all the parameters. Save 'em and return;
m_iFrameStart = iFrameStart;
m_iFrameEnd = iFrameEnd;
m_flFramerate = flFramerate;
m_bWrap = bWrap;
m_nModifyMode = MATERIAL_MODIFY_MODE_ANIM_SEQUENCE;
m_bNewAnimCommandsSemaphore = !m_bNewAnimCommandsSemaphore;
return;
}
}
}
}
Warning("%s (%s) received StartAnimSequence input without correct parameters. Syntax: <Frame Start> <Frame End> <Frame Rate> <Loop>\nSetting <Frame End> to -1 uses the last frame of the texture. <Loop> should be 1 or 0.\n", GetClassname(), GetDebugName() );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMaterialModifyControl::InputStartFloatLerp( inputdata_t &inputdata )
{
char parseString[255];
Q_strncpy(parseString, inputdata.value.String(), sizeof(parseString));
// if( debug_materialmodifycontrol.GetBool() )//&& Q_stristr( GetDebugName(), "alyx" ) )
// {
// DevMsg( 1, "CMaterialModifyControl::InputStartFloatLerp %s %s %s \"%s\"\n",
// GetDebugName(), m_szMaterialName.Get(), m_szMaterialVar.Get(), inputdata.value.String() );
// }
// Get the start & end values
char *pszParam = strtok(parseString," ");
if ( pszParam && pszParam[0] )
{
float flStartValue = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
float flEndValue = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
float flTransitionTime = atof(pszParam);
pszParam = strtok(NULL," ");
if ( pszParam && pszParam[0] )
{
bool bWrap = atoi(pszParam) != 0;
// We don't implement wrap currently.
bWrap = bWrap;
// Got all the parameters. Save 'em and return;
m_flFloatLerpStartValue = flStartValue;
m_flFloatLerpEndValue = flEndValue;
m_flFloatLerpTransitionTime = flTransitionTime;
m_nModifyMode = MATERIAL_MODIFY_MODE_FLOAT_LERP;
m_bNewAnimCommandsSemaphore = !m_bNewAnimCommandsSemaphore;
return;
}
}
}
}
Warning("%s (%s) received StartFloatLerp input without correct parameters. Syntax: <Start Value> <End Value> <Transition Time> <Loop>\n<Loop> should be 1 or 0.\n", GetClassname(), GetDebugName() );
}

View File

@@ -0,0 +1,529 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Used to fire events based on the orientation of a given entity.
//
// Looks at its target's anglular velocity every frame and fires outputs
// as the angular velocity passes a given threshold value.
//
//=============================================================================//
#include "cbase.h"
#include "entityinput.h"
#include "entityoutput.h"
#include "eventqueue.h"
#include "mathlib/mathlib.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
enum
{
AVELOCITY_SENSOR_NO_LAST_RESULT = -2
};
ConVar g_debug_angularsensor( "g_debug_angularsensor", "0", FCVAR_CHEAT );
class CPointAngularVelocitySensor : public CPointEntity
{
DECLARE_CLASS( CPointAngularVelocitySensor, CPointEntity );
public:
CPointAngularVelocitySensor();
void Activate(void);
void Spawn(void);
void Think(void);
private:
float SampleAngularVelocity(CBaseEntity *pEntity);
int CompareToThreshold(CBaseEntity *pEntity, float flThreshold, bool bFireVelocityOutput);
void FireCompareOutput(int nCompareResult, CBaseEntity *pActivator);
void DrawDebugLines( void );
// Input handlers
void InputTest( inputdata_t &inputdata );
void InputTestWithInterval( inputdata_t &inputdata );
EHANDLE m_hTargetEntity; // Entity whose angles are being monitored.
float m_flThreshold; // The threshold angular velocity that we are looking for.
int m_nLastCompareResult; // The comparison result from our last measurement, expressed as -1, 0, or 1
int m_nLastFireResult; // The last result for which we fire the output.
float m_flFireTime;
float m_flFireInterval;
float m_flLastAngVelocity;
QAngle m_lastOrientation;
Vector m_vecAxis;
bool m_bUseHelper;
// Outputs
COutputFloat m_AngularVelocity;
// Compare the target's angular velocity to the threshold velocity and fire the appropriate output.
// These outputs are filtered by m_flFireInterval to ignore excessive oscillations.
COutputEvent m_OnLessThan;
COutputEvent m_OnLessThanOrEqualTo;
COutputEvent m_OnGreaterThan;
COutputEvent m_OnGreaterThanOrEqualTo;
COutputEvent m_OnEqualTo;
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS(point_angularvelocitysensor, CPointAngularVelocitySensor);
BEGIN_DATADESC( CPointAngularVelocitySensor )
// Fields
DEFINE_FIELD( m_hTargetEntity, FIELD_EHANDLE ),
DEFINE_KEYFIELD(m_flThreshold, FIELD_FLOAT, "threshold"),
DEFINE_FIELD(m_nLastCompareResult, FIELD_INTEGER),
DEFINE_FIELD( m_nLastFireResult, FIELD_INTEGER ),
DEFINE_FIELD( m_flFireTime, FIELD_TIME ),
DEFINE_KEYFIELD( m_flFireInterval, FIELD_FLOAT, "fireinterval" ),
DEFINE_FIELD( m_flLastAngVelocity, FIELD_FLOAT ),
DEFINE_FIELD( m_lastOrientation, FIELD_VECTOR ),
// Inputs
DEFINE_INPUTFUNC(FIELD_VOID, "Test", InputTest),
DEFINE_INPUTFUNC(FIELD_VOID, "TestWithInterval", InputTestWithInterval),
// Outputs
DEFINE_OUTPUT(m_OnLessThan, "OnLessThan"),
DEFINE_OUTPUT(m_OnLessThanOrEqualTo, "OnLessThanOrEqualTo"),
DEFINE_OUTPUT(m_OnGreaterThan, "OnGreaterThan"),
DEFINE_OUTPUT(m_OnGreaterThanOrEqualTo, "OnGreaterThanOrEqualTo"),
DEFINE_OUTPUT(m_OnEqualTo, "OnEqualTo"),
DEFINE_OUTPUT(m_AngularVelocity, "AngularVelocity"),
DEFINE_KEYFIELD( m_vecAxis, FIELD_VECTOR, "axis" ),
DEFINE_KEYFIELD( m_bUseHelper, FIELD_BOOLEAN, "usehelper" ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: constructor provides default values
//-----------------------------------------------------------------------------
CPointAngularVelocitySensor::CPointAngularVelocitySensor()
{
m_flFireInterval = 0.2f;
}
//-----------------------------------------------------------------------------
// Purpose: Called when spawning after parsing keyvalues.
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::Spawn(void)
{
m_flThreshold = fabs(m_flThreshold);
m_nLastFireResult = AVELOCITY_SENSOR_NO_LAST_RESULT;
m_nLastCompareResult = AVELOCITY_SENSOR_NO_LAST_RESULT;
// m_flFireInterval = 0.2;
m_lastOrientation = vec3_angle;
}
//-----------------------------------------------------------------------------
// Purpose: Called after all entities in the map have spawned.
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::Activate(void)
{
BaseClass::Activate();
m_hTargetEntity = gEntList.FindEntityByName( NULL, m_target );
if (m_hTargetEntity)
{
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose: Draws magic lines...
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::DrawDebugLines( void )
{
if ( m_hTargetEntity )
{
Vector vForward, vRight, vUp;
AngleVectors( m_hTargetEntity->GetAbsAngles(), &vForward, &vRight, &vUp );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vForward * 64, 255, 0, 0, false, 0 );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vRight * 64, 0, 255, 0, false, 0 );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vUp * 64, 0, 0, 255, false, 0 );
}
if ( m_bUseHelper == true )
{
QAngle Angles;
Vector vAxisForward, vAxisRight, vAxisUp;
Vector vLine = m_vecAxis - GetAbsOrigin();
VectorNormalize( vLine );
VectorAngles( vLine, Angles );
AngleVectors( Angles, &vAxisForward, &vAxisRight, &vAxisUp );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vAxisForward * 64, 255, 0, 0, false, 0 );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vAxisRight * 64, 0, 255, 0, false, 0 );
NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vAxisUp * 64, 0, 0, 255, false, 0 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns the magnitude of the entity's angular velocity.
//-----------------------------------------------------------------------------
float CPointAngularVelocitySensor::SampleAngularVelocity(CBaseEntity *pEntity)
{
if (pEntity->GetMoveType() == MOVETYPE_VPHYSICS)
{
IPhysicsObject *pPhys = pEntity->VPhysicsGetObject();
if (pPhys != NULL)
{
Vector vecVelocity;
AngularImpulse vecAngVelocity;
pPhys->GetVelocity(&vecVelocity, &vecAngVelocity);
QAngle angles;
pPhys->GetPosition( NULL, &angles );
float dt = gpGlobals->curtime - GetLastThink();
if ( dt == 0 )
dt = 0.1;
// HACKHACK: We don't expect a real 'delta' orientation here, just enough of an error estimate to tell if this thing
// is trying to move, but failing.
QAngle delta = angles - m_lastOrientation;
if ( ( delta.Length() / dt ) < ( vecAngVelocity.Length() * 0.01 ) )
{
return 0.0f;
}
m_lastOrientation = angles;
if ( m_bUseHelper == false )
{
return vecAngVelocity.Length();
}
else
{
Vector vLine = m_vecAxis - GetAbsOrigin();
VectorNormalize( vLine );
Vector vecWorldAngVelocity;
pPhys->LocalToWorldVector( &vecWorldAngVelocity, vecAngVelocity );
float flDot = DotProduct( vecWorldAngVelocity, vLine );
return flDot;
}
}
}
else
{
QAngle vecAngVel = pEntity->GetLocalAngularVelocity();
float flMax = MAX(fabs(vecAngVel[PITCH]), fabs(vecAngVel[YAW]));
return MAX(flMax, fabs(vecAngVel[ROLL]));
}
return 0;
}
//-----------------------------------------------------------------------------
// Purpose: Compares the given entity's angular velocity to the threshold velocity.
// Input : pEntity - Entity whose angular velocity is being measured.
// flThreshold -
// Output : Returns -1 if less than, 0 if equal to, or 1 if greater than the threshold.
//-----------------------------------------------------------------------------
int CPointAngularVelocitySensor::CompareToThreshold(CBaseEntity *pEntity, float flThreshold, bool bFireVelocityOutput)
{
if (pEntity == NULL)
{
return 0;
}
float flAngVelocity = SampleAngularVelocity(pEntity);
if ( g_debug_angularsensor.GetBool() )
{
DrawDebugLines();
}
if (bFireVelocityOutput && (flAngVelocity != m_flLastAngVelocity))
{
m_AngularVelocity.Set(flAngVelocity, pEntity, this);
m_flLastAngVelocity = flAngVelocity;
}
if (flAngVelocity > flThreshold)
{
return 1;
}
if (flAngVelocity == flThreshold)
{
return 0;
}
return -1;
}
//-----------------------------------------------------------------------------
// Called every frame to sense the angular velocity of the target entity.
// Output is filtered by m_flFireInterval to ignore excessive oscillations.
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::Think(void)
{
if (m_hTargetEntity != NULL)
{
//
// Check to see if the measure entity's angular velocity has been within
// tolerance of the threshold for the given period of time.
//
int nCompare = CompareToThreshold(m_hTargetEntity, m_flThreshold, true);
if (nCompare != m_nLastCompareResult)
{
// If we've oscillated back to where we last fired the output, don't
// fire the same output again.
if (nCompare == m_nLastFireResult)
{
m_flFireTime = 0;
}
else if (m_nLastCompareResult != AVELOCITY_SENSOR_NO_LAST_RESULT)
{
//
// The value has changed -- reset the timer. We'll fire the output if
// it stays at this value until the interval expires.
//
m_flFireTime = gpGlobals->curtime + m_flFireInterval;
}
m_nLastCompareResult = nCompare;
}
else if ((m_flFireTime != 0) && (gpGlobals->curtime >= m_flFireTime))
{
//
// The compare result has held steady long enough -- time to
// fire the output.
//
FireCompareOutput(nCompare, this);
m_nLastFireResult = nCompare;
m_flFireTime = 0;
}
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Fires the output after the fire interval if the velocity is stable.
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::InputTestWithInterval( inputdata_t &inputdata )
{
if (m_hTargetEntity != NULL)
{
m_flFireTime = gpGlobals->curtime + m_flFireInterval;
m_nLastFireResult = AVELOCITY_SENSOR_NO_LAST_RESULT;
m_nLastCompareResult = CompareToThreshold(m_hTargetEntity, m_flThreshold, true);
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for forcing an instantaneous test of the condition.
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::InputTest( inputdata_t &inputdata )
{
int nCompareResult = CompareToThreshold(m_hTargetEntity, m_flThreshold, false);
FireCompareOutput(nCompareResult, inputdata.pActivator);
}
//-----------------------------------------------------------------------------
// Purpose: Fires the appropriate output based on the given comparison result.
// Input : nCompareResult -
// pActivator -
//-----------------------------------------------------------------------------
void CPointAngularVelocitySensor::FireCompareOutput( int nCompareResult, CBaseEntity *pActivator )
{
if (nCompareResult == -1)
{
m_OnLessThan.FireOutput(pActivator, this);
m_OnLessThanOrEqualTo.FireOutput(pActivator, this);
}
else if (nCompareResult == 1)
{
m_OnGreaterThan.FireOutput(pActivator, this);
m_OnGreaterThanOrEqualTo.FireOutput(pActivator, this);
}
else
{
m_OnEqualTo.FireOutput(pActivator, this);
m_OnLessThanOrEqualTo.FireOutput(pActivator, this);
m_OnGreaterThanOrEqualTo.FireOutput(pActivator, this);
}
}
// ============================================================================
//
// Simple velocity sensor
//
// ============================================================================
class CPointVelocitySensor : public CPointEntity
{
DECLARE_CLASS( CPointVelocitySensor, CPointEntity );
public:
void Spawn();
void Activate( void );
void Think( void );
private:
void SampleVelocity( void );
EHANDLE m_hTargetEntity; // Entity whose angles are being monitored.
Vector m_vecAxis; // Axis along which to measure the speed.
bool m_bEnabled; // Whether we're measuring or not
// Outputs
float m_fPrevVelocity; // stores velocity from last frame, so we only write the output if it has changed
COutputFloat m_Velocity;
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( point_velocitysensor, CPointVelocitySensor );
BEGIN_DATADESC( CPointVelocitySensor )
// Fields
DEFINE_FIELD( m_hTargetEntity, FIELD_EHANDLE ),
DEFINE_KEYFIELD( m_vecAxis, FIELD_VECTOR, "axis" ),
DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "enabled" ),
DEFINE_FIELD( m_fPrevVelocity, FIELD_FLOAT ),
// Outputs
DEFINE_OUTPUT( m_Velocity, "Velocity" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
END_DATADESC()
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CPointVelocitySensor::Spawn()
{
Vector vLine = m_vecAxis - GetAbsOrigin();
VectorNormalize( vLine );
m_vecAxis = vLine;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPointVelocitySensor::Activate( void )
{
BaseClass::Activate();
m_hTargetEntity = gEntList.FindEntityByName( NULL, m_target );
if ( m_bEnabled && m_hTargetEntity )
{
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPointVelocitySensor::InputEnable( inputdata_t &inputdata )
{
// Don't interrupt us if we're already enabled
if ( m_bEnabled )
return;
m_bEnabled = true;
if ( m_hTargetEntity )
{
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPointVelocitySensor::InputDisable( inputdata_t &inputdata )
{
m_bEnabled = false;
}
//-----------------------------------------------------------------------------
// Purpose: Called every frame
//-----------------------------------------------------------------------------
void CPointVelocitySensor::Think( void )
{
if ( m_hTargetEntity != NULL && m_bEnabled )
{
SampleVelocity();
SetNextThink( gpGlobals->curtime );
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns the magnitude of the entity's angular velocity.
//-----------------------------------------------------------------------------
void CPointVelocitySensor::SampleVelocity( void )
{
if ( m_hTargetEntity == NULL )
return;
Vector vecVelocity;
if ( m_hTargetEntity->GetMoveType() == MOVETYPE_VPHYSICS )
{
IPhysicsObject *pPhys = m_hTargetEntity->VPhysicsGetObject();
if ( pPhys != NULL )
{
pPhys->GetVelocity( &vecVelocity, NULL );
}
}
else
{
vecVelocity = m_hTargetEntity->GetAbsVelocity();
}
/*
float flSpeed = VectorNormalize( vecVelocity );
float flDot = ( m_vecAxis != vec3_origin ) ? DotProduct( vecVelocity, m_vecAxis ) : 1.0f;
*/
// We want the component of the velocity vector in the direction of the axis, which since the
// axis is normalized is simply their dot product (eg V . A = |V|*|A|*cos(theta) )
m_fPrevVelocity = ( m_vecAxis != vec3_origin ) ? DotProduct( vecVelocity, m_vecAxis ) : 1.0f;
// if it's changed since the last frame, poke the output
if ( m_fPrevVelocity != m_Velocity.Get() )
{
m_Velocity.Set( m_fPrevVelocity, NULL, NULL );
}
}

View File

@@ -0,0 +1,268 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Dissolve entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "RagdollBoogie.h"
#include "physics_prop_ragdoll.h"
#include "effect_dispatch_data.h"
#include "te_effect_dispatch.h"
#include "IEffects.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Make electriciy every so often
//-----------------------------------------------------------------------------
static const char *s_pZapContext = "ZapContext";
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC( CRagdollBoogie )
DEFINE_FIELD( m_flStartTime, FIELD_TIME ),
DEFINE_FIELD( m_flBoogieLength, FIELD_FLOAT ),
DEFINE_FIELD( m_flMagnitude, FIELD_FLOAT ),
// Think this should be handled by StartTouch/etc.
// DEFINE_FIELD( m_nSuppressionCount, FIELD_INTEGER ),
DEFINE_FUNCTION( BoogieThink ),
DEFINE_FUNCTION( ZapThink ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( env_ragdoll_boogie, CRagdollBoogie );
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CRagdollBoogie *CRagdollBoogie::Create( CBaseEntity *pTarget, float flMagnitude,
float flStartTime, float flLengthTime, int nSpawnFlags )
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( pTarget );
if ( !pRagdoll )
return NULL;
CRagdollBoogie *pBoogie = (CRagdollBoogie *)CreateEntityByName( "env_ragdoll_boogie" );
if ( pBoogie == NULL )
return NULL;
pBoogie->AddSpawnFlags( nSpawnFlags );
pBoogie->AttachToEntity( pTarget );
pBoogie->SetBoogieTime( flStartTime, flLengthTime );
pBoogie->SetMagnitude( flMagnitude );
pBoogie->Spawn();
return pBoogie;
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CRagdollBoogie::Spawn()
{
BaseClass::Spawn();
SetThink( &CRagdollBoogie::BoogieThink );
SetNextThink( gpGlobals->curtime + 0.01f );
if ( HasSpawnFlags( SF_RAGDOLL_BOOGIE_ELECTRICAL ) )
{
SetContextThink( &CRagdollBoogie::ZapThink, gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ), s_pZapContext );
}
}
//-----------------------------------------------------------------------------
// Zap!
//-----------------------------------------------------------------------------
void CRagdollBoogie::ZapThink()
{
if ( !GetMoveParent() )
return;
CBaseAnimating *pRagdoll = GetMoveParent()->GetBaseAnimating();
if ( !pRagdoll )
return;
// Make electricity on the client
CStudioHdr *pStudioHdr = pRagdoll->GetModelPtr( );
if (!pStudioHdr)
return;
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pRagdoll->GetHitboxSet() );
if ( set->numhitboxes == 0 )
return;
if ( m_nSuppressionCount == 0 )
{
CEffectData data;
data.m_nEntIndex = GetMoveParent()->entindex();
data.m_flMagnitude = 4;
data.m_flScale = HasSpawnFlags(SF_RAGDOLL_BOOGIE_ELECTRICAL_NARROW_BEAM) ? 1.0f : 2.0f;
DispatchEffect( "TeslaHitboxes", data );
}
#ifdef HL2_EPISODIC
EmitSound( "RagdollBoogie.Zap" );
#endif
SetContextThink( &CRagdollBoogie::ZapThink, gpGlobals->curtime + random->RandomFloat( 0.1f, 0.3f ), s_pZapContext );
}
//-----------------------------------------------------------------------------
// Suppression count
//-----------------------------------------------------------------------------
void CRagdollBoogie::IncrementSuppressionCount( CBaseEntity *pTarget )
{
// Look for other boogies on the ragdoll + kill them
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
{
CRagdollBoogie *pBoogie = dynamic_cast<CRagdollBoogie*>(pChild);
if ( !pBoogie )
continue;
++pBoogie->m_nSuppressionCount;
}
}
void CRagdollBoogie::DecrementSuppressionCount( CBaseEntity *pTarget )
{
// Look for other boogies on the ragdoll + kill them
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
CRagdollBoogie *pBoogie = dynamic_cast<CRagdollBoogie*>(pChild);
if ( !pBoogie )
continue;
if ( --pBoogie->m_nSuppressionCount <= 0 )
{
pBoogie->m_nSuppressionCount = 0;
float dt = gpGlobals->curtime - pBoogie->m_flStartTime;
if ( dt >= pBoogie->m_flBoogieLength )
{
PhysCallbackRemove( pBoogie->NetworkProp() );
}
}
}
}
//-----------------------------------------------------------------------------
// Attach to an entity
//-----------------------------------------------------------------------------
void CRagdollBoogie::AttachToEntity( CBaseEntity *pTarget )
{
m_nSuppressionCount = 0;
// Look for other boogies on the ragdoll + kill them
CBaseEntity *pNext;
for ( CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext )
{
pNext = pChild->NextMovePeer();
CRagdollBoogie *pBoogie = dynamic_cast<CRagdollBoogie*>(pChild);
if ( !pBoogie )
continue;
m_nSuppressionCount = pBoogie->m_nSuppressionCount;
UTIL_Remove( pChild );
}
FollowEntity( pTarget );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CRagdollBoogie::SetBoogieTime( float flStartTime, float flLengthTime )
{
m_flStartTime = flStartTime;
m_flBoogieLength = flLengthTime;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CRagdollBoogie::SetMagnitude( float flMagnitude )
{
m_flMagnitude = flMagnitude;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CRagdollBoogie::BoogieThink( void )
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( GetMoveParent() );
if ( !pRagdoll )
{
UTIL_Remove( this );
return;
}
float flMagnitude = m_flMagnitude;
if ( m_flBoogieLength != 0 )
{
float dt = gpGlobals->curtime - m_flStartTime;
if ( dt >= m_flBoogieLength )
{
// Don't remove while suppressed... this helps if we try to start another boogie
if ( m_nSuppressionCount == 0 )
{
UTIL_Remove( this );
}
SetThink( NULL );
return;
}
if ( dt < 0 )
{
SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1, 0.2f ) );
return;
}
flMagnitude = SimpleSplineRemapVal( dt, 0.0f, m_flBoogieLength, m_flMagnitude, 0.0f );
}
#ifndef _XBOX
if ( m_nSuppressionCount == 0 )
{
ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll( );
for ( int j = 0; j < pRagdollPhys->listCount; ++j )
{
float flMass = pRagdollPhys->list[j].pObject->GetMass();
float flForce = m_flMagnitude * flMass;
Vector vecForce;
vecForce = RandomVector( -flForce, flForce );
pRagdollPhys->list[j].pObject->ApplyForceCenter( vecForce );
}
}
#endif // !_XBOX
SetNextThink( gpGlobals->curtime + random->RandomFloat( 0.1, 0.2f ) );
}

View File

@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef RAGDOLLBOOGIE_H
#define RAGDOLLBOOGIE_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Set this spawnflag before calling Spawn to get electrical effects
//-----------------------------------------------------------------------------
#define SF_RAGDOLL_BOOGIE_ELECTRICAL 0x10000
#define SF_RAGDOLL_BOOGIE_ELECTRICAL_NARROW_BEAM 0x20000
//-----------------------------------------------------------------------------
// Makes ragdolls DANCE!
//-----------------------------------------------------------------------------
class CRagdollBoogie : public CBaseEntity
{
DECLARE_DATADESC();
DECLARE_CLASS( CRagdollBoogie, CBaseEntity );
public:
static CRagdollBoogie *Create( CBaseEntity *pTarget, float flMagnitude, float flStartTime, float flLengthTime = 0.0f, int nSpawnFlags = 0 );
static void IncrementSuppressionCount( CBaseEntity *pTarget );
static void DecrementSuppressionCount( CBaseEntity *pTarget );
void Spawn();
private:
void AttachToEntity( CBaseEntity *pTarget );
void SetBoogieTime( float flStartTime, float flLengthTime );
void SetMagnitude( float flMagnitude );
void BoogieThink( void );
void ZapThink();
float m_flStartTime;
float m_flBoogieLength;
float m_flMagnitude;
int m_nSuppressionCount;
};
#endif // RAGDOLLBOOGIE_H

View File

@@ -0,0 +1,268 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Dissolve entity to be attached to target entity. Serves two purposes:
//
// 1) An entity that can be placed by a level designer and triggered
// to ignite a target entity.
//
// 2) An entity that can be created at runtime to ignite a target entity.
//
//=============================================================================//
#include "cbase.h"
#include "RagdollEgonBoogie.h"
#include "physics_prop_ragdoll.h"
#include "effect_dispatch_data.h"
#include "te_effect_dispatch.h"
#include "IEffects.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Make electriciy every so often
//-----------------------------------------------------------------------------
static const char *s_pZapContext = "ZapContext";
//-----------------------------------------------------------------------------
// Save/load
//-----------------------------------------------------------------------------
BEGIN_DATADESC(CRagdollEgonBoogie)
DEFINE_FIELD(m_flStartTime, FIELD_TIME),
DEFINE_FIELD(m_flBoogieLength, FIELD_FLOAT),
DEFINE_FIELD(m_flMagnitude, FIELD_FLOAT),
// Think this should be handled by StartTouch/etc.
// DEFINE_FIELD( m_nSuppressionCount, FIELD_INTEGER ),
DEFINE_FUNCTION(BoogieThink),
DEFINE_FUNCTION(ZapThink),
END_DATADESC()
LINK_ENTITY_TO_CLASS(env_ragdoll_egon_boogie, CRagdollEgonBoogie);
//-----------------------------------------------------------------------------
// Purpose: Creates a flame and attaches it to a target entity.
// Input : pTarget -
//-----------------------------------------------------------------------------
CRagdollEgonBoogie *CRagdollEgonBoogie::Create(CBaseEntity *pTarget, float flMagnitude,
float flStartTime, float flLengthTime, int nSpawnFlags)
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >(pTarget);
if (!pRagdoll)
return NULL;
CRagdollEgonBoogie *pBoogie = (CRagdollEgonBoogie *)CreateEntityByName("env_ragdoll_egon_boogie");
if (pBoogie == NULL)
return NULL;
pBoogie->AddSpawnFlags(nSpawnFlags);
pBoogie->AttachToEntity(pTarget);
pBoogie->SetBoogieTime(flStartTime, flLengthTime);
pBoogie->SetMagnitude(flMagnitude);
pBoogie->Spawn();
return pBoogie;
}
//-----------------------------------------------------------------------------
// Spawn
//-----------------------------------------------------------------------------
void CRagdollEgonBoogie::Spawn()
{
BaseClass::Spawn();
SetThink(&CRagdollEgonBoogie::BoogieThink);
SetNextThink(gpGlobals->curtime + 0.01f);
if (HasSpawnFlags(SF_RAGDOLL_EGON_BOOGIE_ELECTRICAL))
{
SetContextThink(&CRagdollEgonBoogie::ZapThink, gpGlobals->curtime + random->RandomFloat(0.1f, 0.3f), s_pZapContext);
}
}
//-----------------------------------------------------------------------------
// Zap!
//-----------------------------------------------------------------------------
void CRagdollEgonBoogie::ZapThink()
{
if (!GetMoveParent())
return;
CBaseAnimating *pRagdoll = GetMoveParent()->GetBaseAnimating();
if (!pRagdoll)
return;
// Make electricity on the client
CStudioHdr *pStudioHdr = pRagdoll->GetModelPtr();
if (!pStudioHdr)
return;
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet(pRagdoll->GetHitboxSet());
if (set->numhitboxes == 0)
return;
if (m_nSuppressionCount == 0)
{
CEffectData data;
data.m_nEntIndex = GetMoveParent()->entindex();
data.m_flMagnitude = 4;
data.m_flScale = HasSpawnFlags(SF_RAGDOLL_EGON_BOOGIE_ELECTRICAL_NARROW_BEAM) ? 1.0f : 2.0f;
DispatchEffect("TeslaHitboxes", data);
}
#ifdef HL2_EPISODIC
EmitSound("RagdollBoogie.Zap");
#endif
SetContextThink(&CRagdollEgonBoogie::ZapThink, gpGlobals->curtime + random->RandomFloat(0.1f, 0.3f), s_pZapContext);
}
//-----------------------------------------------------------------------------
// Suppression count
//-----------------------------------------------------------------------------
void CRagdollEgonBoogie::IncrementSuppressionCount(CBaseEntity *pTarget)
{
// Look for other boogies on the ragdoll + kill them
for (CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer())
{
CRagdollEgonBoogie *pBoogie = dynamic_cast<CRagdollEgonBoogie*>(pChild);
if (!pBoogie)
continue;
++pBoogie->m_nSuppressionCount;
}
}
void CRagdollEgonBoogie::DecrementSuppressionCount(CBaseEntity *pTarget)
{
// Look for other boogies on the ragdoll + kill them
CBaseEntity *pNext;
for (CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext)
{
pNext = pChild->NextMovePeer();
CRagdollEgonBoogie *pBoogie = dynamic_cast<CRagdollEgonBoogie*>(pChild);
if (!pBoogie)
continue;
if (--pBoogie->m_nSuppressionCount <= 0)
{
pBoogie->m_nSuppressionCount = 0;
float dt = gpGlobals->curtime - pBoogie->m_flStartTime;
if (dt >= pBoogie->m_flBoogieLength)
{
PhysCallbackRemove(pBoogie->NetworkProp());
}
}
}
}
//-----------------------------------------------------------------------------
// Attach to an entity
//-----------------------------------------------------------------------------
void CRagdollEgonBoogie::AttachToEntity(CBaseEntity *pTarget)
{
m_nSuppressionCount = 0;
// Look for other boogies on the ragdoll + kill them
CBaseEntity *pNext;
for (CBaseEntity *pChild = pTarget->FirstMoveChild(); pChild; pChild = pNext)
{
pNext = pChild->NextMovePeer();
CRagdollEgonBoogie *pBoogie = dynamic_cast<CRagdollEgonBoogie*>(pChild);
if (!pBoogie)
continue;
m_nSuppressionCount = pBoogie->m_nSuppressionCount;
UTIL_Remove(pChild);
}
FollowEntity(pTarget);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lifetime -
//-----------------------------------------------------------------------------
void CRagdollEgonBoogie::SetBoogieTime(float flStartTime, float flLengthTime)
{
m_flStartTime = flStartTime;
m_flBoogieLength = flLengthTime;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CRagdollEgonBoogie::SetMagnitude(float flMagnitude)
{
m_flMagnitude = flMagnitude;
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CRagdollEgonBoogie::BoogieThink(void)
{
CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >(GetMoveParent());
if (!pRagdoll)
{
UTIL_Remove(this);
return;
}
float flMagnitude = m_flMagnitude;
if (m_flBoogieLength != 0)
{
float dt = gpGlobals->curtime - m_flStartTime;
if (dt >= m_flBoogieLength)
{
// Don't remove while suppressed... this helps if we try to start another boogie
if (m_nSuppressionCount == 0)
{
UTIL_Remove(this);
}
SetThink(NULL);
return;
}
if (dt < 0)
{
SetNextThink(gpGlobals->curtime + random->RandomFloat(0.1, 0.2f));
return;
}
flMagnitude = SimpleSplineRemapVal(dt, 0.0f, m_flBoogieLength, m_flMagnitude, 0.0f);
}
#ifndef _XBOX
if (m_nSuppressionCount == 0)
{
ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll();
for (int j = 0; j < pRagdollPhys->listCount; ++j)
{
float flMass = pRagdollPhys->list[j].pObject->GetMass();
float flForce = m_flMagnitude * flMass;
Vector vecForce;
vecForce = RandomVector(-flForce, flForce);
pRagdollPhys->list[j].pObject->ApplyForceCenter(vecForce);
}
}
#endif // !_XBOX
SetNextThink(gpGlobals->curtime + random->RandomFloat(0.1, 0.2f));
}

Some files were not shown because too many files have changed in this diff Show More