Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

660 lines
22 KiB

//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: Declares the base class for all paint power users.
//
//=============================================================================//
#ifndef PAINT_POWER_USER_H
#define PAINT_POWER_USER_H
#include <utility>
#include <algorithm>
#include "gamestringpool.h"
#include "paint_power_user_interface.h"
#include "portal_player_shared.h"
#include "paint_power_info.h"
extern ConVar sv_enable_paint_power_user_debug;
//#define PAINT_POWER_USER_DEBUG
char const* const PAINT_POWER_USER_DATA_CLASS_NAME = "PaintPowerUser";
const int MAX_PAINT_SURFACE_CONTEXT_LENGTH = 32;
template< typename T >
inline T* GetBegin( CUtlVector<T>& v )
{
return v.Base();
}
template< typename T >
inline T* GetEnd( CUtlVector<T>& v )
{
return v.Base() + v.Count();
}
template< typename T >
inline const T* GetConstBegin( const CUtlVector<T>& v )
{
return v.Base();
}
template< typename T >
inline const T* GetConstEnd( const CUtlVector<T>& v )
{
return v.Base() + v.Count();
}
template< typename T >
inline const std::pair< T*, T* > GetRange( CUtlVector< T >& v )
{
return std::pair< T*, T* >( v.Base(), v.Base() + v.Count() );
}
template< typename T >
inline const std::pair< const T*, const T* > GetConstRange( const CUtlVector< T >& v )
{
return std::pair< const T*, const T* >( v.Base(), v.Base() + v.Count() );
}
template< typename IteratorType >
inline int GetCountFromRange( const std::pair< IteratorType, IteratorType >& range )
{
return range.second - range.first;
}
template< typename IteratorType >
inline bool IsEmptyRange( const std::pair< IteratorType, IteratorType >& range )
{
return range.first == range.second;
}
//=============================================================================
// class PaintPowerUser
// Purpose: Base class for entities which use paint powers.
//=============================================================================
template< typename BaseEntityType >
class PaintPowerUser : public BaseEntityType, public IPaintPowerUser
{
DECLARE_CLASS( PaintPowerUser< BaseEntityType >, BaseEntityType );
#if defined( CLIENT_DLL ) && !defined( NO_ENTITY_PREDICTION )
DECLARE_PREDICTABLE();
static const datamap_t PredMapInit();
#endif
public:
//-------------------------------------------------------------------------
// Constructor/Virtual Destructor
//-------------------------------------------------------------------------
PaintPowerUser();
virtual ~PaintPowerUser();
//-------------------------------------------------------------------------
// Public Accessors
//-------------------------------------------------------------------------
virtual const PaintPowerConstRange GetPaintPowers() const;
virtual const PaintPowerInfo_t& GetPaintPower( unsigned powerType ) const;
virtual const PaintPowerInfo_t* FindHighestPriorityActivePaintPower() const;
//-------------------------------------------------------------------------
// Paint Power Effects
//-------------------------------------------------------------------------
virtual void AddSurfacePaintPowerInfo( const PaintPowerInfo_t& contact, char const* context /*= 0*/ );
virtual void UpdatePaintPowers();
//-------------------------------------------------------------------------
// Protected Types
//-------------------------------------------------------------------------
typedef CUtlVector< PaintPowerInfo_t > PaintPowerInfoVector;
virtual void ChooseActivePaintPowers( PaintPowerInfoVector& activePowers ) = 0; // Default provided
void ClearSurfacePaintPowerInfo();
protected:
//-------------------------------------------------------------------------
// Paint Power Effects
//-------------------------------------------------------------------------
typedef int (*PaintPowerInfoCompare)( const PaintPowerInfo_t*, const PaintPowerInfo_t* );
void PrioritySortSurfacePaintPowerInfo( PaintPowerInfoCompare comp );
PaintPowerState ActivatePaintPower( PaintPowerInfo_t& power );
PaintPowerState UsePaintPower( PaintPowerInfo_t& power );
PaintPowerState DeactivatePaintPower( PaintPowerInfo_t& power );
void MapSurfacesToPowers();
bool SurfaceInfoContainsPower( const PaintPowerInfo_t& power, char const* context = 0 ) const;
//-------------------------------------------------------------------------
// Protected Accessors
//-------------------------------------------------------------------------
const PaintPowerConstRange GetSurfacePaintPowerInfo( char const* context = 0 ) const;
bool HasAnySurfacePaintPowerInfo() const;
//-------------------------------------------------------------------------
// Protected Mutators
//-------------------------------------------------------------------------
void ForceSetPaintPower( const PaintPowerInfo_t& powerInfo );
void ForcePaintPowerToState( PaintPowerType type, PaintPowerState newState );
private:
//-------------------------------------------------------------------------
// Private Types
//-------------------------------------------------------------------------
struct ContextSurfacePaintPowerInfo_t
{
PaintPowerInfoVector paintPowerInfo;
string_t context;
};
typedef CUtlVector< ContextSurfacePaintPowerInfo_t > ContextPaintPowerInfoArray;
//-------------------------------------------------------------------------
// Private Data
//-------------------------------------------------------------------------
PaintPowerInfo_t m_PaintPowers[PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER]; // Current powers and their states
PaintPowerInfoVector m_SurfacePaintPowerInfo; // Array of paint power info from surfaces touched
ContextPaintPowerInfoArray m_ContextSurfacePaintPowerInfo; // Array of paint power info from surfaces under some context
//-------------------------------------------------------------------------
// Private Accessors
//-------------------------------------------------------------------------
const PaintPowerRange GetNonConstSurfacePaintPowerInfo( char const* context = 0 );
int FindContextSurfacePaintPowerInfo( char const* context ) const;
//-------------------------------------------------------------------------
// Paint Power Effects
//-------------------------------------------------------------------------
virtual PaintPowerState ActivateSpeedPower( PaintPowerInfo_t& powerInfo ) = 0;
virtual PaintPowerState UseSpeedPower( PaintPowerInfo_t& powerInfo ) = 0;
virtual PaintPowerState DeactivateSpeedPower( PaintPowerInfo_t& powerInfo ) = 0;
virtual PaintPowerState ActivateBouncePower( PaintPowerInfo_t& powerInfo ) = 0;
virtual PaintPowerState UseBouncePower( PaintPowerInfo_t& powerInfo ) = 0;
virtual PaintPowerState DeactivateBouncePower( PaintPowerInfo_t& powerInfo ) = 0;
virtual PaintPowerState ActivateNoPower( PaintPowerInfo_t& powerInfo );
virtual PaintPowerState UseNoPower( PaintPowerInfo_t& powerInfo );
virtual PaintPowerState DeactivateNoPower( PaintPowerInfo_t& powerInfo );
};
//=============================================================================
// PaintPowerUser Implementation
//=============================================================================
//#define DEFINE_PRED_TYPEDESCRIPTION( name, fieldtype ) \
// { FIELD_EMBEDDED, #name, offsetof(classNameTypedef, name), 1, FTYPEDESC_SAVE | FTYPEDESC_KEY, NULL, NULL, NULL, &fieldtype::m_PredMap }
// OMFG HACK: A macro to individually add embedded types from arrays because the current macros don't handle arrays of embedded types properly
// OMFG TODO: Write a generic macro to work with templatized classes.
#define DEFINE_EMBEDDED_ARRAY_ELEMENT( elementType, arrayName, arrayIndex ) \
{ FIELD_EMBEDDED, #arrayName"["#arrayIndex"]", offsetof(classNameTypedef, arrayName[arrayIndex]), 1, FTYPEDESC_SAVE | FTYPEDESC_KEY, NULL, NULL, NULL, &elementType::m_PredMap }
// OMFG HACK: Define the prediction table. The current macros don't work with templatized classes.
// OMFG TODO: Write a generic macro to work with templatized classes.
#if defined( CLIENT_DLL ) && !defined( NO_ENTITY_PREDICTION )
template< typename BaseEntityType >
datamap_t PaintPowerUser<BaseEntityType>::m_PredMap = PaintPowerUser<BaseEntityType>::PredMapInit();
// Note: This type description table is unused but declared as part of DECLARE_PREDICTABLE. Initializing it here to get rid of warnings.
template< typename BaseEntityType >
typedescription_t PaintPowerUser<BaseEntityType>::m_PredDesc[1] = { { FIELD_VOID,0,0,0,0,0,0,0,0 } };
template< typename BaseEntityType >
datamap_t *PaintPowerUser<BaseEntityType>::GetPredDescMap( void )
{
return &m_PredMap;
}
template< typename BaseEntityType >
const datamap_t PaintPowerUser<BaseEntityType>::PredMapInit()
{
typedef PaintPowerUser<BaseEntityType> classNameTypedef;
static typedescription_t predDesc[] =
{
//{ FIELD_VOID,0,0,0,0,0,0,0,0 },
//DEFINE_EMBEDDED_AUTO_ARRAY( m_PaintPowers ) // This only predicts the first element of the array right now
DEFINE_EMBEDDED_ARRAY_ELEMENT( PaintPowerInfo_t, m_PaintPowers, BOUNCE_POWER ),
DEFINE_EMBEDDED_ARRAY_ELEMENT( PaintPowerInfo_t, m_PaintPowers, SPEED_POWER ),
DEFINE_EMBEDDED_ARRAY_ELEMENT( PaintPowerInfo_t, m_PaintPowers, NO_POWER )
};
datamap_t predMap = { predDesc, ARRAYSIZE( predDesc ), PAINT_POWER_USER_DATA_CLASS_NAME, &PaintPowerUser<BaseEntityType>::BaseClass::m_PredMap };
return predMap;
}
#endif // if defined( CLIENT_DLL ) && !defined( NO_ENTITY_PREDICTION )
template< typename BaseEntityType >
PaintPowerUser<BaseEntityType>::PaintPowerUser()
{
for( unsigned i = 0; i < PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER; ++i )
{
m_PaintPowers[i] = PaintPowerInfo_t();
m_PaintPowers[i].m_State = INACTIVE_PAINT_POWER;
}
}
template< typename BaseEntityType >
PaintPowerUser<BaseEntityType>::~PaintPowerUser()
{
}
template< typename BaseEntityType >
const PaintPowerConstRange PaintPowerUser<BaseEntityType>::GetPaintPowers() const
{
return PaintPowerConstRange( m_PaintPowers, m_PaintPowers + ARRAYSIZE(m_PaintPowers) );
}
template< typename BaseEntityType >
const PaintPowerInfo_t& PaintPowerUser<BaseEntityType>::GetPaintPower( unsigned powerType ) const
{
AssertMsg( powerType < PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER, "Out of bounds." );
return m_PaintPowers[ powerType < PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER ? powerType : NO_POWER ];
}
template< typename BaseEntityType >
const PaintPowerInfo_t* PaintPowerUser<BaseEntityType>::FindHighestPriorityActivePaintPower() const
{
const PaintPowerInfo_t* pPower = 0;
for( unsigned i = 0; i < PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER; ++i )
{
if( m_PaintPowers[i].m_State == ACTIVE_PAINT_POWER )
{
pPower = m_PaintPowers + i;
break;
}
}
return pPower;
}
template< typename BaseEntityType >
void PaintPowerUser<BaseEntityType>::AddSurfacePaintPowerInfo( const PaintPowerInfo_t& contact, char const* context )
{
if ( !engine->HasPaintmap() )
{
Warning( "MEMORY LEAK: adding surface paint powers in a level with no paintmaps.\n" );
return;
}
// If there's no context, add it to the default list
if( context == NULL)
{
m_SurfacePaintPowerInfo.AddToTail( contact );
}
// There is a context, so add it to the appropriate list
else
{
// Search for context
int index = FindContextSurfacePaintPowerInfo( context );
// If not found, create it first
if( index == m_ContextSurfacePaintPowerInfo.InvalidIndex() )
{
index = m_ContextSurfacePaintPowerInfo.Count();
m_ContextSurfacePaintPowerInfo.EnsureCount( index + 1 );
m_ContextSurfacePaintPowerInfo[index].context = AllocPooledString( context );
}
// Add the new surface info
m_ContextSurfacePaintPowerInfo[index].paintPowerInfo.AddToTail( contact );
}
}
template< typename BaseEntityType >
void PaintPowerUser<BaseEntityType>::ChooseActivePaintPowers( PaintPowerInfoVector& activePowers )
{
// Figure out colors/powers
MapSurfacesToPowers();
// If there is a contact with any surface
if( m_SurfacePaintPowerInfo.Count() != 0 )
{
// Sort the surfaces by priority
PrioritySortSurfacePaintPowerInfo( &DescendingPaintPriorityCompare );
// The active power is the one with the highest priority
activePowers.AddToTail( m_SurfacePaintPowerInfo.Head() );
}
}
template< typename BaseEntityType >
void PaintPowerUser<BaseEntityType>::UpdatePaintPowers()
{
// Only update if there's paint in the map
if( engine->HasPaintmap() )
{
// Update which powers are active
PaintPowerInfoVector activePowers;
ChooseActivePaintPowers( activePowers );
// Cache the powers
PaintPowerInfo_t cachedPowers[PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER];
//V_memcpy( cachedPowers, m_PaintPowers, sizeof(PaintPowerInfo_t) * PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER );
std::copy( m_PaintPowers, m_PaintPowers + PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER, cachedPowers );
// Set all powers in a state other than inactive to deactivating
for( unsigned i = 0; i < PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER; ++i )
{
PaintPowerInfo_t& power = m_PaintPowers[i];
power.m_State = IsInactivePower( power ) ? INACTIVE_PAINT_POWER : DEACTIVATING_PAINT_POWER;
}
// For each new active power
PaintPowerConstRange activeRange = GetConstRange( activePowers );
for( PaintPowerConstIter i = activeRange.first; i != activeRange.second; ++i )
{
// Set it as the current one
const PaintPowerInfo_t& newPower = *i;
const unsigned index = newPower.m_PaintPowerType;
m_PaintPowers[index] = newPower;
// If the old power was active and roughly the same, keep it active. Otherwise, activate it.
const PaintPowerInfo_t& oldPower = cachedPowers[index];
const bool stayActive = IsActivePower( oldPower ) && AreSamePower( oldPower, newPower );
m_PaintPowers[index].m_State = stayActive ? ACTIVE_PAINT_POWER : ACTIVATING_PAINT_POWER;
}
// Clear the surface information
// NOTE: Calling this after Activating/Using/Deactivating paint powers makes sticky boxes not very sticky
// and that's why I moved it back over here. -Brett
ClearSurfacePaintPowerInfo();
// Update the state of each power
for( unsigned i = 0; i < PAINT_POWER_TYPE_COUNT_PLUS_NO_POWER; ++i )
{
switch( m_PaintPowers[i].m_State )
{
case ACTIVATING_PAINT_POWER:
m_PaintPowers[i].m_State = ActivatePaintPower( m_PaintPowers[i] );
#if defined CLIENT_DLL
RANDOM_CEG_TEST_SECRET_PERIOD( 127, 1023 );
#endif
break;
case ACTIVE_PAINT_POWER:
m_PaintPowers[i].m_State = UsePaintPower( m_PaintPowers[i] );
break;
case DEACTIVATING_PAINT_POWER:
#if defined GAME_DLL
RANDOM_CEG_TEST_SECRET_PERIOD( 937, 3821 );
#endif
m_PaintPowers[i].m_State = DeactivatePaintPower( m_PaintPowers[i] );
break;
}
}
}
}
template< typename BaseEntityType >
void PaintPowerUser<BaseEntityType>::ClearSurfacePaintPowerInfo()
{
m_SurfacePaintPowerInfo.RemoveAll();
const int count = m_ContextSurfacePaintPowerInfo.Count();
for( int i = 0; i < count; ++i )
{
m_ContextSurfacePaintPowerInfo[i].paintPowerInfo.RemoveAll();
}
}
template< typename BaseEntityType >
void PaintPowerUser<BaseEntityType>::PrioritySortSurfacePaintPowerInfo( PaintPowerInfoCompare comp )
{
// Sort the surfaces by priority
m_SurfacePaintPowerInfo.Sort( comp );
const int count = m_ContextSurfacePaintPowerInfo.Count();
for( int i = 0; i < count; ++i )
{
m_ContextSurfacePaintPowerInfo[i].paintPowerInfo.Sort( comp );
}
}
template< typename PaintPowerIterator >
void MapSurfacesToPowers( PaintPowerIterator begin, PaintPowerIterator end )
{
for( PaintPowerIterator i = begin; i != end; ++i )
{
MapSurfaceToPower(*i);
}
}
template< typename BaseEntityType >
void PaintPowerUser<BaseEntityType>::MapSurfacesToPowers()
{
PaintPowerRange range = GetNonConstSurfacePaintPowerInfo();
::MapSurfacesToPowers( range.first, range.second );
const int count = m_ContextSurfacePaintPowerInfo.Count();
for( int i = 0; i < count; ++i )
{
PaintPowerRange contextRange = GetRange( m_ContextSurfacePaintPowerInfo[i].paintPowerInfo );
::MapSurfacesToPowers( contextRange.first, contextRange.second );
}
}
template< typename BaseEntityType >
bool PaintPowerUser<BaseEntityType>::SurfaceInfoContainsPower( const PaintPowerInfo_t& power, char const* context ) const
{
PaintPowerConstRange range = GetSurfacePaintPowerInfo( context );
for( PaintPowerConstIter i = range.first; i != range.second; ++i )
{
if( AreSamePower(power, *i) )
return true;
}
return false;
}
template< typename BaseEntityType >
const PaintPowerRange PaintPowerUser<BaseEntityType>::GetNonConstSurfacePaintPowerInfo( char const* context )
{
if( !context )
return GetRange( m_SurfacePaintPowerInfo );
const int i = FindContextSurfacePaintPowerInfo( context );
#ifdef PAINT_POWER_USER_DEBUG
if( i == m_ContextSurfacePaintPowerInfo.InvalidIndex() )
Warning( "Trying to get a range that doesn't exist.\n" );
#endif
return i != m_ContextSurfacePaintPowerInfo.InvalidIndex() ? GetRange( m_ContextSurfacePaintPowerInfo[i].paintPowerInfo ) : PaintPowerRange( (PaintPowerIter)0, (PaintPowerIter)0 );
}
template< typename BaseEntityType >
int PaintPowerUser<BaseEntityType>::FindContextSurfacePaintPowerInfo( char const* context ) const
{
AssertMsg( context, "Null pointers are bad, and you should feel bad." );
int index = m_ContextSurfacePaintPowerInfo.InvalidIndex();
const int count = m_ContextSurfacePaintPowerInfo.Count();
for( int i = 0; i < count; ++i )
{
if( !V_strncmp( STRING( m_ContextSurfacePaintPowerInfo[i].context ), context, MAX_PAINT_SURFACE_CONTEXT_LENGTH ) )
{
index = i;
break;
}
}
return index;
}
template< typename BaseEntityType >
PaintPowerState PaintPowerUser<BaseEntityType>::ActivatePaintPower( PaintPowerInfo_t& power )
{
AssertMsg( power.m_State == ACTIVATING_PAINT_POWER, "Activating a paint power that's not trying to activate." );
switch( power.m_PaintPowerType )
{
case BOUNCE_POWER:
return ActivateBouncePower( power );
case SPEED_POWER:
return ActivateSpeedPower( power );
case PORTAL_POWER:
return ActivateNoPower( power );
case REFLECT_POWER:
return ActivateNoPower( power );
case NO_POWER:
return ActivateNoPower( power );
default:
AssertMsg( false, "Invalid power or power hasn't been added to PaintPowerUser properly." );
return INACTIVE_PAINT_POWER;
}
}
template< typename BaseEntityType >
PaintPowerState PaintPowerUser<BaseEntityType>::UsePaintPower( PaintPowerInfo_t& power )
{
AssertMsg( power.m_State == ACTIVE_PAINT_POWER, "Using a power that hasn't been activated." );
switch( power.m_PaintPowerType )
{
case BOUNCE_POWER:
return UseBouncePower( power );
case SPEED_POWER:
return UseSpeedPower( power );
case PORTAL_POWER:
return UseNoPower( power );
case REFLECT_POWER:
return UseNoPower( power );
case NO_POWER:
return UseNoPower( power );
default:
AssertMsg( false, "Invalid power or power hasn't been added to PaintPowerUser properly." );
return INACTIVE_PAINT_POWER;
}
}
template< typename BaseEntityType >
PaintPowerState PaintPowerUser<BaseEntityType>::DeactivatePaintPower( PaintPowerInfo_t& power )
{
AssertMsg( power.m_State == DEACTIVATING_PAINT_POWER, "Deactivating a power that's not trying to deactivate." );
switch( power.m_PaintPowerType )
{
case BOUNCE_POWER:
return DeactivateBouncePower( power );
case SPEED_POWER:
return DeactivateSpeedPower( power );
case PORTAL_POWER:
return DeactivateNoPower( power );
case REFLECT_POWER:
return DeactivateNoPower( power );
case NO_POWER:
return DeactivateNoPower( power );
default:
AssertMsg( false, "Invalid power or power hasn't been added to PaintPowerUser properly." );
return INACTIVE_PAINT_POWER;
}
}
template< typename BaseEntityType >
const PaintPowerConstRange PaintPowerUser<BaseEntityType>::GetSurfacePaintPowerInfo( char const* context ) const
{
if( !context )
return GetConstRange( m_SurfacePaintPowerInfo );
const int i = FindContextSurfacePaintPowerInfo( context );
#ifdef PAINT_POWER_USER_DEBUG
if( i == m_ContextSurfacePaintPowerInfo.InvalidIndex() )
Warning( "Trying to get a range that doesn't exist.\n" );
#endif
return i != m_ContextSurfacePaintPowerInfo.InvalidIndex() ? GetConstRange( m_ContextSurfacePaintPowerInfo[i].paintPowerInfo ) : PaintPowerConstRange( (PaintPowerConstIter)0, (PaintPowerConstIter)0 );
}
template< typename BaseEntityType >
bool PaintPowerUser<BaseEntityType>::HasAnySurfacePaintPowerInfo() const
{
bool hasSurfaceInfo = m_SurfacePaintPowerInfo.Count() != 0;
const int count = m_ContextSurfacePaintPowerInfo.Count();
for( int i = 0; i < count && !hasSurfaceInfo; ++i )
{
hasSurfaceInfo = m_ContextSurfacePaintPowerInfo[i].paintPowerInfo.Count() != 0;
}
return hasSurfaceInfo;
}
template< typename BaseEntityType >
void PaintPowerUser<BaseEntityType>::ForceSetPaintPower( const PaintPowerInfo_t& powerInfo )
{
m_PaintPowers[powerInfo.m_PaintPowerType] = powerInfo;
}
template< typename BaseEntityType >
void PaintPowerUser<BaseEntityType>::ForcePaintPowerToState( PaintPowerType type, PaintPowerState newState )
{
// TODO: Implement some error checking for edge cases here.
m_PaintPowers[type].m_State = newState;
}
template< typename BaseEntityType >
PaintPowerState PaintPowerUser<BaseEntityType>::ActivateNoPower( PaintPowerInfo_t& powerInfo )
{
return ACTIVE_PAINT_POWER;
}
template< typename BaseEntityType >
PaintPowerState PaintPowerUser<BaseEntityType>::UseNoPower( PaintPowerInfo_t& powerInfo )
{
return ACTIVE_PAINT_POWER;
}
template< typename BaseEntityType >
PaintPowerState PaintPowerUser<BaseEntityType>::DeactivateNoPower( PaintPowerInfo_t& powerInfo )
{
return INACTIVE_PAINT_POWER;
}
#endif // ifndef PAINT_POWER_USER_H