mirror of
https://github.com/Gigaslav/HL2Overcharged.git
synced 2026-01-04 02:10:18 +03:00
Init comit
This commit is contained in:
31
game/client/vgui_int.h
Normal file
31
game/client/vgui_int.h
Normal 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
|
||||
176
game/client/vgui_loadingdiscpanel.cpp
Normal file
176
game/client/vgui_loadingdiscpanel.cpp
Normal 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;
|
||||
467
game/client/vgui_messagechars.cpp
Normal file
467
game/client/vgui_messagechars.cpp
Normal 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;
|
||||
1513
game/client/vgui_netgraphpanel.cpp
Normal file
1513
game/client/vgui_netgraphpanel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
291
game/client/vgui_schemevisualizer.cpp
Normal file
291
game/client/vgui_schemevisualizer.cpp
Normal 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 );
|
||||
}
|
||||
55
game/client/vgui_schemevisualizer.h
Normal file
55
game/client/vgui_schemevisualizer.h
Normal 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
|
||||
174
game/client/vgui_slideshow_display_screen.cpp
Normal file
174
game/client/vgui_slideshow_display_screen.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
414
game/client/vgui_textmessagepanel.cpp
Normal file
414
game/client/vgui_textmessagepanel.cpp
Normal 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
423
game/client/vgui_video.cpp
Normal 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
79
game/client/vgui_video.h
Normal 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
|
||||
457
game/client/vgui_video_player.cpp
Normal file
457
game/client/vgui_video_player.cpp
Normal 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 );
|
||||
}
|
||||
88
game/client/vgui_video_player.h
Normal file
88
game/client/vgui_video_player.h
Normal 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
|
||||
|
||||
48
game/client/vguicenterprint.h
Normal file
48
game/client/vguicenterprint.h
Normal 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
1412
game/client/view.cpp
Normal file
File diff suppressed because it is too large
Load Diff
98
game/client/view.h
Normal file
98
game/client/view.h
Normal 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
2354
game/client/view_beams.cpp
Normal file
File diff suppressed because it is too large
Load Diff
795
game/client/view_effects.cpp
Normal file
795
game/client/view_effects.cpp
Normal 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
155
game/client/view_scene.cpp
Normal 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
166
game/client/view_scene.h
Normal 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
|
||||
386
game/client/viewangleanim.cpp
Normal file
386
game/client/viewangleanim.cpp
Normal 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 );
|
||||
}
|
||||
|
||||
75
game/client/viewangleanim.h
Normal file
75
game/client/viewangleanim.h
Normal 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
675
game/client/viewdebug.cpp
Normal 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
29
game/client/viewdebug.h
Normal 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
|
||||
3085
game/client/viewpostprocess.cpp
Normal file
3085
game/client/viewpostprocess.cpp
Normal file
File diff suppressed because it is too large
Load Diff
18
game/client/viewpostprocess.h
Normal file
18
game/client/viewpostprocess.h
Normal 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
7302
game/client/viewrender.cpp
Normal file
File diff suppressed because it is too large
Load Diff
560
game/client/viewrender.h
Normal file
560
game/client/viewrender.h
Normal 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 ¶ms );
|
||||
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
789
game/client/vis_tester.cpp
Normal 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
123
game/client/voice_menu.cpp
Normal 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;
|
||||
}
|
||||
95
game/client/warp_overlay.cpp
Normal file
95
game/client/warp_overlay.cpp
Normal 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 );
|
||||
}
|
||||
}
|
||||
712
game/client/weapon_selection.cpp
Normal file
712
game/client/weapon_selection.cpp
Normal 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;
|
||||
}
|
||||
119
game/client/weapon_selection.h
Normal file
119
game/client/weapon_selection.h
Normal 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
|
||||
270
game/client/weapons_resource.cpp
Normal file
270
game/client/weapons_resource.cpp
Normal 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;
|
||||
}
|
||||
|
||||
44
game/client/weapons_resource.h
Normal file
44
game/client/weapons_resource.h
Normal 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
307
game/client/worldlight.cpp
Normal 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
50
game/client/worldlight.h
Normal 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
17
game/protobuf_include.vpc
Normal 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
516
game/server/AI_Criteria.cpp
Normal 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
237
game/server/AI_Criteria.h
Normal 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
|
||||
139
game/server/AI_Interest_Target.cpp
Normal file
139
game/server/AI_Interest_Target.cpp
Normal 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;
|
||||
}
|
||||
88
game/server/AI_Interest_Target.h
Normal file
88
game/server/AI_Interest_Target.h
Normal 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
|
||||
3404
game/server/AI_ResponseSystem.cpp
Normal file
3404
game/server/AI_ResponseSystem.cpp
Normal file
File diff suppressed because it is too large
Load Diff
41
game/server/AI_ResponseSystem.h
Normal file
41
game/server/AI_ResponseSystem.h
Normal 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
268
game/server/AR2Bullet.cpp
Normal 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
47
game/server/AR2Bullet.h
Normal 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
|
||||
1153
game/server/BaseAnimatingOverlay.cpp
Normal file
1153
game/server/BaseAnimatingOverlay.cpp
Normal file
File diff suppressed because it is too large
Load Diff
232
game/server/BaseAnimatingOverlay.h
Normal file
232
game/server/BaseAnimatingOverlay.h
Normal 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
310
game/server/BasePropDoor.h
Normal 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
|
||||
495
game/server/BloodEmitter.cpp
Normal file
495
game/server/BloodEmitter.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
76
game/server/BloodEmitter.h
Normal file
76
game/server/BloodEmitter.h
Normal 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
|
||||
222
game/server/CRagdollMagnet.cpp
Normal file
222
game/server/CRagdollMagnet.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
45
game/server/CRagdollMagnet.h
Normal file
45
game/server/CRagdollMagnet.h
Normal 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
|
||||
314
game/server/Cguard_Sphere.cpp
Normal file
314
game/server/Cguard_Sphere.cpp
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
47
game/server/Cguard_Sphere.h
Normal file
47
game/server/Cguard_Sphere.h
Normal 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
|
||||
2
game/server/ClassDiagram.cd
Normal file
2
game/server/ClassDiagram.cd
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ClassDiagram />
|
||||
1659
game/server/CommentarySystem.cpp
Normal file
1659
game/server/CommentarySystem.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
game/server/Debug_mod_episodic/server.pch.codeanalysis
Normal file
BIN
game/server/Debug_mod_episodic/server.pch.codeanalysis
Normal file
Binary file not shown.
BIN
game/server/Debug_mod_episodic/server.pch.codeanalysisast
Normal file
BIN
game/server/Debug_mod_episodic/server.pch.codeanalysisast
Normal file
Binary file not shown.
BIN
game/server/Debug_mod_hl2/server.pch.codeanalysis
Normal file
BIN
game/server/Debug_mod_hl2/server.pch.codeanalysis
Normal file
Binary file not shown.
BIN
game/server/Debug_mod_hl2/server.pch.codeanalysisast
Normal file
BIN
game/server/Debug_mod_hl2/server.pch.codeanalysisast
Normal file
Binary file not shown.
198
game/server/EffectsServer.cpp
Normal file
198
game/server/EffectsServer.cpp
Normal 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;
|
||||
}
|
||||
388
game/server/EntityDissolve.cpp
Normal file
388
game/server/EntityDissolve.cpp
Normal 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 );
|
||||
}
|
||||
63
game/server/EntityDissolve.h
Normal file
63
game/server/EntityDissolve.h
Normal 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
|
||||
505
game/server/EntityDissolveEgon.cpp
Normal file
505
game/server/EntityDissolveEgon.cpp
Normal 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);
|
||||
}
|
||||
64
game/server/EntityDissolveEgon.h
Normal file
64
game/server/EntityDissolveEgon.h
Normal 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
335
game/server/EntityFlame.cpp
Normal 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
66
game/server/EntityFlame.h
Normal 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
|
||||
207
game/server/EntityParticleTrail.cpp
Normal file
207
game/server/EntityParticleTrail.cpp
Normal 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 ¶ms )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
52
game/server/EntityParticleTrail.h
Normal file
52
game/server/EntityParticleTrail.h
Normal 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 ¶ms );
|
||||
|
||||
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
762
game/server/EnvBeam.cpp
Normal 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
200
game/server/EnvFade.cpp
Normal 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
142
game/server/EnvHudHint.cpp
Normal 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
250
game/server/EnvLaser.cpp
Normal 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
51
game/server/EnvLaser.h
Normal 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
278
game/server/EnvMessage.cpp
Normal 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
48
game/server/EnvMessage.h
Normal 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
413
game/server/EnvShake.cpp
Normal 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
195
game/server/EnvSpark.cpp
Normal 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
257
game/server/EventLog.cpp
Normal 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
46
game/server/EventLog.h
Normal 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
1099
game/server/GameStats.cpp
Normal file
File diff suppressed because it is too large
Load Diff
183
game/server/GameStats_BasicStatsFunctions.cpp
Normal file
183
game/server/GameStats_BasicStatsFunctions.cpp
Normal 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;
|
||||
}
|
||||
|
||||
289
game/server/MaterialModifyControl.cpp
Normal file
289
game/server/MaterialModifyControl.cpp
Normal 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() );
|
||||
}
|
||||
529
game/server/PointAngularVelocitySensor.cpp
Normal file
529
game/server/PointAngularVelocitySensor.cpp
Normal 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 );
|
||||
}
|
||||
}
|
||||
268
game/server/RagdollBoogie.cpp
Normal file
268
game/server/RagdollBoogie.cpp
Normal 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 ) );
|
||||
}
|
||||
50
game/server/RagdollBoogie.h
Normal file
50
game/server/RagdollBoogie.h
Normal 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
|
||||
268
game/server/RagdollEgonBoogie.cpp
Normal file
268
game/server/RagdollEgonBoogie.cpp
Normal 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
Reference in New Issue
Block a user