Merge branch 'master' of https://github.com/ValveSoftware/source-sdk-2013 into mapbase-mp-2025

# Conflicts:
#	src/game/client/c_point_commentary_node.cpp
#	src/game/client/particlemgr.cpp
#	src/game/server/player.cpp
This commit is contained in:
Blixibon 2025-07-29 14:57:00 -05:00
commit ec163919a6
113 changed files with 12312 additions and 246 deletions

View File

@ -18,6 +18,6 @@ WARRANTY OF ANY KIND. VALVE EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS O
INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, TITLE AND FITNESS FOR A PARTICULAR PURPOSE.
LIMITATION OF LIABILITY. VALVE AND ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES WHATSOEVER ) THAT MAY BE INCURRED BY YOU EVEN IF VALVE HAS BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
OR CONSEQUENTIAL DAMAGES WHATSOEVER THAT MAY BE INCURRED BY YOU EVEN IF VALVE HAS BEEN ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF SUCH DAMAGES.

View File

@ -270,7 +270,11 @@ Clone the repository using the following command:
Requirements:
- Source SDK 2013 Multiplayer installed via Steam
- Visual Studio 2022
- Visual Studio 2022 with the following workload and components:
- Desktop development with C++:
- MSVC v143 - VS 2022 C++ x64/x86 build tools (Latest)
- Windows 11 SDK (10.0.22621.0) or Windows 10 SDK (10.0.19041.1)
- Python 3.13 or later
Inside the cloned directory, navigate to `src`, run:
```bat

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1388,10 +1388,10 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe
// Get our scheme and font information
vgui::HScheme scheme = GetScheme();
m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" );
m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault", true );
if ( !m_hFont )
{
m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" );
m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default", true );
}
m_hSmallFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentarySmall" );

View File

@ -267,7 +267,7 @@ void C_SlideshowDisplay::BuildSlideShowImagesList( void )
char szFullFileName[_MAX_PATH];
Q_snprintf( szFullFileName, sizeof( szFullFileName ), "materials/vgui/%s/%s", m_szSlideshowDirectory, szMatFileName );
KeyValues *pMaterialKeys = new KeyValues( "material" );
KeyValuesAD pMaterialKeys( "material" );
bool bLoaded = pMaterialKeys->LoadFromFile( g_pFullFileSystem, szFullFileName, NULL );
if ( bLoaded )

View File

@ -121,7 +121,7 @@ inline ClientThinkHandle_t CClientThinkList::GetInvalidThinkHandle()
inline CClientThinkList::ThinkEntry_t* CClientThinkList::GetThinkEntry( ClientThinkHandle_t hThink )
{
return &m_ThinkEntries[ (unsigned long)hThink ];
return &m_ThinkEntries[ (uintp)hThink ];
}

View File

@ -901,23 +901,26 @@ void ClientModeShared::StartMessageMode( int iMessageModeType )
}
#if defined( TF_CLIENT_DLL )
bool bSuspensionInMatch = GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch();
if ( !cl_enable_text_chat.GetBool() || bSuspensionInMatch )
if ( iMessageModeType == MM_SAY || iMessageModeType == MM_SAY_TEAM )
{
CBaseHudChat *pHUDChat = ( CBaseHudChat * ) GET_HUDELEMENT( CHudChat );
if ( pHUDChat )
bool bSuspensionInMatch = GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch();
if ( !cl_enable_text_chat.GetBool() || bSuspensionInMatch )
{
const char *pszReason = "#TF_Chat_Disabled";
if ( bSuspensionInMatch )
CBaseHudChat *pHUDChat = ( CBaseHudChat * ) GET_HUDELEMENT( CHudChat );
if ( pHUDChat )
{
pszReason = "#TF_Chat_Unavailable";
}
const char *pszReason = "#TF_Chat_Disabled";
if ( bSuspensionInMatch )
{
pszReason = "#TF_Chat_Unavailable";
}
char szLocalized[100];
g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pszReason ), szLocalized, sizeof( szLocalized ) );
pHUDChat->ChatPrintf( 0, CHAT_FILTER_NONE, "%s ", szLocalized );
char szLocalized[100];
g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pszReason ), szLocalized, sizeof( szLocalized ) );
pHUDChat->ChatPrintf( 0, CHAT_FILTER_NONE, "%s ", szLocalized );
}
return;
}
return;
}
#endif // TF_CLIENT_DLL

View File

@ -1672,7 +1672,7 @@ void CHudCloseCaption::CreateFonts( void )
{
vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
m_hFonts[CCFONT_NORMAL] = pScheme->GetFont( "CloseCaption_Normal", true );
m_hFonts[CCFONT_NORMAL] = pScheme->GetFont( "CloseCaption", true );
if ( IsPC() )
{

View File

@ -191,12 +191,12 @@ void CMoveHelperClient::ProcessImpacts( void )
}
// misyl: Debug
if ( vOldLocalVel != vOldAbsVel )
{
Msg( "%d\n", gpGlobals->tickcount );
Msg( "vOldLocalVel: %f %f %f\n", vOldLocalVel.x, vOldLocalVel.y, vOldLocalVel.z );
Msg( "vOldAbsVel: %f %f %f\n", vOldAbsVel.x, vOldAbsVel.y, vOldAbsVel.z );
}
// if ( vOldLocalVel != vOldAbsVel )
// {
// Msg( "%d\n", gpGlobals->tickcount );
// Msg( "vOldLocalVel: %f %f %f\n", vOldLocalVel.x, vOldLocalVel.y, vOldLocalVel.z );
// Msg( "vOldAbsVel: %f %f %f\n", vOldAbsVel.x, vOldAbsVel.y, vOldAbsVel.z );
// }
// Restore the velocity
m_pHost->SetAbsVelocity( vOldAbsVel );
//m_pHost->SetLocalVelocity( vOldLocalVel );

View File

@ -146,7 +146,7 @@ CParticleEffectBinding::CParticleEffectBinding()
m_LastMin = m_Min;
m_LastMax = m_Max;
m_flParticleCullRadius = 0.0f;
m_flParticleCullRadius = -1.f; // dummy value, is overwritten below
SetParticleCullRadius( 0.0f );
m_nActiveParticles = 0;

View File

@ -60,7 +60,7 @@ C_ObjectSentrygun::C_ObjectSentrygun()
m_nShieldLevel = SHIELD_NONE;
m_nOldShieldLevel = SHIELD_NONE;
m_hLaserBeamEffect = NULL;
m_pTempShield = NULL;
m_hShieldModel = NULL;
m_bNearMiss = false;
m_flNextNearMissCheck = 0.f;
@ -312,7 +312,7 @@ void C_ObjectSentrygun::SetDormant( bool bDormant )
if ( IsDormant() && !bDormant )
{
// Make sure our shield is where we are. We may have moved since last seen.
if ( m_pTempShield )
if ( m_hShieldModel )
{
m_bRecreateShield = true;
m_bRecreateLaserBeam = true;
@ -329,13 +329,12 @@ void C_ObjectSentrygun::CreateShield( void )
{
DestroyShield();
model_t *pModel = (model_t *) engine->LoadModel( "models/buildables/sentry_shield.mdl" );
m_pTempShield = tempents->SpawnTempModel( pModel, GetAbsOrigin(), GetAbsAngles(), Vector(0, 0, 0), 1, FTENT_NEVERDIE );
if ( m_pTempShield )
m_hShieldModel = C_SentrygunShield::Create( "models/buildables/sentry_shield.mdl" );
if ( m_hShieldModel )
{
m_pTempShield->ChangeTeam( GetTeamNumber() );
m_pTempShield->m_nSkin = ( GetTeamNumber() == TF_TEAM_RED ) ? 0 : 1;
//m_pTempShield->m_nRenderFX = kRenderFxDistort;
m_hShieldModel->FollowEntity( this, false );
m_hShieldModel->ChangeTeam( GetTeamNumber() );
m_hShieldModel->m_nSkin = ( GetTeamNumber() == TF_TEAM_RED ) ? 0 : 1;
}
m_hShieldEffect = ParticleProp()->Create( "turret_shield", PATTACH_ABSORIGIN_FOLLOW, 0, Vector( 0,0,30) );
@ -356,12 +355,10 @@ void C_ObjectSentrygun::CreateShield( void )
//-----------------------------------------------------------------------------
void C_ObjectSentrygun::DestroyShield( void )
{
if ( m_pTempShield )
if ( m_hShieldModel )
{
m_pTempShield->flags = FTENT_FADEOUT;
m_pTempShield->die = gpGlobals->curtime;
m_pTempShield->fadeSpeed = 1.0f;
m_pTempShield = NULL;
m_hShieldModel->StartFadeOut( 1.0f );
m_hShieldModel = NULL;
}
if ( m_hShieldEffect )
@ -758,4 +755,49 @@ const char* C_ObjectSentrygun::GetStatusName() const
return "#TF_Object_Sentry";
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_SentrygunShield* C_SentrygunShield::Create( const char* pszModelName )
{
C_SentrygunShield* pShield = new C_SentrygunShield();
if ( !pShield )
return NULL;
if ( !pShield->InitializeAsClientEntity( pszModelName, RENDER_GROUP_TRANSLUCENT_ENTITY ) )
{
pShield->Release();
return NULL;
}
pShield->AddEffects( EF_NORECEIVESHADOW | EF_NOSHADOW );
return pShield;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_SentrygunShield::ClientThink()
{
if ( m_flFadeOutEndTime <= gpGlobals->curtime )
{
Release();
return;
}
float flAlpha = RemapVal( gpGlobals->curtime, m_flFadeOutStartTime, m_flFadeOutEndTime, 255.0f, 0.0f );
SetRenderColorA( (byte)flAlpha );
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_SentrygunShield::StartFadeOut( float flDuration )
{
SetRenderMode( kRenderTransTexture );
m_flFadeOutStartTime = gpGlobals->curtime;
m_flFadeOutEndTime = gpGlobals->curtime + flDuration;
SetNextClientThink( gpGlobals->curtime );
}

View File

@ -27,6 +27,25 @@ enum
SHIELD_MAX, // 10% damage taken, no inactive period
};
//-----------------------------------------------------------------------------
// Purpose: Wrangler shield
//-----------------------------------------------------------------------------
class C_SentrygunShield : public C_BaseAnimating
{
DECLARE_CLASS( C_SentrygunShield, C_BaseAnimating );
public:
static C_SentrygunShield* Create( const char* pszModelName );
virtual void ClientThink();
void StartFadeOut( float flDuration );
private:
float m_flFadeOutStartTime;
float m_flFadeOutEndTime;
};
//-----------------------------------------------------------------------------
// Purpose: Sentry object
//-----------------------------------------------------------------------------
@ -124,7 +143,7 @@ private:
bool m_bRecreateLaserBeam;
float m_flNextNearMissCheck;
C_LocalTempEntity *m_pTempShield;
CHandle<C_SentrygunShield> m_hShieldModel;
HPARTICLEFFECT m_hSirenEffect;
HPARTICLEFFECT m_hShieldEffect;

View File

@ -531,6 +531,7 @@ void ClientModeTFNormal::Shutdown()
{
RemoveFilesInPath( "materials/temp" );
RemoveFilesInPath( "download/user_custom" );
RemoveFilesInPath( "sound/temp" );
}
DestroyStatsSummaryPanel();

View File

@ -35,7 +35,7 @@ void CTFAutoRP::ParseDataFile( void )
Assert( !m_pDataFileKV );
// Load & parse the word files
KeyValues *pFileKV = new KeyValues( "AutoRPFile" );
KeyValuesAD pFileKV( "AutoRPFile" );
if ( pFileKV->LoadFromFile( filesystem, "scripts/autorp.txt", "MOD" ) == false )
return;
@ -547,7 +547,7 @@ void CTFAutoRP::ModifySpeech( const char *pszInText, char *pszOutText, int iOutL
{
szStoredWord[0] = toupper( szStoredWord[0] );
}
else if ( pszCurWord[0] >= 'a' && pszCurWord[0] <= 'a' )
else if ( pszCurWord[0] >= 'a' && pszCurWord[0] <= 'z' )
{
szStoredWord[0] = tolower( szStoredWord[0] );
}

View File

@ -777,7 +777,7 @@ void CHudMainMenuOverride::LoadCharacterImageFile( void )
//-----------------------------------------------------------------------------
void CHudMainMenuOverride::LoadMenuEntries( void )
{
KeyValues *datafile = new KeyValues("GameMenu");
KeyValuesAD datafile("GameMenu");
datafile->UsesEscapeSequences( true ); // VGUI uses escape sequences
bool bLoaded = datafile->LoadFromFile( g_pFullFileSystem, "Resource/GameMenu.res", "custom_mod" );
if ( !bLoaded )
@ -2274,7 +2274,7 @@ public:
//V_strcpy_safe( uilanguage, "german" );
KeyValues *pEntriesKV = new KeyValues( "motd_entries");
KeyValuesAD pEntriesKV( "motd_entries");
// Try and load the cache file. If we fail, we'll just create a new one.
if ( !pMMPanel->ReloadedAllMOTDs() )

View File

@ -851,7 +851,14 @@ void CWaveStatusPanel::UpdateEnemyCounts( void )
if ( pPanel->m_pEnemyCountImageBG )
{
pPanel->m_pEnemyCountImageBG->SetBgColor( m_clrNormal );
if ( support[i].iFlags & MVM_CLASS_FLAG_MINIBOSS )
{
pPanel->m_pEnemyCountImageBG->SetBgColor( m_clrMiniBoss );
}
else
{
pPanel->m_pEnemyCountImageBG->SetBgColor( m_clrNormal );
}
}
if ( pPanel->m_pEnemyCountCritBG )

View File

@ -574,6 +574,23 @@ void CTFHudMatchStatus::FireGameEvent( IGameEvent * event )
}
const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( TFGameRules()->GetCurrentMatchGroup() );
// FIX: Refresh versus doors so late-joiners do not see the wrong skin
int nSkin = 0;
int nSubModel = 0;
if (pMatchDesc->BGetRoundDoorParameters(nSkin, nSubModel))
{
// Is VS doors model not initialized yet?
if (m_pMatchStartModelPanel->m_hModel == NULL)
{
m_pMatchStartModelPanel->UpdateModel();
}
m_pMatchStartModelPanel->SetBodyGroup( "logos", nSubModel );
m_pMatchStartModelPanel->UpdateModel();
m_pMatchStartModelPanel->SetSkin( nSkin );
}
bool bForceDoors = false;
if ( bForceDoors || ( pMatchDesc && pMatchDesc->BUsesPostRoundDoors() ) )
{

View File

@ -242,6 +242,7 @@ protected:
virtual void ApplySchemeSettings(vgui::IScheme *scheme);
virtual void Paint( void );
virtual bool ShouldDraw( void );
virtual bool CanAnimate() const OVERRIDE { return false; }
private:
int m_iScopeTexture[4];

View File

@ -385,14 +385,6 @@ void CTFMapInfoMenu::LoadMapPage()
{
m_pMapInfo->SetText( wszMapDescription );
}
else if ( StringHasPrefix( m_szMapName, "vsh_" ) )
{
m_pMapInfo->SetText( "#default_vsh_description" );
}
else if ( StringHasPrefix( m_szMapName, "zi_" ) )
{
m_pMapInfo->SetText( "#default_zi_description" );
}
else
{
// try loading map descriptions from .txt files first
@ -497,7 +489,15 @@ void CTFMapInfoMenu::LoadMapPage()
if( !g_pVGuiLocalize->Find( mapInfoKey ) )
{
if ( TFGameRules() )
if ( StringHasPrefix( m_szMapName, "vsh_" ) )
{
pszDescription = "#default_vsh_description";
}
else if ( StringHasPrefix( m_szMapName, "zi_" ) )
{
pszDescription = "#default_zi_description";
}
else if ( TFGameRules() )
{
if ( TFGameRules()->IsMannVsMachineMode() )
{

View File

@ -17,6 +17,10 @@
static int g_ActiveVoiceMenu = 0;
#if defined( TF_CLIENT_DLL )
extern ConVar tf_voice_command_suspension_mode;
#endif
void OpenVoiceMenu( int index )
{
// do not show the menu if the player is dead or is an observer
@ -28,7 +32,7 @@ void OpenVoiceMenu( int index )
return;
#if defined ( TF_CLIENT_DLL )
if ( GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch() )
if ( GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch() && tf_voice_command_suspension_mode.GetInt() == 1 )
{
CBaseHudChat *pHUDChat = ( CBaseHudChat * ) GET_HUDELEMENT( CHudChat );
if ( pHUDChat )

View File

@ -40,6 +40,7 @@ public:
virtual Vector EyePosition( void );
virtual INextBot *MyNextBotPointer( void ) { return this; }
virtual bool IsNextBot(void) const { return true; }
// Event hooks into NextBot system ---------------------------------------
virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );

View File

@ -1165,6 +1165,9 @@ public:
void TraceBleed( float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType );
virtual bool IsTriggered( CBaseEntity *pActivator ) {return true;}
virtual bool IsNPC( void ) const { return false; }
#ifdef NEXT_BOT
virtual bool IsNextBot(void) const { return false; }
#endif
CAI_BaseNPC *MyNPCPointer( void );
virtual CBaseCombatCharacter *MyCombatCharacterPointer( void ) { return NULL; }
virtual INextBot *MyNextBotPointer( void ) { return NULL; }

View File

@ -110,9 +110,9 @@ ConVar spec_freeze_traveltime( "spec_freeze_traveltime", "0.4", FCVAR_CHEAT | FC
ConVar sv_bonus_challenge( "sv_bonus_challenge", "0", FCVAR_REPLICATED, "Set to values other than 0 to select a bonus map challenge type." );
ConVar sv_chat_bucket_size_tier1( "sv_chat_bucket_size_tier1", "4", FCVAR_NONE, "The maxmimum size of the short term chat msg bucket." );
ConVar sv_chat_bucket_size_tier1( "sv_chat_bucket_size_tier1", "4", FCVAR_NONE, "The maximum size of the short term chat msg bucket." );
ConVar sv_chat_seconds_per_msg_tier1( "sv_chat_seconds_per_msg_tier1", "3", FCVAR_NONE, "The number of seconds to accrue an additional short term chat msg." );
ConVar sv_chat_bucket_size_tier2( "sv_chat_bucket_size_tier2", "30", FCVAR_NONE, "The maxmimum size of the long term chat msg bucket." );
ConVar sv_chat_bucket_size_tier2( "sv_chat_bucket_size_tier2", "30", FCVAR_NONE, "The maximum size of the long term chat msg bucket." );
ConVar sv_chat_seconds_per_msg_tier2( "sv_chat_seconds_per_msg_tier2", "10", FCVAR_NONE, "The number of seconds to accrue an additional long term chat msg." );
static ConVar sv_maxusrcmdprocessticks( "sv_maxusrcmdprocessticks", "24", FCVAR_NOTIFY, "Maximum number of client-issued usrcmd ticks that can be replayed in packet loss conditions, 0 to allow no restrictions" );
@ -8982,13 +8982,6 @@ void CLogicPlayerInfo::GetPlayerInfo( CBasePlayer *pPlayer )
}
#endif
void SendProxy_CropFlagsToPlayerFlagBitsLength( const SendProp* pProp, const void* pStruct, const void* pVarData, DVariant* pOut, int iElement, int objectID )
{
int mask = ( 1 << PLAYER_FLAG_BITS ) - 1;
int data = *( int* )pVarData;
pOut->m_Int = ( data & mask );
}
#ifdef MAPBASE
// Needs to shift bits since network table only sends the player ones
@ -9088,7 +9081,7 @@ void SendProxy_ShiftPlayerSpawnflags( const SendProp *pProp, const void *pStruct
SendPropInt (SENDINFO(m_iBonusProgress), 15 ),
SendPropInt (SENDINFO(m_iBonusChallenge), 4 ),
SendPropFloat (SENDINFO(m_flMaxspeed), 12, SPROP_ROUNDDOWN, 0.0f, 2048.0f ), // CL
SendPropInt (SENDINFO(m_fFlags), PLAYER_FLAG_BITS, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN, SendProxy_CropFlagsToPlayerFlagBitsLength ),
SendPropInt (SENDINFO(m_fFlags), 0, SPROP_UNSIGNED|SPROP_CHANGES_OFTEN ),
SendPropInt (SENDINFO(m_iObserverMode), 3, SPROP_UNSIGNED ),
SendPropEHandle (SENDINFO(m_hObserverTarget) ),
SendPropInt (SENDINFO(m_iFOV), 8, SPROP_UNSIGNED ),

View File

@ -523,7 +523,7 @@ void CSlideshowDisplay::BuildSlideShowImagesList( void )
char szFullFileName[_MAX_PATH];
Q_snprintf( szFullFileName, sizeof( szFullFileName ), "materials/vgui/%s/%s", m_szSlideshowDirectory.Get(), szMatFileName );
KeyValues *pMaterialKeys = new KeyValues( "material" );
KeyValuesAD pMaterialKeys( "material" );
bool bLoaded = pMaterialKeys->LoadFromFile( g_pFullFileSystem, szFullFileName, NULL );
if ( bLoaded )

View File

@ -1156,6 +1156,9 @@ int CTeamControlPointMaster::GetNumPointsOwnedByTeam( int iTeam )
//-----------------------------------------------------------------------------
int CTeamControlPointMaster::CalcNumRoundsRemaining( int iTeam )
{
if ( m_ControlPointRounds.IsEmpty() )
return 0;
// To determine how many rounds remain for a given team if it consistently wins mini-rounds, we have to
// simulate forward each mini-round and track the control point ownership that would result

View File

@ -29,7 +29,8 @@ ActionResult< CTFBot > CTFBotEngineerBuildTeleportEntrance::OnStart( CTFBot *me,
ActionResult< CTFBot > CTFBotEngineerBuildTeleportEntrance::Update( CTFBot *me, float interval )
{
CTeamControlPoint *point = me->GetMyControlPoint();
if ( !point )
CCaptureZone *zone = me->GetFlagCaptureZone();
if ( !point && !zone )
{
// wait until a control point becomes available
return Continue();
@ -64,7 +65,14 @@ ActionResult< CTFBot > CTFBotEngineerBuildTeleportEntrance::Update( CTFBot *me,
if ( !m_path.IsValid() )
{
CTFBotPathCost cost( me, FASTEST_ROUTE );
m_path.Compute( me, point->GetAbsOrigin(), cost );
if ( point )
{
m_path.Compute( me, point->GetAbsOrigin(), cost );
}
else if ( zone )
{
m_path.Compute( me, zone->WorldSpaceCenter(), cost );
}
}
m_path.Update( me );

View File

@ -243,7 +243,7 @@ ActionResult< CTFBot > CTFBotDeliverFlag::Update( CTFBot *me, float interval )
m_flTotalTravelDistance = NavAreaTravelDistance( me->GetLastKnownArea(), TheNavMesh->GetNavArea( zone->WorldSpaceCenter() ), cost );
if ( flOldTravelDistance != -1.0f && m_flTotalTravelDistance - flOldTravelDistance > 2000.0f )
if ( TFGameRules()->IsMannVsMachineMode() && flOldTravelDistance != -1.0f && m_flTotalTravelDistance - flOldTravelDistance > 2000.0f )
{
TFGameRules()->BroadcastSound( 255, "Announcer.MVM_Bomb_Reset" );

View File

@ -70,7 +70,14 @@ ActionResult< CTFBot > CTFBotSpyHide::Update( CTFBot *me, float interval )
if ( m_talkTimer.IsElapsed() )
{
m_talkTimer.Start( RandomFloat( 5.0f, 10.0f ) );
me->EmitSound( "Spy.TeaseVictim" );
if ( TFGameRules()->IsMannVsMachineMode() && me->GetTeamNumber() == TF_TEAM_PVE_INVADERS )
{
me->EmitSound( "Spy.MVM_TeaseVictim" );
}
else
{
me->EmitSound( "Spy.TeaseVictim" );
}
}
if ( m_isAtGoal )

View File

@ -704,9 +704,9 @@ DEFINE_SCRIPTFUNC( IsOnAnyMission, "Return true if this bot has a current missio
DEFINE_SCRIPTFUNC_WRAPPED( SetMissionTarget, "Set this bot's mission target to the given entity" )
DEFINE_SCRIPTFUNC_WRAPPED( GetMissionTarget, "Get this bot's current mission target" )
DEFINE_SCRIPTFUNC( SetBehaviorFlag, "Set the given behavior flag(s) for this bot" )
DEFINE_SCRIPTFUNC( ClearBehaviorFlag, "Clear the given behavior flag(s) for this bot" )
DEFINE_SCRIPTFUNC( IsBehaviorFlagSet, "Return true if the given behavior flag(s) are set for this bot" )
DEFINE_SCRIPTFUNC_WRAPPED( SetBehaviorFlag, "Set the given behavior flag(s) for this bot" )
DEFINE_SCRIPTFUNC_WRAPPED( ClearBehaviorFlag, "Clear the given behavior flag(s) for this bot" )
DEFINE_SCRIPTFUNC_WRAPPED( IsBehaviorFlagSet, "Return true if the given behavior flag(s) are set for this bot" )
DEFINE_SCRIPTFUNC_WRAPPED( SetActionPoint, "Set the given action point for this bot" )
DEFINE_SCRIPTFUNC_WRAPPED( GetActionPoint, "Get the given action point for this bot" )

View File

@ -331,6 +331,9 @@ public:
void SetBehaviorFlag( unsigned int flags );
void ClearBehaviorFlag( unsigned int flags );
bool IsBehaviorFlagSet( unsigned int flags ) const;
void ScriptSetBehaviorFlag( int flags ) { this->SetBehaviorFlag( (unsigned int)flags ); }
void ScriptClearBehaviorFlag( int flags ) { this->ClearBehaviorFlag( (unsigned int)flags ); }
bool ScriptIsBehaviorFlagSet( int flags ) const { return this->IsBehaviorFlagSet( (unsigned int)flags ); }
bool FindSplashTarget( CBaseEntity *target, float maxSplashRadius, Vector *splashTarget ) const;
@ -358,11 +361,11 @@ public:
CBaseEntity *GetMissionTarget( void ) const;
void SetMissionString( CUtlString string );
CUtlString *GetMissionString( void );
void ScriptSetMission( unsigned int mission, bool resetBehaviorSystem = true ) { this->SetMission( (MissionType)mission, resetBehaviorSystem ); }
void ScriptSetPrevMission( unsigned int mission ) { this->SetPrevMission( (MissionType)mission ); }
unsigned int ScriptGetMission( void ) const { return (unsigned int)this->GetMission(); }
unsigned int ScriptGetPrevMission( void ) const { return (unsigned int)this->GetPrevMission(); }
bool ScriptHasMission( unsigned int mission ) const { return this->HasMission( (MissionType)mission ); }
void ScriptSetMission( int mission, bool resetBehaviorSystem = true ) { this->SetMission( (MissionType)mission, resetBehaviorSystem ); }
void ScriptSetPrevMission( int mission ) { this->SetPrevMission( (MissionType)mission ); }
int ScriptGetMission( void ) const { return (int)this->GetMission(); }
int ScriptGetPrevMission( void ) const { return (int)this->GetPrevMission(); }
bool ScriptHasMission( int mission ) const { return this->HasMission( (MissionType)mission ); }
void ScriptSetMissionTarget( HSCRIPT hTarget ) { this->SetMissionTarget( ToEnt( hTarget ) ); }
HSCRIPT ScriptGetMissionTarget( void ) const { return ToHScript( this->GetMissionTarget() ); }

View File

@ -17,6 +17,7 @@
#include "particle_parse.h"
#include "player_vs_environment/tf_population_manager.h"
#include "collisionutils.h"
#include "func_respawnroom.h"
#include "tf_objective_resource.h"
//=============================================================================
@ -209,6 +210,21 @@ void CCurrencyPack::ComeToRest( void )
}
}
}
// Or a func_respawnroom (robots can drop money in their own spawn)
for ( int i = 0; i < IFuncRespawnRoomAutoList::AutoList().Count(); i++ )
{
CFuncRespawnRoom *pRespawnRoom = static_cast<CFuncRespawnRoom *>( IFuncRespawnRoomAutoList::AutoList()[ i ] );
Vector vecMins, vecMaxs;
pRespawnRoom->GetCollideable()->WorldSpaceSurroundingBounds( &vecMins, &vecMaxs );
if ( IsPointInBox( GetCollideable()->GetCollisionOrigin(), vecMins, vecMaxs ) )
{
TFGameRules()->DistributeCurrencyAmount( m_nAmount );
m_bTouched = true;
UTIL_Remove( this );
}
}
}
//-----------------------------------------------------------------------------

View File

@ -126,7 +126,6 @@
#include "tf_revive.h"
#include "tf_logic_halloween_2014.h"
#include "tf_logic_player_destruction.h"
#include "tf_weapon_rocketpack.h"
#include "tf_weapon_slap.h"
#include "func_croc.h"
#include "tf_weapon_bonesaw.h"
@ -278,6 +277,7 @@ extern ConVar sv_vote_allow_spectators;
ConVar sv_vote_late_join_time( "sv_vote_late_join_time", "90", FCVAR_NONE, "Grace period after the match starts before players who join the match receive a vote-creation cooldown" );
ConVar sv_vote_late_join_cooldown( "sv_vote_late_join_cooldown", "300", FCVAR_NONE, "Length of the vote-creation cooldown when joining the server after the grace period has expired" );
extern ConVar tf_voice_command_suspension_mode;
extern ConVar tf_feign_death_duration;
extern ConVar spec_freeze_time;
extern ConVar spec_freeze_traveltime;
@ -997,7 +997,6 @@ CTFPlayer::CTFPlayer()
m_flNextChangeClassTime = 0.0f;
m_flNextChangeTeamTime = 0.0f;
m_bScattergunJump = false;
m_iOldStunFlags = 0;
m_iLastWeaponSlot = 1;
m_iNumberofDominations = 0;
@ -1453,35 +1452,6 @@ void CTFPlayer::TFPlayerThink()
else
{
m_iLeftGroundHealth = -1;
if ( GetFlags() & FL_ONGROUND )
{
// Airborne conditions end on ground contact
m_Shared.RemoveCond( TF_COND_KNOCKED_INTO_AIR );
m_Shared.RemoveCond( TF_COND_AIR_CURRENT );
if ( m_Shared.InCond( TF_COND_ROCKETPACK ) )
{
// Make sure we're still not dealing with launch, where it's possible
// to hit your head and fall to the ground before the second stage.
CTFWeaponBase *pRocketPack = Weapon_OwnsThisID( TF_WEAPON_ROCKETPACK );
if ( pRocketPack )
{
if ( gpGlobals->curtime > ( static_cast< CTFRocketPack* >( pRocketPack )->GetRefireTime() ) )
{
EmitSound( "Weapon_RocketPack.BoostersShutdown" );
EmitSound( "Weapon_RocketPack.Land" );
m_Shared.RemoveCond( TF_COND_ROCKETPACK );
IGameEvent *pEvent = gameeventmanager->CreateEvent( "rocketpack_landed" );
if ( pEvent )
{
pEvent->SetInt( "userid", GetUserID() );
gameeventmanager->FireEvent( pEvent );
}
}
}
}
}
if ( m_iBlastJumpState )
{
@ -2833,6 +2803,7 @@ void CTFPlayer::PrecacheMvM()
PrecacheScriptSound( "MVM.DeployBombGiant" );
PrecacheScriptSound( "Weapon_Upgrade.ExplosiveHeadshot" );
PrecacheScriptSound( "Spy.MVM_Chuckle" );
PrecacheScriptSound( "Spy.MVM_TeaseVictim" );
PrecacheScriptSound( "MVM.Robot_Engineer_Spawn" );
PrecacheScriptSound( "MVM.Robot_Teleporter_Deliver" );
PrecacheScriptSound( "MVM.MoneyPickup" );
@ -3781,7 +3752,6 @@ void CTFPlayer::Spawn()
m_Shared.SetFeignDeathReady( false );
m_bScattergunJump = false;
m_iOldStunFlags = 0;
m_flAccumulatedHealthRegen = 0;
@ -9127,44 +9097,40 @@ int CTFPlayer::OnTakeDamage( const CTakeDamageInfo &inputInfo )
}
}
if ( pTFAttacker && pTFAttacker->IsPlayerClass( TF_CLASS_MEDIC ) )
if ( pTFAttacker && pTFAttacker->IsPlayerClass( TF_CLASS_MEDIC ) && pWeapon && pWeapon->GetWeaponID() == TF_WEAPON_BONESAW )
{
CTFWeaponBase *pAttackerWeapon = pTFAttacker->GetActiveTFWeapon();
if ( pAttackerWeapon && pAttackerWeapon->GetWeaponID() == TF_WEAPON_BONESAW )
CTFBonesaw *pBoneSaw = static_cast< CTFBonesaw* >( pWeapon );
if ( pBoneSaw->GetBonesawType() == BONESAW_UBER_SAVEDONDEATH )
{
CTFBonesaw *pBoneSaw = static_cast< CTFBonesaw* >( pAttackerWeapon );
if ( pBoneSaw->GetBonesawType() == BONESAW_UBER_SAVEDONDEATH )
// Spawn their spleen
CPhysicsProp *pRandomInternalOrgan = dynamic_cast< CPhysicsProp* >( CreateEntityByName( "prop_physics_override" ) );
if ( pRandomInternalOrgan )
{
// Spawn their spleen
CPhysicsProp *pRandomInternalOrgan = dynamic_cast< CPhysicsProp* >( CreateEntityByName( "prop_physics_override" ) );
if ( pRandomInternalOrgan )
{
pRandomInternalOrgan->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
pRandomInternalOrgan->AddFlag( FL_GRENADE );
char buf[512];
Q_snprintf( buf, sizeof( buf ), "%.10f %.10f %.10f", GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z );
pRandomInternalOrgan->KeyValue( "origin", buf );
Q_snprintf( buf, sizeof( buf ), "%.10f %.10f %.10f", GetAbsAngles().x, GetAbsAngles().y, GetAbsAngles().z );
pRandomInternalOrgan->KeyValue( "angles", buf );
pRandomInternalOrgan->KeyValue( "model", "models/player/gibs/random_organ.mdl" );
pRandomInternalOrgan->KeyValue( "fademindist", "-1" );
pRandomInternalOrgan->KeyValue( "fademaxdist", "0" );
pRandomInternalOrgan->KeyValue( "fadescale", "1" );
pRandomInternalOrgan->KeyValue( "inertiaScale", "1.0" );
pRandomInternalOrgan->KeyValue( "physdamagescale", "0.1" );
DispatchSpawn( pRandomInternalOrgan );
pRandomInternalOrgan->m_takedamage = DAMAGE_YES; // Take damage, otherwise this can block trains
pRandomInternalOrgan->SetHealth( 100 );
pRandomInternalOrgan->Activate();
pRandomInternalOrgan->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
pRandomInternalOrgan->AddFlag( FL_GRENADE );
char buf[512];
Q_snprintf( buf, sizeof( buf ), "%.10f %.10f %.10f", GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z );
pRandomInternalOrgan->KeyValue( "origin", buf );
Q_snprintf( buf, sizeof( buf ), "%.10f %.10f %.10f", GetAbsAngles().x, GetAbsAngles().y, GetAbsAngles().z );
pRandomInternalOrgan->KeyValue( "angles", buf );
pRandomInternalOrgan->KeyValue( "model", "models/player/gibs/random_organ.mdl" );
pRandomInternalOrgan->KeyValue( "fademindist", "-1" );
pRandomInternalOrgan->KeyValue( "fademaxdist", "0" );
pRandomInternalOrgan->KeyValue( "fadescale", "1" );
pRandomInternalOrgan->KeyValue( "inertiaScale", "1.0" );
pRandomInternalOrgan->KeyValue( "physdamagescale", "0.1" );
DispatchSpawn( pRandomInternalOrgan );
pRandomInternalOrgan->m_takedamage = DAMAGE_YES; // Take damage, otherwise this can block trains
pRandomInternalOrgan->SetHealth( 100 );
pRandomInternalOrgan->Activate();
Vector vecImpulse = RandomVector( -1.f, 1.f );
vecImpulse.z = 1.f;
VectorNormalize( vecImpulse );
Vector vecVelocity = vecImpulse * 250.0;
pRandomInternalOrgan->ApplyAbsVelocityImpulse( vecVelocity );
Vector vecImpulse = RandomVector( -1.f, 1.f );
vecImpulse.z = 1.f;
VectorNormalize( vecImpulse );
Vector vecVelocity = vecImpulse * 250.0;
pRandomInternalOrgan->ApplyAbsVelocityImpulse( vecVelocity );
pRandomInternalOrgan->ThinkSet( &CBaseEntity::SUB_Remove, gpGlobals->curtime + 5.f, "DieContext" );
}
pRandomInternalOrgan->ThinkSet( &CBaseEntity::SUB_Remove, gpGlobals->curtime + 5.f, "DieContext" );
}
}
}
@ -20032,7 +19998,20 @@ bool CTFPlayer::ShouldShowVoiceSubtitleToEnemy( void )
//-----------------------------------------------------------------------------
bool CTFPlayer::CanSpeakVoiceCommand( void )
{
return ( gpGlobals->curtime > m_flNextVoiceCommandTime );
if ( tf_voice_command_suspension_mode.GetInt() == 1 )
return false;
if ( gpGlobals->curtime <= m_flNextVoiceCommandTime )
return false;
// misyl: New F2P voice command rate-limiting path.
if ( BHaveChatSuspensionInCurrentMatch() && tf_voice_command_suspension_mode.GetInt() == 2 )
{
if ( !m_RateLimitedVoiceCommandTokenBucket.BTakeToken( gpGlobals->curtime ) )
return false;
}
return true;
}
//-----------------------------------------------------------------------------

View File

@ -66,6 +66,46 @@ enum EAmmoSource
kAmmoSource_ResourceMeter, // it regenerated after a cooldown
};
extern ConVar tf_voice_command_suspension_rate_limit_bucket_count;
extern ConVar tf_voice_command_suspension_rate_limit_bucket_refill_rate;
class CVoiceCommandBucketSizer
{
public:
int GetBucketSize() const { return tf_voice_command_suspension_rate_limit_bucket_count.GetInt(); }
float GetBucketRefillRate() const { return tf_voice_command_suspension_rate_limit_bucket_refill_rate.GetFloat(); }
};
template <typename TBucketSizer>
class CRateLimitingTokenBucket : public TBucketSizer
{
public:
CRateLimitingTokenBucket()
: m_nBucket( this->GetBucketSize() )
{
}
bool BTakeToken( float flNow )
{
// misyl: This token bucket doesn't go negative, so you don't ever dig yourself into a hole by spamming.
// You might want that if you use this class, feel free to add something to the BucketSizer.
int nNewBucket = MIN( m_nBucket + ( flNow - m_flLastTokenTaken ) / this->GetBucketRefillRate(), this->GetBucketSize() ) - 1;
if ( nNewBucket <= 0 )
{
return false;
}
m_nBucket = nNewBucket;
m_flLastTokenTaken = flNow;
return true;
}
private:
float m_flLastTokenTaken = 0.0f;
int m_nBucket = 0;
};
//=============================================================================
//
// TF Player
@ -483,6 +523,8 @@ public:
float m_flNextVoiceCommandTime;
int m_iVoiceSpamCounter;
CRateLimitingTokenBucket<CVoiceCommandBucketSizer> m_RateLimitedVoiceCommandTokenBucket;
float m_flNextSpeakWeaponFire;
virtual int CalculateTeamBalanceScore( void );
@ -938,7 +980,6 @@ public:
bool m_bSuicideExplode;
bool m_bScattergunJump;
int m_iOldStunFlags;
bool m_bFlipViewModels;

View File

@ -801,7 +801,7 @@ void CAchievementMgr::LoadGlobalState()
// HPE_END
//=============================================================================
KeyValues *pKV = new KeyValues("GameState" );
KeyValuesAD pKV("GameState" );
if ( pKV->LoadFromFile( filesystem, szFilename, "MOD" ) )
{
KeyValues *pNode = pKV->GetFirstSubKey();

View File

@ -3143,7 +3143,7 @@ void UTIL_LoadActivityRemapFile( const char *filename, const char *section, CUtl
return;
}
KeyValues *pkvFile = new KeyValues( section );
KeyValuesAD pkvFile( section );
if ( pkvFile->LoadFromFile( filesystem, filename, NULL ) )
{

View File

@ -70,8 +70,6 @@ BEGIN_DATADESC( CBaseGrenade )
END_DATADESC()
void SendProxy_CropFlagsToPlayerFlagBitsLength( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID);
#endif
#ifdef MAPBASE_VSCRIPT
@ -108,7 +106,7 @@ BEGIN_NETWORK_TABLE( CBaseGrenade, DT_BaseGrenade )
SendPropVector( SENDINFO( m_vecVelocity ), 0, SPROP_NOSCALE ),
// HACK: Use same flag bits as player for now
SendPropInt ( SENDINFO(m_fFlags), PLAYER_FLAG_BITS, SPROP_UNSIGNED, SendProxy_CropFlagsToPlayerFlagBitsLength ),
SendPropInt ( SENDINFO(m_fFlags), 0, SPROP_UNSIGNED ),
#else
RecvPropFloat( RECVINFO( m_flDamage ) ),
RecvPropFloat( RECVINFO( m_DmgRadius ) ),

View File

@ -177,10 +177,14 @@ void CEconItemSystem::ReloadWhitelist( void )
// If we didn't find a file, we're done.
if ( !bFoundWhitelist )
{
pWhitelistKV->deleteThis();
return;
}
// Otherwise, go through the KVs and turn on the matching items.
Msg("Parsing item whitelist (default: %s)\n", bDefault ? "allowed" : "disallowed" );
KeyValues* ownerWhitelistKV = pWhitelistKV;
pWhitelistKV = pWhitelistKV->GetFirstSubKey();
while ( pWhitelistKV )
{
@ -204,6 +208,8 @@ void CEconItemSystem::ReloadWhitelist( void )
pWhitelistKV = pWhitelistKV->GetNextKey();
}
Msg("Finished.\n");
ownerWhitelistKV->deleteThis();
}
#ifdef GAME_DLL

View File

@ -11,6 +11,7 @@
#ifdef CLIENT_DLL
#include "c_hl2mp_player.h"
#include <prediction.h>
#else
#include "hl2mp_player.h"
#endif
@ -146,16 +147,18 @@ void CWeapon357::PrimaryAttack( void )
// Fire the bullets, and force the first shot to be perfectly accuracy
pPlayer->FireBullets( info );
#ifdef CLIENT_DLL
//Disorient the player
QAngle angles = pPlayer->GetLocalAngles();
angles.x += random->RandomInt( -1, 1 );
angles.y += random->RandomInt( -1, 1 );
angles.z = 0;
#ifndef CLIENT_DLL
pPlayer->SnapEyeAngles( angles );
#endif
if ( prediction->IsFirstTimePredicted() )
{
QAngle angles;
engine->GetViewAngles( angles );
angles.x += random->RandomInt( -1, 1 );
angles.y += random->RandomInt( -1, 1 );
angles.z += 0.0f;
engine->SetViewAngles( angles );
}
#endif // CLIENT_DLL
pPlayer->ViewPunch( QAngle( -8, random->RandomFloat( -2, 2 ), 0 ) );

View File

@ -186,7 +186,7 @@ void ParseParticleEffectsMap( const char *pMapName, bool bLoadSheets )
V_snprintf( szMapManifestFilename, sizeof( szMapManifestFilename ), "maps/%s_particles.txt", pMapName );
}
KeyValues *manifest = new KeyValues( szMapManifestFilename );
KeyValuesAD manifest( szMapManifestFilename );
// In order:
// - particles.txt within the map BSP

View File

@ -325,6 +325,7 @@ void CSave::Log( const char *pName, fieldtype_t fieldType, void *value, int coun
char chValue = pValue[iCount];
Q_snprintf( szTempBuf, sizeof( szTempBuf ), "%c", chValue );
Q_strncat( szBuf, szTempBuf, sizeof( szTempBuf ), COPY_ALL_CHARACTERS );
break;
}
case FIELD_COLOR32:
{
@ -332,6 +333,7 @@ void CSave::Log( const char *pName, fieldtype_t fieldType, void *value, int coun
byte *pColor = &pValue[iCount*4];
Q_snprintf( szTempBuf, sizeof( szTempBuf ), "(%d %d %d %d)", ( int )pColor[0], ( int )pColor[1], ( int )pColor[2], ( int )pColor[3] );
Q_strncat( szBuf, szTempBuf, sizeof( szTempBuf ), COPY_ALL_CHARACTERS );
break;
}
case FIELD_EMBEDDED:
case FIELD_CUSTOM:

View File

@ -53,7 +53,7 @@ ConVar tf_max_charge_speed( "tf_max_charge_speed", "750", FCVAR_NOTIFY | FCVAR_R
ConVar tf_parachute_gravity( "tf_parachute_gravity", "0.2f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Gravity while parachute is deployed" );
ConVar tf_parachute_maxspeed_xy( "tf_parachute_maxspeed_xy", "300.0f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Max XY Speed while Parachute is deployed" );
ConVar tf_parachute_maxspeed_z( "tf_parachute_maxspeed_z", "-100.0f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Max Z Speed while Parachute is deployed" );
ConVar tf_parachute_maxspeed_onfire_z( "tf_parachute_maxspeed_onfire_z", "10.0f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Max Z Speed when on Fire and Parachute is deployed" );
ConVar tf_parachute_maxspeed_onfire_z( "tf_parachute_maxspeed_onfire_z", "-100.0f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Max Z Speed when on Fire and Parachute is deployed" );
ConVar tf_parachute_aircontrol( "tf_parachute_aircontrol", "2.5f", FCVAR_DEVELOPMENTONLY | FCVAR_REPLICATED, "Multiplier for how much air control players have when Parachute is deployed" );
ConVar tf_parachute_deploy_toggle_allowed( "tf_parachute_deploy_toggle_allowed", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY );
@ -1116,12 +1116,6 @@ void CTFGameMovement::PreventBunnyJumping()
//-----------------------------------------------------------------------------
void CTFGameMovement::ToggleParachute()
{
if ( ( m_pTFPlayer->GetFlags() & FL_ONGROUND ) )
{
m_pTFPlayer->m_Shared.RemoveCond( TF_COND_PARACHUTE_DEPLOYED );
return;
}
if ( mv->m_nOldButtons & IN_JUMP )
return;
@ -1148,9 +1142,10 @@ void CTFGameMovement::ToggleParachute()
}
else
{
bool bOnGround = ( m_pTFPlayer->GetFlags() & FL_ONGROUND );
int iParachuteDisabled = 0;
CALL_ATTRIB_HOOK_INT_ON_OTHER( m_pTFPlayer, iParachuteDisabled, parachute_disabled );
if ( !iParachuteDisabled && ( tf_parachute_deploy_toggle_allowed.GetBool() || !m_pTFPlayer->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) ) )
if ( !bOnGround && !iParachuteDisabled && ( tf_parachute_deploy_toggle_allowed.GetBool() || !m_pTFPlayer->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) ) )
{
m_pTFPlayer->m_Shared.AddCond( TF_COND_PARACHUTE_ACTIVE );
m_pTFPlayer->m_Shared.AddCond( TF_COND_PARACHUTE_DEPLOYED );
@ -1382,7 +1377,7 @@ int CTFGameMovement::CheckStuck( void )
m_pTFPlayer->GetTeam()->GetName(),
m_pTFPlayer->GetAbsOrigin().x, m_pTFPlayer->GetAbsOrigin().y, m_pTFPlayer->GetAbsOrigin().z );
m_pTFPlayer->TakeDamage( CTakeDamageInfo( m_pTFPlayer, m_pTFPlayer, vec3_origin, m_pTFPlayer->WorldSpaceCenter(), 999999.9f, DMG_CRUSH ) );
m_pTFPlayer->CommitSuicide( false, true );
}
else
{
@ -2630,8 +2625,8 @@ void CTFGameMovement::FullWalkMove()
{
if ( m_pTFPlayer->m_Shared.InCond( TF_COND_PARACHUTE_ACTIVE ) && mv->m_vecVelocity[2] < 0 )
{
mv->m_vecVelocity[2] = Max( mv->m_vecVelocity[2], tf_parachute_maxspeed_z.GetFloat() );
mv->m_vecVelocity[2] = Max( mv->m_vecVelocity[2], m_pTFPlayer->m_Shared.InCond( TF_COND_BURNING ) ? tf_parachute_maxspeed_onfire_z.GetFloat() : tf_parachute_maxspeed_z.GetFloat() );
float flDrag = tf_parachute_maxspeed_xy.GetFloat();
// Instead of clamping, we'll dampen
float flSpeedX = abs( mv->m_vecVelocity[0] );
@ -2957,9 +2952,9 @@ void CTFGameMovement::SetGroundEntity( trace_t *pm )
{
m_pTFPlayer->SpeakConceptIfAllowed( MP_CONCEPT_DOUBLE_JUMP, "started_jumping:0" );
}
m_pTFPlayer->m_Shared.SetWeaponKnockbackID( -1 );
m_pTFPlayer->m_bScattergunJump = false;
#endif // GAME_DLL
m_pTFPlayer->m_Shared.SetWeaponKnockbackID( -1 );
m_pTFPlayer->m_Shared.m_bScattergunJump = false;
m_pTFPlayer->m_Shared.SetAirDash( 0 );
m_pTFPlayer->m_Shared.SetAirDucked( 0 );

View File

@ -1107,7 +1107,13 @@ ConVar tf_competitive_required_late_join_confirm_timeout( "tf_competitive_requir
ConVar tf_gamemode_community ( "tf_gamemode_community", "0", FCVAR_REPLICATED | FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY );
ConVar tf_voice_command_suspension_mode( "tf_voice_command_suspension_mode", "2", FCVAR_REPLICATED, "0 = None | 1 = No Voice Commands | 2 = Rate Limited" );
#ifdef GAME_DLL
ConVar tf_voice_command_suspension_rate_limit_bucket_count( "tf_voice_command_suspension_rate_limit_bucket_count", "5" ); // Bucket size of 5.
ConVar tf_voice_command_suspension_rate_limit_bucket_refill_rate( "tf_voice_command_suspension_rate_limit_bucket_refill_rate", "6" ); // 6s
void cc_powerup_mode( IConVar *pConVar, const char *pOldString, float flOldValue )
{
ConVarRef var( pConVar );
@ -10129,7 +10135,12 @@ VoiceCommandMenuItem_t *CTFGameRules::VoiceCommand( CBaseMultiplayerPlayer *pPla
if ( pTFPlayer )
{
if ( pTFPlayer->BHaveChatSuspensionInCurrentMatch() )
return NULL;
{
if ( tf_voice_command_suspension_mode.GetInt() == 1 )
{
return NULL;
}
}
if ( pTFPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
{
@ -16969,7 +16980,7 @@ int CTFGameRules::CalcPlayerScore( RoundStats_t *pRoundStats, CTFPlayer *pPlayer
( pRoundStats->m_iStat[TFSTAT_TELEPORTS] / TF_SCORE_TELEPORTS_PER_POINT ) +
( pRoundStats->m_iStat[TFSTAT_INVULNS] / TF_SCORE_INVULN ) +
( pRoundStats->m_iStat[TFSTAT_REVENGE] / TF_SCORE_REVENGE ) +
( pRoundStats->m_iStat[TFSTAT_BONUS_POINTS] / TF_SCORE_BONUS_POINT_DIVISOR );
( pRoundStats->m_iStat[TFSTAT_BONUS_POINTS] / TF_SCORE_BONUS_POINT_DIVISOR ) +
( pRoundStats->m_iStat[TFSTAT_CURRENCY_COLLECTED] / TF_SCORE_CURRENCY_COLLECTED );
if ( pPlayer )

View File

@ -279,7 +279,7 @@ void CTFPowerupBottle::ReapplyProvision( void )
// Refill weapon clips
for ( int i = 0; i < MAX_WEAPONS; i++ )
{
CBaseCombatWeapon *pWeapon = pTFPlayer->GetWeapon(i);
CTFWeaponBase *pWeapon = dynamic_cast<CTFWeaponBase *>( pTFPlayer->GetWeapon( i ) );
if ( !pWeapon )
continue;
@ -287,7 +287,8 @@ void CTFPowerupBottle::ReapplyProvision( void )
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
{
if ( ( pWeapon->UsesPrimaryAmmo() && !pWeapon->HasPrimaryAmmo() ) ||
( pWeapon->UsesSecondaryAmmo() && !pWeapon->HasSecondaryAmmo() ) )
( pWeapon->UsesSecondaryAmmo() && !pWeapon->HasSecondaryAmmo() ) ||
( pWeapon->IsEnergyWeapon() && !pWeapon->Energy_HasEnergy() ) )
{
pTFPlayer->AwardAchievement( ACHIEVEMENT_TF_MVM_USE_AMMO_BOTTLE );
}
@ -297,7 +298,7 @@ void CTFPowerupBottle::ReapplyProvision( void )
if ( iShareBottle && pHealTarget )
{
CBaseCombatWeapon *pPatientWeapon = pHealTarget->GetWeapon(i);
CTFWeaponBase *pPatientWeapon = dynamic_cast<CTFWeaponBase *>( pHealTarget->GetWeapon( i ) );
if ( !pPatientWeapon )
continue;

View File

@ -31,6 +31,7 @@
#include "tf_mapinfo.h"
#include "tf_dropped_weapon.h"
#include "tf_weapon_passtime_gun.h"
#include "tf_weapon_rocketpack.h"
#include <functional>
// Client specific.
@ -471,7 +472,10 @@ BEGIN_PREDICTION_DATA_NO_BASE( CTFPlayerShared )
DEFINE_PRED_FIELD( m_bHasPasstimeBall, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_bIsTargetedForPasstimePass, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), // does this belong here?
DEFINE_PRED_FIELD( m_askForBallTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_flHolsterAnimTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_ARRAY( m_flItemChargeMeter, FIELD_FLOAT, LAST_LOADOUT_SLOT_WITH_CHARGE_METER, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_iStunIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_bScattergunJump, FIELD_BOOLEAN, 0 ),
END_PREDICTION_DATA()
// Server specific.
@ -784,6 +788,8 @@ CTFPlayerShared::CTFPlayerShared()
m_flPrevInvisibility = 0.f;
m_flTmpDamageBonusAmount = 1.0f;
m_bScattergunJump = false;
m_bFeignDeathReady = false;
m_fCloakConsumeRate = tf_spy_cloak_consume_rate.GetFloat();
@ -1005,7 +1011,6 @@ void CTFPlayerShared::Spawn( void )
SetRevengeCrits( 0 );
m_PlayerStuns.RemoveAll();
m_iStunIndex = -1;
m_iPasstimeThrowAnimState = PASSTIME_THROW_ANIM_NONE;
m_bHasPasstimeBall = false;
@ -1014,6 +1019,7 @@ void CTFPlayerShared::Spawn( void )
#else
m_bSyncingConditions = false;
#endif
m_iStunIndex = -1;
m_bKingRuneBuffActive = false;
// Reset our assist here incase something happens before we get killed
@ -3090,9 +3096,46 @@ void CTFPlayerShared::ConditionThink( void )
VehicleThink();
if ( m_pOuter->GetFlags() & FL_ONGROUND && InCond( TF_COND_PARACHUTE_ACTIVE ) )
if ( m_pOuter->GetFlags() & FL_ONGROUND )
{
// Airborne conditions end on ground contact
RemoveCond( TF_COND_KNOCKED_INTO_AIR );
RemoveCond( TF_COND_AIR_CURRENT );
RemoveCond( TF_COND_PARACHUTE_ACTIVE );
RemoveCond( TF_COND_PARACHUTE_DEPLOYED );
if ( InCond( TF_COND_ROCKETPACK ) )
{
// Make sure we're still not dealing with launch, where it's possible
// to hit your head and fall to the ground before the second stage.
CTFWeaponBase *pRocketPack = m_pOuter->Weapon_OwnsThisID( TF_WEAPON_ROCKETPACK );
if ( pRocketPack )
{
if ( gpGlobals->curtime > ( static_cast< CTFRocketPack* >( pRocketPack )->GetRefireTime() ) )
{
#ifdef CLIENT_DLL
if ( prediction->IsFirstTimePredicted() )
#endif
{
CPASAttenuationFilter filter( m_pOuter );
filter.UsePredictionRules();
m_pOuter->EmitSound( filter, m_pOuter->entindex(), "Weapon_RocketPack.BoostersShutdown" );
m_pOuter->EmitSound( filter, m_pOuter->entindex(), "Weapon_RocketPack.Land" );
}
RemoveCond( TF_COND_ROCKETPACK );
#ifdef GAME_DLL
IGameEvent *pEvent = gameeventmanager->CreateEvent( "rocketpack_landed" );
if ( pEvent )
{
pEvent->SetInt( "userid", m_pOuter->GetUserID() );
gameeventmanager->FireEvent( pEvent );
}
#endif
}
}
}
}
// See if we should be pulsing our radius heal
@ -7301,6 +7344,8 @@ void CTFPlayerShared::OnRemoveStunned( void )
m_iStunFlags = 0;
m_hStunner = NULL;
m_iStunIndex = -1;
#ifdef CLIENT_DLL
if ( m_pOuter->m_pStunnedEffect )
{
@ -7310,7 +7355,6 @@ void CTFPlayerShared::OnRemoveStunned( void )
m_pOuter->m_pStunnedEffect = NULL;
}
#else
m_iStunIndex = -1;
m_PlayerStuns.RemoveAll();
#endif
@ -9624,15 +9668,16 @@ bool CTFPlayerShared::AddToSpyCloakMeter( float val, bool bForce )
#endif
#ifdef GAME_DLL
//-----------------------------------------------------------------------------
// Purpose: Stun & Snare Application
//-----------------------------------------------------------------------------
void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iStunFlags, CTFPlayer* pAttacker )
{
#ifdef GAME_DLL
// Insanity prevention
if ( ( m_PlayerStuns.Count() + 1 ) >= 250 )
return;
#endif
if ( InCond( TF_COND_PHASE ) || InCond( TF_COND_PASSTIME_INTERCEPTION ) )
return;
@ -9643,15 +9688,19 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt
if ( InCond( TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED ) && !InCond( TF_COND_MVM_BOT_STUN_RADIOWAVE ) )
return;
#ifdef GAME_DLL
if ( pAttacker && TFGameRules() && TFGameRules()->IsTruceActive() && pAttacker->IsTruceValidForEnt() )
{
if ( ( pAttacker->GetTeamNumber() == TF_TEAM_RED ) || ( pAttacker->GetTeamNumber() == TF_TEAM_BLUE ) )
return;
}
#endif
float flRemapAmount = RemapValClamped( flReductionAmount, 0.0, 1.0, 0, 255 );
#ifdef GAME_DLL
int iOldStunFlags = GetStunFlags();
#endif
// Already stunned
bool bStomp = false;
@ -9674,10 +9723,13 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt
}
else if ( GetActiveStunInfo() )
{
#ifdef GAME_DLL
// Something yanked our TF_COND_STUNNED in an unexpected way
if ( !HushAsserts() )
Assert( !"Something yanked out TF_COND_STUNNED." );
m_PlayerStuns.RemoveAll();
#endif
m_iStunIndex = -1;
return;
}
@ -9699,7 +9751,16 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt
// This can happen when stuns use TF_STUN_CONTROLS or TF_STUN_LOSER_STATE.
float flOldStun = GetActiveStunInfo() ? GetActiveStunInfo()->flStunAmount : 0.f;
#ifdef GAME_DLL
m_iStunIndex = m_PlayerStuns.AddToTail( stunEvent );
#else
m_iStunIndex = 0;
if ( prediction->IsFirstTimePredicted() )
{
m_ActiveStunInfo = stunEvent;
}
#endif
if ( flOldStun > flRemapAmount )
{
@ -9709,10 +9770,18 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt
else
{
// Done for now
#ifdef GAME_DLL
m_PlayerStuns.AddToTail( stunEvent );
#else
if ( prediction->IsFirstTimePredicted() )
{
m_ActiveStunInfo = stunEvent;
}
#endif
return;
}
#ifdef GAME_DLL
// Add in extra time when TF_STUN_CONTROLS
if ( GetActiveStunInfo()->iStunFlags & TF_STUN_CONTROLS )
{
@ -9766,10 +9835,10 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt
m_pOuter->ClearExpression();
m_pOuter->ClearWeaponFireScene();
}
#endif
AddCond( TF_COND_STUNNED, -1.f, pAttacker );
}
#endif // GAME_DLL
//-----------------------------------------------------------------------------
// Purpose: Returns the intensity of the current stun effect, if we have the type of stun indicated.

View File

@ -560,9 +560,7 @@ public:
// Stuns
stun_struct_t *GetActiveStunInfo( void ) const;
#ifdef GAME_DLL
void StunPlayer( float flTime, float flReductionAmount, int iStunFlags = TF_STUN_MOVEMENT, CTFPlayer* pAttacker = NULL );
#endif // GAME_DLL
float GetAmountStunned( int iStunFlags );
bool IsLoserStateStunned( void ) const;
bool IsControlStunned( void );
@ -1218,6 +1216,8 @@ private:
#endif
public:
bool m_bScattergunJump;
float m_flStunFade;
float m_flStunEnd;
float m_flStunMid;

View File

@ -1144,7 +1144,7 @@ protected:
int nNumJumps = pNonConstPlayer->GetGroundEntity() == NULL ? 1 : 0;
nNumJumps += pPlayer->m_Shared.GetAirDash();
nNumJumps += pPlayer->m_bScattergunJump;
nNumJumps += pPlayer->m_Shared.m_bScattergunJump;
if ( m_eJumpingState == JUMPING_STATE_IS_NOT_JUMPING )
{
@ -3027,7 +3027,7 @@ bool CTFJumpStateQuestModifier::BPassesModifier( const CTFPlayer *pOwner, Invali
#else
int nNumJumps = const_cast< CTFPlayer* >( pOwner )->GetGroundEntity() == NULL ? 1 : 0;
nNumJumps += pOwner->m_Shared.GetAirDash();
nNumJumps += pOwner->m_bScattergunJump;
nNumJumps += pOwner->m_Shared.m_bScattergunJump;
// If we want them on the ground, make sure they're on the ground
if ( m_nJumpCount == 0 )

View File

@ -2110,7 +2110,7 @@ bool CTFFlameThrower::EffectMeterShouldFlash( void )
//-----------------------------------------------------------------------------
Vector CTFFlameThrower::GetMuzzlePosHelper( bool bVisualPos )
{
Vector vecMuzzlePos;
Vector vecMuzzlePos = vec3_origin;
CTFPlayer *pOwner = GetTFPlayerOwner();
if ( pOwner )
{

View File

@ -13,6 +13,7 @@
#ifdef CLIENT_DLL
#include "c_tf_player.h"
#include "c_rope.h"
#include "prediction.h"
// Server specific.
#else
#include "tf_player.h"
@ -47,7 +48,10 @@ END_NETWORK_TABLE()
#ifdef CLIENT_DLL
BEGIN_PREDICTION_DATA( CTFRocketPack )
DEFINE_PRED_FIELD( m_flInitLaunchTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_flLaunchTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_flToggleEndTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_flRefireTime, FIELD_FLOAT, 0 ),
DEFINE_PRED_FIELD( m_bLaunchedFromGround, FIELD_BOOLEAN, 0 ),
END_PREDICTION_DATA()
#endif // CLIENT_DLL
@ -211,10 +215,13 @@ bool CTFRocketPack::InitiateLaunch( void )
CTFPlayer *pOwner = GetTFPlayerOwner();
if ( !pOwner->m_Shared.IsRocketPackReady() )
{
#ifdef GAME_DLL
CPVSFilter filter( WorldSpaceCenter() );
pOwner->EmitSound( filter, entindex(), "Weapon_RocketPack.BoostersNotReady" );
#endif // GAME_DLL
// note: this is never reached
#ifdef CLIENT_DLL
if ( prediction->IsFirstTimePredicted() )
{
pOwner->EmitSound( "Weapon_RocketPack.BoostersNotReady" );
}
#endif
return false;
}
@ -224,16 +231,18 @@ bool CTFRocketPack::InitiateLaunch( void )
return false;
}
#ifdef GAME_DLL
if ( pOwner->m_Shared.IsLoser() )
#ifdef CLIENT_DLL
if ( prediction->IsFirstTimePredicted() )
#endif
{
pOwner->EmitSound( "Weapon_RocketPack.BoostersNotReady" );
CPASAttenuationFilter filter( pOwner );
filter.UsePredictionRules();
pOwner->EmitSound(
filter,
entindex(),
pOwner->m_Shared.IsLoser() ? "Weapon_RocketPack.BoostersNotReady" : "Weapon_RocketPack.BoostersCharge"
);
}
else
{
pOwner->EmitSound( "Weapon_RocketPack.BoostersCharge" );
}
#endif // GAME_DLL
m_flInitLaunchTime = gpGlobals->curtime;
@ -369,7 +378,6 @@ bool CTFRocketPack::ShouldDraw()
#endif // CLIENT_DLL
#ifdef GAME_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
@ -384,7 +392,7 @@ Vector CTFRocketPack::CalcRocketForceFromPlayer( CTFPlayer *pPlayer )
const float flVertPushScale = ( bOnGround ) ? 0.7f : 0.25f; // Less vertical force while airborne
Vector vecForward, vecRight;
QAngle angAim = ( bOnGround ) ? pPlayer->GetAbsAngles() : pPlayer->EyeAngles();
QAngle angAim = pPlayer->EyeAngles();
AngleVectors( angAim, &vecForward, &vecRight, NULL );
bool bNone = !( pPlayer->m_nButtons & IN_FORWARD ) &&
!( pPlayer->m_nButtons & IN_BACK ) /* &&
@ -468,7 +476,6 @@ void CTFRocketPack::RocketLaunchPlayer( CTFPlayer *pPlayer, const Vector& vecFor
pPlayer->ApplyAbsVelocityImpulse( vecForce );
}
#endif // GAME_DLL
//-----------------------------------------------------------------------------
// Purpose:
@ -482,7 +489,6 @@ bool CTFRocketPack::PreLaunch( void )
pOwner->DoAnimationEvent( PLAYERANIMEVENT_CUSTOM, ACT_MP_ATTACK_STAND_PRIMARYFIRE );
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
#ifdef GAME_DLL
// Negate any fall
Vector vecVel = pOwner->GetAbsVelocity();
if ( vecVel.z < 0.f )
@ -496,14 +502,15 @@ bool CTFRocketPack::PreLaunch( void )
pOwner->ApplyAbsVelocityImpulse( vForward );
pOwner->m_Shared.AddCond( TF_COND_PARACHUTE_ACTIVE );
#ifdef GAME_DLL
const Vector &vecOrigin = pOwner->GetAbsOrigin();
CPVSFilter filter( vecOrigin );
TE_TFParticleEffect( filter, 0.f, "heavy_ring_of_fire", vecOrigin, vec3_angle );
DispatchParticleEffect( "rocketjump_smoke", PATTACH_POINT_FOLLOW, pOwner, "foot_L" );
DispatchParticleEffect( "rocketjump_smoke", PATTACH_POINT_FOLLOW, pOwner, "foot_R" );
#endif // GAME_DLL
m_flLaunchTime = gpGlobals->curtime + tf_rocketpack_launch_delay.GetFloat();
#endif // GAME_DLL
return true;
}
@ -519,16 +526,20 @@ bool CTFRocketPack::Launch( void )
pOwner->StopSound( "Weapon_LooseCannon.Charge" );
#ifdef GAME_DLL
m_flLaunchTime = 0.f;
pOwner->m_Shared.RemoveCond( TF_COND_PARACHUTE_ACTIVE );
#ifdef CLIENT_DLL
Vector m_vecLaunchDir;
#endif
// Launch
m_vecLaunchDir = CalcRocketForceFromPlayer( pOwner );
RocketLaunchPlayer( pOwner, m_vecLaunchDir, false );
#ifdef GAME_DLL
SetContextThink( &CTFRocketPack::PassengerDelayLaunchThink, gpGlobals->curtime + TF_ROCKETPACK_PASSENGER_DELAY_LAUNCH, "PassengerDelayLaunchThink" );
#endif
m_flRefireTime = gpGlobals->curtime + 0.5f;
@ -536,6 +547,7 @@ bool CTFRocketPack::Launch( void )
pOwner->m_Shared.SetRocketPackCharge( pOwner->m_Shared.GetRocketPackCharge() - tf_rocketpack_cost.GetFloat() );
}
#ifdef GAME_DLL
// Knock-back nearby enemies
float flRadius = 150.f;
CUtlVector< CTFPlayer* > vecPushedPlayers;
@ -594,6 +606,7 @@ bool CTFRocketPack::Launch( void )
}
CPASAttenuationFilter filter( pOwner );
filter.UsePredictionRules();
pOwner->EmitSound( filter, pOwner->entindex(), "Weapon_RocketPack.BoostersFire" );
IGameEvent *pEvent = gameeventmanager->CreateEvent( "rocketpack_launch" );
@ -610,7 +623,12 @@ bool CTFRocketPack::Launch( void )
DispatchParticleEffect( ROCKET_PACK_LAUNCH_EFFECT, PATTACH_POINT_FOLLOW, pWearable, "charge_LA" );
DispatchParticleEffect( ROCKET_PACK_LAUNCH_EFFECT, PATTACH_POINT_FOLLOW, pWearable, "charge_RA" );
}
#endif // GAME_DLL
#else
if ( prediction->IsFirstTimePredicted() )
{
pOwner->EmitSound( "Weapon_RocketPack.BoostersFire" );
}
#endif // CLIENT_DLL
return true;
}
@ -748,7 +766,7 @@ void CTFRocketPack::ItemPostFrame( void )
{
ResetTransition();
#ifdef CLIENT_DLL
if ( pOwner == C_TFPlayer::GetLocalTFPlayer() )
if ( pOwner == C_TFPlayer::GetLocalTFPlayer() && prediction->IsFirstTimePredicted() )
{
pOwner->EmitSound( "Weapon_RocketPack.BoostersReady" );
}
@ -757,7 +775,7 @@ void CTFRocketPack::ItemPostFrame( void )
else if ( pOwner->m_afButtonPressed & IN_ATTACK2 )
{
#ifdef CLIENT_DLL
if ( pOwner == C_TFPlayer::GetLocalTFPlayer() )
if ( pOwner == C_TFPlayer::GetLocalTFPlayer() && prediction->IsFirstTimePredicted() )
{
pOwner->EmitSound( "Player.DenyWeaponSelection" );
}
@ -841,14 +859,21 @@ const CEconItemView *CTFRocketPack::GetTauntItem() const
//-----------------------------------------------------------------------------
bool CTFRocketPack::Deploy( void )
{
#ifdef GAME_DLL
CTFPlayer *pOwner = GetTFPlayerOwner();
if ( pOwner )
{
EmitSound( "Weapon_RocketPack.BoostersExtend" );
#ifdef CLIENT_DLL
if ( prediction->IsFirstTimePredicted() )
#endif
{
CPASAttenuationFilter filter( pOwner );
filter.UsePredictionRules();
EmitSound( filter, entindex(), "Weapon_RocketPack.BoostersExtend" );
}
#ifdef GAME_DLL
SetEnabled( true );
#endif
}
#endif // GAME_DLL
return BaseClass::Deploy();
}
@ -861,14 +886,21 @@ void CTFRocketPack::StartHolsterAnim( void )
{
BaseClass::StartHolsterAnim();
#ifdef GAME_DLL
CTFPlayer *pOwner = GetTFPlayerOwner();
if ( pOwner )
{
EmitSound( "Weapon_RocketPack.BoostersRetract" );
#ifdef CLIENT_DLL
if ( prediction->IsFirstTimePredicted() )
#endif
{
CPASAttenuationFilter filter( pOwner );
filter.UsePredictionRules();
EmitSound( filter, entindex(), "Weapon_RocketPack.BoostersRetract" );
}
#ifdef GAME_DLL
SetEnabled( false );
#endif
}
#endif // GAME_DLL
}
@ -890,7 +922,7 @@ void CTFRocketPack::OnResourceMeterFilled()
{
#ifdef CLIENT_DLL
CBasePlayer *pPlayer = GetPlayerOwner();
if ( pPlayer->IsLocalPlayer() )
if ( pPlayer->IsLocalPlayer() && prediction->IsFirstTimePredicted() )
{
pPlayer->EmitSound( "TFPlayer.ReCharged" );
}

View File

@ -71,14 +71,14 @@ private:
bool IsTransitionCompleted( void ) const;
void WaitToLaunch( void );
void RocketLaunchPlayer( CTFPlayer *pPlayer, const Vector& vecForce, bool bIsPassenger );
Vector CalcRocketForceFromPlayer( CTFPlayer *pPlayer );
#ifdef GAME_DLL
void SetEnabled( bool bEnabled );
void PassengerDelayLaunchThink( void );
void RocketLaunchPlayer( CTFPlayer *pPlayer, const Vector& vecForce, bool bIsPassenger );
Vector CalcRocketForceFromPlayer( CTFPlayer *pPlayer );
#else
void CleanupParticles( void );
#endif // GAME_DLL
#endif // CLIENT_DLL
CNetworkVar( float, m_flInitLaunchTime );
CNetworkVar( float, m_flLaunchTime );

View File

@ -316,7 +316,6 @@ extern float AirBurstDamageForce( const Vector &size, float damage, float scale
//-----------------------------------------------------------------------------
void CTFScatterGun::FireBullet( CTFPlayer *pPlayer )
{
#ifndef CLIENT_DLL
if ( HasKnockback() )
{
// Perform some knock back.
@ -329,9 +328,9 @@ void CTFScatterGun::FireBullet( CTFPlayer *pPlayer )
return;
// Knock the firer back!
if ( !(pOwner->GetFlags() & FL_ONGROUND) && !pPlayer->m_bScattergunJump )
if ( !(pOwner->GetFlags() & FL_ONGROUND) && !pPlayer->m_Shared.m_bScattergunJump )
{
pPlayer->m_bScattergunJump = true;
pPlayer->m_Shared.m_bScattergunJump = true;
pOwner->m_Shared.StunPlayer( 0.3f, 1.f, TF_STUN_MOVEMENT | TF_STUN_MOVEMENT_FORWARD_ONLY );
@ -341,15 +340,15 @@ void CTFScatterGun::FireBullet( CTFPlayer *pPlayer )
AngleVectors( pOwner->EyeAngles(), &vecForward );
Vector vecForce = vecForward * -flForce;
EntityMatrix mtxPlayer;
mtxPlayer.InitFromEntity( pOwner );
VMatrix mtxPlayer;
mtxPlayer.SetupMatrixOrgAngles( pOwner->GetAbsOrigin(), pOwner->EyeAngles() );
Vector vecAbsVelocity = pOwner->GetAbsVelocity();
Vector vecAbsVelocityAsPoint = vecAbsVelocity + pOwner->GetAbsOrigin();
Vector vecLocalVelocity = mtxPlayer.WorldToLocal( vecAbsVelocityAsPoint );
Vector vecLocalVelocity = mtxPlayer.VMul4x3Transpose( vecAbsVelocityAsPoint );
vecLocalVelocity.x = -300;
vecAbsVelocityAsPoint = mtxPlayer.LocalToWorld( vecLocalVelocity );
vecAbsVelocityAsPoint = mtxPlayer.VMul4x3( vecLocalVelocity );
vecAbsVelocity = vecAbsVelocityAsPoint - pOwner->GetAbsOrigin();
pOwner->SetAbsVelocity( vecAbsVelocity );
@ -360,7 +359,6 @@ void CTFScatterGun::FireBullet( CTFPlayer *pPlayer )
pOwner->RemoveFlag( FL_ONGROUND );
}
}
#endif
BaseClass::FireBullet( pPlayer );
}

View File

@ -424,6 +424,19 @@ void CTFWeaponBase::Activate( void )
GiveDefaultAmmo();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFWeaponBase::GiveDefaultAmmo( void )
{
BaseClass::GiveDefaultAmmo();
if ( IsEnergyWeapon() )
{
m_flEnergy = Energy_GetMaxEnergy();
}
}
// -----------------------------------------------------------------------------
// Purpose:
// -----------------------------------------------------------------------------

View File

@ -282,6 +282,7 @@ class CTFWeaponBase : public CBaseCombatWeapon, public IHasOwner, public IHasGen
virtual void Spawn();
virtual void Activate( void );
virtual void GiveDefaultAmmo( void );
virtual void Precache();
virtual bool IsPredicted() const { return true; }
virtual void FallInit( void );

View File

@ -7,7 +7,7 @@
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@ -43,7 +43,7 @@ END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"#include ""winres.h""\r\n"
"\0"
END

View File

@ -7,7 +7,7 @@
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@ -43,7 +43,7 @@ END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"#include ""winres.h""\r\n"
"\0"
END

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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -155,7 +155,7 @@ float4 main( PS_INPUT i ) : COLOR
if( bFlashlight )
{
float3 worldSpaceNormal;
// Make the unbumped version not so fucking stupid and not need tangentSpaceTranspose you knob.
// Make the unbumped version not need tangentSpaceTranspose
worldSpaceNormal = mul( normal, i.tangentSpaceTranspose );
int nShadowSampleLevel = 0;

View File

@ -121,7 +121,7 @@
#define FL_INWATER (1<<9) // In water
// NOTE if you move things up, make sure to change this value
#define PLAYER_FLAG_BITS 10
#define PLAYER_FLAG_BITS 32
#define FL_FLY (1<<10) // Changes the SV_Movestep() behavior to not need to be on ground
#define FL_SWIM (1<<11) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water)

View File

@ -101,6 +101,7 @@ public:
virtual ~CProtoBufMsgBase();
bool BIsInitialized() const;
bool InitFromPacket( IMsgNetPacket * pNetPacket );
bool BAsyncSend( IProtoBufSendHandler & pSender ) const;
bool BAsyncSendWithPreSerializedBody( IProtoBufSendHandler & pSender, const byte *pubBody, uint32 cubBody ) const;

View File

@ -41,7 +41,11 @@ protected:
virtual void PerformLayout();
virtual void Paint();
MESSAGE_FUNC( OnMenuClose, "MenuClose" );
MESSAGE_FUNC_INT( OnCursorEnteredMenuButton, "CursorEnteredMenuButton", VPanel);
#ifdef PLATFORM_64BITS
MESSAGE_FUNC_PTR( OnCursorEnteredMenuButton, "CursorEnteredMenuButton", VPanel );
#else
MESSAGE_FUNC_INT( OnCursorEnteredMenuButton, "CursorEnteredMenuButton", VPanel );
#endif
private:
CUtlVector<MenuButton *> m_pMenuButtons;

View File

@ -347,6 +347,8 @@ public:
bool IsRightAligned(); // returns true if the settings are aligned to the right of the screen
bool IsBottomAligned(); // returns true if the settings are aligned to the bottom of the screen
virtual bool CanAnimate() const { return true; } // If the panel can animate
// scheme access functions
virtual HScheme GetScheme();
virtual void SetScheme(const char *tag);

View File

@ -0,0 +1,727 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#if defined(WIN32) && !defined( _X360 )
#include <windows.h>
#endif
#include "filesystem.h"
#include "filesystem_init.h"
#include "appframework/IAppSystemGroup.h"
#include "appframework/IAppSystem.h"
#include "appframework/AppFramework.h"
#include "filesystem_helpers.h"
#include "matsys_controls/QCGenerator.h"
#include "tier1/KeyValues.h"
#include "tier2/vconfig.h"
#include "vgui_controls/ListPanel.h"
#include "vgui_controls/TextEntry.h"
#include "vgui_controls/Button.h"
#include "vgui_controls/FileOpenDialog.h"
#include "vgui_controls/DirectorySelectDialog.h"
#include "vgui_controls/ComboBox.h"
#include "vgui_controls/CheckButton.h"
#include "vgui_controls/MessageBox.h"
#include "vgui/ISurface.h"
#include "vgui/IInput.h"
#include "vgui/Cursor.h"
#include "vgui_controls/KeyBoardEditorDialog.h"
#if defined( _X360 )
#include "xbox/xbox_win32stubs.h"
#endif
using namespace vgui;
#define MAX_KEYVALUE 1024
//-----------------------------------------------------------------------------
// Purpose: returns a pointer to the 'count' occurence of a character from the end of a string
// returns 0 of there aren't 'count' number of the character in the string
//-----------------------------------------------------------------------------
char *strrchrcount(char *string, int character, int count )
{
int j = count;
int numChars = V_strlen( string );
for( int i = numChars; i > 0; i-- )
{
if( string[i-1] == character )
{
j--;
}
if( j == 0 )
{
return string + i-1;
}
}
return 0;
}
class CModalPreserveMessageBox : public vgui::MessageBox
{
public:
CModalPreserveMessageBox(const char *title, const char *text, vgui::Panel *parent)
: vgui::MessageBox( title, text, parent )
{
m_PrevAppFocusPanel = vgui::input()->GetAppModalSurface();
}
~CModalPreserveMessageBox()
{
vgui::input()->SetAppModalSurface( m_PrevAppFocusPanel );
}
public:
vgui::VPANEL m_PrevAppFocusPanel;
};
void VGUIMessageBox( vgui::Panel *pParent, const char *pTitle, const char *pMsg, ... )
{
char msg[4096];
va_list marker;
va_start( marker, pMsg );
Q_vsnprintf( msg, sizeof( msg ), pMsg, marker );
va_end( marker );
vgui::MessageBox *dlg = new CModalPreserveMessageBox( pTitle, msg, pParent );
dlg->DoModal();
dlg->Activate();
dlg->RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose: Places all the info from the vgui controls into the QCInfo struct
//-----------------------------------------------------------------------------
void QCInfo::SyncFromControls()
{
char tempText[MAX_PATH];
vgui::Panel *pTargetField = pQCGenerator->FindChildByName( "staticPropCheck" );
bStaticProp = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "mostlyOpaqueCheck" );
bMostlyOpaque = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "disableCollisionsCheck" );
bDisableCollision = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "referencePhysicsCheck" );
bReferenceAsPhys = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "concaveCheck" );
bConcave = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "automassCheck" );
bAutomass = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "massField" );
((TextEntry *)pTargetField)->GetText(tempText, MAX_PATH);
fMass = atof(tempText);
pTargetField = pQCGenerator->FindChildByName( "scaleField" );
((TextEntry *)pTargetField)->GetText(tempText, MAX_PATH);
fScale = atof(tempText);
pTargetField = pQCGenerator->FindChildByName( "collisionSMDField" );
((TextEntry *)pTargetField)->GetText( tempText, MAX_PATH );
V_strcpy_safe( pszCollisionPath, tempText );
pTargetField = pQCGenerator->FindChildByName( "surfacePropertyDropDown" );
((ComboBox *)pTargetField)->GetText( tempText, MAX_PATH );
V_strcpy_safe( pszSurfaceProperty, tempText );
pTargetField = pQCGenerator->FindChildByName( "materialsField" );
((TextEntry *)pTargetField)->GetText( tempText, MAX_PATH );
V_strcpy_safe( pszMaterialPath, tempText );
LODs.RemoveAll();
pTargetField = pQCGenerator->FindChildByName( "LODList" );
int numLOD = ((ListPanel *)pTargetField)->GetItemCount();
for ( int i = 0; i < numLOD; i++ )
{
KeyValues *key = ((ListPanel *)pTargetField)->GetItem( i );
LODInfo newLOD;
V_strcpy_safe( newLOD.pszFilename, key->GetString( "SMD" ) );
newLOD.iLOD = key->GetInt( "LOD" );
LODs.AddToTail( newLOD );
}
}
//-----------------------------------------------------------------------------
// Purpose: Called during intialization to setup the initial state of the VGUI controls
//-----------------------------------------------------------------------------
void QCInfo::SyncToControls()
{
char tempText[MAX_PATH];
vgui::Panel *pTargetField = pQCGenerator->FindChildByName( "staticPropCheck" );
((CheckButton *)pTargetField)->SetSelected( bStaticProp );
pTargetField = pQCGenerator->FindChildByName( "mostlyOpaqueCheck" );
((CheckButton *)pTargetField)->SetSelected( bMostlyOpaque );
pTargetField = pQCGenerator->FindChildByName( "disableCollisionsCheck" );
((CheckButton *)pTargetField)->SetSelected( bDisableCollision );
pTargetField = pQCGenerator->FindChildByName( "referencePhysicsCheck" );
((CheckButton *)pTargetField)->SetSelected( bReferenceAsPhys );
pTargetField = pQCGenerator->FindChildByName( "concaveCheck" );
((CheckButton *)pTargetField)->SetSelected( bConcave );
pTargetField = pQCGenerator->FindChildByName( "automassCheck" );
((CheckButton *)pTargetField)->SetSelected( bAutomass );
Q_snprintf( tempText, 10, "%d", (int)fMass );
pTargetField = pQCGenerator->FindChildByName( "massField" );
((TextEntry *)pTargetField)->SetText( tempText );
Q_snprintf( tempText, 10, "%d", (int)fScale );
pTargetField = pQCGenerator->FindChildByName( "scaleField" );
((TextEntry *)pTargetField)->SetText( tempText );
pTargetField = pQCGenerator->FindChildByName( "collisionSMDField" );
((TextEntry *)pTargetField)->SetText( pszCollisionPath );
pTargetField = pQCGenerator->FindChildByName( "materialsField" );
((TextEntry *)pTargetField)->SetText( pszMaterialPath );
pTargetField = pQCGenerator->FindChildByName( "surfacePropertyDropDown" );
int numItems = ((ComboBox *)pTargetField)->GetItemCount();
for( int i = 0; i < numItems; i++ )
{
((ComboBox *)pTargetField)->GetItemText( i, tempText, MAX_PATH );
if ( !Q_strcmp( tempText, pszSurfaceProperty ) )
{
((ComboBox *)pTargetField)->SetItemEnabled( i, true );
((ComboBox *)pTargetField)->SetText( tempText );
break;
}
}
}
CBrowseButton::CBrowseButton( vgui::Panel *pParent ) : BaseClass( pParent, "Browse Button", "...", pParent, "browse" )
{
SetParent( pParent );
pszStartingDirectory = NULL;
pszFileFilter = NULL;
pszTargetField = NULL;
}
CBrowseButton::~CBrowseButton()
{
}
void CBrowseButton::SetCharVar( char **pVar, const char *pszNewText )
{
if ( *pVar && pszNewText && !Q_strcmp( *pVar, pszNewText ) )
{
return;
}
if ( *pVar )
{
delete [] *pVar;
*pVar = NULL;
}
if ( pszNewText )
{
int len = Q_strlen( pszNewText ) + 1;
*pVar = new char[ len ];
Q_strncpy( *pVar, pszNewText, len );
}
}
void CBrowseButton::InitBrowseInfo( int x, int y, const char *pszName, const char *pszDir, const char *pszFilter, const char *pszField )
{
SetSize( 24, 24 );
SetPos( x, y );
SetName( pszName );
SetCharVar( GetStartingDirectory(), pszDir );
SetCharVar( GetFileFilter(), pszFilter );
SetCharVar( GetTargetField(), pszField );
SetActionMessage();
}
void CBrowseButton::SetActionMessage()
{
KeyValues *newActionMessage = new KeyValues( "browse", "directory", pszStartingDirectory, "filter", pszFileFilter);
newActionMessage->SetString( "targetField", pszTargetField );
SetCommand( newActionMessage );
}
const char *ParseKeyvalue( const char *pBuffer, char *key, char *value )
{
char com_token[1024];
pBuffer = (const char *)ParseFile( pBuffer, com_token, NULL );
if ( Q_strlen( com_token ) < MAX_KEYVALUE )
{
Q_strncpy( key, com_token, MAX_KEYVALUE );
Q_strlower( key );
}
// no value on a close brace
if ( !Q_strcmp( key, "}" ) )
{
value[0] = 0;
return pBuffer;
}
pBuffer = (const char *)ParseFile( pBuffer, com_token, NULL );
if ( Q_strlen( com_token ) < MAX_KEYVALUE )
{
Q_strncpy( value, com_token, MAX_KEYVALUE );
Q_strlower( value );
}
return pBuffer;
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CQCGenerator::CQCGenerator( vgui::Panel *pParent, const char *pszPath, const char *pszScene ) : BaseClass( pParent, "QCGenerator" )
{
m_szTargetField[0] = 0;
m_nSelectedSequence = 0;
m_nSelectedColumn = 0;
m_QCInfo_t.Init( this );
SetMinimumSize(846, 770);
m_pLODPanel = new ListPanel(this, "LODList");
m_pLODPanel->SetSelectIndividualCells( true );
m_pLODPanel->AddColumnHeader(0, "SMD", "LOD SMD", 450, 0);
m_pLODPanel->AddColumnHeader(1, "LOD", "LOD Distance", 50, 0);
m_pLODPanel->AddActionSignalTarget( this );
m_pLODPanel->SetMouseInputEnabled( true );
LoadControlSettings( "QCGenerator.res" );
m_pCollisionBrowseButton = new CBrowseButton( this );
m_pCollisionBrowseButton->InitBrowseInfo( 808, 158, "collisionBrowseButton", pszPath, "*.smd", "collisionSMDField" );
char szTerminatedPath[1024] = "\0";
sprintf( szTerminatedPath, "%s\\", pszPath );
InitializeSMDPaths( szTerminatedPath, pszScene );
char *pszMaterialsStart = strrchrcount( szTerminatedPath, '\\', 3 ) + 1;
char *pszMaterialsEnd = strrchr( szTerminatedPath, '\\');
Q_strncpy( m_QCInfo_t.pszMaterialPath, pszMaterialsStart, pszMaterialsEnd - pszMaterialsStart + 1 );
SetParent( pParent );
char szGamePath[1024] = "\0";
char szSearchPath[1024] = "\0";
// Get the currently set game configuration
GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGamePath, sizeof( szGamePath ) );
static const char *pSurfacePropFilename = "\\scripts\\surfaceproperties.txt";
sprintf( szSearchPath, "%s%s", szGamePath, pSurfacePropFilename );
FileHandle_t fp = g_pFullFileSystem->Open( szSearchPath, "rb" );
if ( !fp )
{
//the set game configuration didn't have a surfaceproperties file; we are grabbing it from hl2
//TODO: This only works if they are in a subdirectory that is a peer to an hl2 directory
// that contains the file. It potentially needs to search the entire drive or prompt for the location
char *pszEndGamePath = Q_strrchr( szGamePath, '\\' );
pszEndGamePath[0] = 0;
V_strcat_safe( szGamePath, "\\hl2" );
sprintf( szSearchPath, "%s%s", szGamePath, pSurfacePropFilename );
fp = g_pFullFileSystem->Open( szSearchPath, "rb" );
}
int len = g_pFullFileSystem->Size( fp );
const char *szSurfacePropContents = new char[len+1];
g_pFullFileSystem->Read( (void *)szSurfacePropContents, len, fp );
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
vgui::Panel *pSurfacePropDropDown = FindChildByName( "surfacePropertyDropDown" );
//filling up the surface property dropdown
while ( szSurfacePropContents )
{
szSurfacePropContents = ParseKeyvalue( szSurfacePropContents, key, value );
((ComboBox *)pSurfacePropDropDown)->AddItem( key, NULL );
while ( szSurfacePropContents )
{
szSurfacePropContents = ParseKeyvalue( szSurfacePropContents, key, value );
if (!stricmp( key, "}" ) )
{
break;
}
}
}
m_QCInfo_t.SyncToControls();
m_pLODEdit = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CQCGenerator::~CQCGenerator()
{
}
void CQCGenerator::OnCommand( const char *command )
{
if ( Q_stricmp( command, "createQC" ) == 0 )
{
m_QCInfo_t.SyncFromControls();
GenerateQCFile();
}
if ( Q_stricmp( command, "deleteSeq" ) == 0 )
{
//delete it
DeleteLOD();
}
if ( Q_stricmp( command, "editSeq" ) == 0 )
{
//edit
EditLOD();
}
BaseClass::OnCommand( command );
}
void CQCGenerator::OnKeyCodeTyped( KeyCode code )
{
switch ( code )
{
case KEY_ENTER:
EditLOD();
}
}
void CQCGenerator::OnBrowse( KeyValues *data )
{
V_strcpy_safe( m_szTargetField, data->GetString( "targetField" ) );
const char *filter = data->GetString( "filter" );
if ( Q_strlen( filter ) == 0 )
{
// BrowseDirectory( data );
}
else
{
BrowseFile( data );
}
}
/*
//This function is no longer used in the current version of the program.
void CQCGenerator::BrowseDirectory( KeyValues *data )
{
DirectorySelectDialog *pDialog = new DirectorySelectDialog( this, "Select Directory" );
pDialog->AddActionSignalTarget( this );
pDialog->DoModal();
pDialog->SetStartDirectory( data->GetString( "directory" ) );
}
*/
void CQCGenerator::BrowseFile( KeyValues *data )
{
const char *filter = data->GetString( "filter" );
FileOpenDialog *pDialog = new FileOpenDialog( this, "Select File", true );
pDialog->AddFilter( filter, filter, true );
pDialog->AddActionSignalTarget(this);
pDialog->SetStartDirectory( data->GetString( "directory" ) );
pDialog->DoModal( true );
}
void CQCGenerator::OnFileSelected( KeyValues *data )
{
if ( *m_szTargetField )
{
vgui::Panel *pTargetField = FindChildByName( m_szTargetField );
((TextEntry *)pTargetField)->SetText( data->GetString( "fullpath" ) );
Repaint();
}
}
void CQCGenerator::OnDirectorySelected( KeyValues *data )
{
if ( *m_szTargetField )
{
vgui::Panel *pTargetField = FindChildByName( m_szTargetField );
((TextEntry *)pTargetField)->SetText( data->GetString( "dir" ) );
Repaint();
}
}
bool CQCGenerator::GenerateQCFile()
{
//TODO: clean this up. Consider creating a datatype that includes the string to write out when the QC file is created
char *nameBegin = strrchr( m_QCInfo_t.pszSMDPath, '\\' );
char szPath[MAX_PATH];
char szName[MAX_PATH];
Q_strncpy( szPath, m_QCInfo_t.pszSMDPath, nameBegin - m_QCInfo_t.pszSMDPath + 2 );
V_strcpy_safe( szName, szPath);
V_strcat_safe( szName, m_QCInfo_t.pszSceneName);
V_strcat_safe( szName, ".qc" );
FileHandle_t pSaveFile = g_pFullFileSystem->Open( szName, "wt" );
if (!pSaveFile)
{
char szSaveError[1024] = "";
Q_snprintf( szSaveError, 1024, "Save failed: invalid file name '%s'\n\nDirectory '%s' must exist.", szName, szPath );
VGUIMessageBox( this, "QC Generator error", szSaveError );
return 0;
}
//write qc header
g_pFullFileSystem->FPrintf( pSaveFile, "//\n// .qc file version 1.0\n\n");
//write out modelname info
char szModelName[MAX_PATH];
char *modelStart = strrchrcount( szName, '\\', 2) + 1;
char *modelEnd = strrchr( szName, '.' );
Q_strncpy( szModelName, modelStart, modelEnd - modelStart + 1 );
V_strcat_safe( szModelName, ".mdl" );
g_pFullFileSystem->FPrintf( pSaveFile, "$modelname %s\n\n", szModelName );
//write out scale info
g_pFullFileSystem->FPrintf( pSaveFile, "$scale %f\n", m_QCInfo_t.fScale );
//write out body info
g_pFullFileSystem->FPrintf( pSaveFile, "$body \"Body\" \"%s\"\n", strrchr( m_QCInfo_t.pszSMDPath, '\\' ) + 1 );
if ( m_QCInfo_t.bStaticProp == true )
{
g_pFullFileSystem->FPrintf( pSaveFile, "$staticprop\n" );
}
if ( m_QCInfo_t.bMostlyOpaque == true )
{
g_pFullFileSystem->FPrintf( pSaveFile, "$mostlyopaque\n" );
}
//write out surfaceprop info
g_pFullFileSystem->FPrintf( pSaveFile, "$surfaceprop \"%s\"\n\n", m_QCInfo_t.pszSurfaceProperty );
//write materials
g_pFullFileSystem->FPrintf( pSaveFile, "$cdmaterials %s\n\n", m_QCInfo_t.pszMaterialPath);
if ( m_QCInfo_t.bStaticProp || m_QCInfo_t.bNoAnimation )
{
g_pFullFileSystem->FPrintf( pSaveFile, "// --------- Animation sequences -------\n");
g_pFullFileSystem->FPrintf( pSaveFile, "$sequence \"idle\" \"%s\" fps 30\n\n", strrchr(m_QCInfo_t.pszSMDPath, '\\')+1);
}
//write out lod info
for( int i = 0; i < m_QCInfo_t.LODs.Count(); i++ )
{
LODInfo thisLOD = m_QCInfo_t.LODs.Element( i );
g_pFullFileSystem->FPrintf( pSaveFile, "$lod %d\n{\n\treplacemodel \"%s\" \"%s\"\n}\n\n", thisLOD.iLOD, strrchr(m_QCInfo_t.pszSMDPath, '\\')+1, thisLOD.pszFilename );
}
if ( m_QCInfo_t.bDisableCollision != true )
{
//write out collision header
g_pFullFileSystem->FPrintf( pSaveFile, "\n" );
//write out collision info
if ( m_QCInfo_t.bReferenceAsPhys == true )
{
g_pFullFileSystem->FPrintf( pSaveFile, "$collisionmodel \"%s\"", strrchr( m_QCInfo_t.pszSMDPath, '\\' ) + 1 );
}
else
{
if( Q_strcmp( m_QCInfo_t.pszCollisionPath, "" ) )
{
g_pFullFileSystem->FPrintf( pSaveFile, "$collisionmodel \"%s\"", strrchr( m_QCInfo_t.pszCollisionPath, '\\' ) + 1 );
}
}
g_pFullFileSystem->FPrintf( pSaveFile, " {\n\t// Mass in kilograms\n ");
if ( m_QCInfo_t.bAutomass == true )
{
g_pFullFileSystem->FPrintf( pSaveFile, "\t$automass\n" );
}
else
{
g_pFullFileSystem->FPrintf( pSaveFile, "\t$mass %f\n", m_QCInfo_t.fMass );
}
if ( m_QCInfo_t.bConcave == true )
{
g_pFullFileSystem->FPrintf( pSaveFile, "\t$concave\n" );
}
g_pFullFileSystem->FPrintf( pSaveFile, "}\n\n");
}
g_pFullFileSystem->Close( pSaveFile );
char szCommand[MAX_PATH];
char szGamePath[MAX_PATH];
char studiomdlPath[512];
g_pFullFileSystem->RelativePathToFullPath( "studiomdl.bat", NULL, studiomdlPath, sizeof( studiomdlPath ));
GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGamePath, sizeof( szGamePath ) );
#ifdef WIN32
STARTUPINFO startup;
PROCESS_INFORMATION process;
memset(&startup, 0, sizeof(startup));
startup.cb = sizeof(startup);
sprintf( szCommand, "%s -game %s %s", studiomdlPath, szGamePath, szName);
bool bReturn = CreateProcess( NULL, szCommand, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &startup, &process);
#else
Assert( !"Implement me, why aren't we using a thread tool abstraction?" );
bool bReturn = false;
#endif
return bReturn;
}
void CQCGenerator::InitializeSMDPaths( const char *pszPath, const char *pszScene )
{
V_strcpy_safe( m_QCInfo_t.pszSceneName, pszScene );
FileFindHandle_t *pFileHandle = new FileFindHandle_t();
g_pFullFileSystem->AddSearchPath( pszPath, "SMD_DIR" );
const char *filename = g_pFullFileSystem->FindFirst( "*.smd", pFileHandle );
bool bFoundReference = false;
bool bFoundCollision = false;
bool bFoundLOD = false;
//iterate through .smd files
const char *startName = pszScene;
int nSearchLength = Q_strlen( pszScene );
int currentLOD = 1;
while( filename )
{
if ( !strncmp( startName, filename, nSearchLength ) )
{
const char *filenameEnd = filename + nSearchLength;
if ( !strncmp( filenameEnd, "_ref", 4 ) || !strncmp( filenameEnd, ".smd", 4 ) )
{
bFoundReference = true;
//we have found the reference smd.
V_strcpy_safe( m_QCInfo_t.pszSMDPath, pszPath );
V_strcat_safe( m_QCInfo_t.pszSMDPath, filename );
}
if ( !strncmp( filenameEnd, "_phy", 4) || !strncmp( filenameEnd, "_col", 4 ) )
{
bFoundCollision = true;
//we have found the collision smd.
V_strcpy_safe( m_QCInfo_t.pszCollisionPath, pszPath );
V_strcat_safe( m_QCInfo_t.pszCollisionPath, filename );
}
if ( !strncmp( filenameEnd, "_lod", 4) )
{
bFoundLOD = true;
//we found an LOD smd.
char lodName[255];
Q_snprintf( lodName, Q_strlen( lodName ), "lod%d", currentLOD );
//we found an LOD
KeyValues *newKv = new KeyValues( lodName, "SMD", filename, "LOD", "10" );
m_pLODPanel->AddItem( newKv, currentLOD, false, false );
currentLOD++;
}
}
filename = g_pFullFileSystem->FindNext( *pFileHandle );
}
char pszMessage[2048] = "";
char pszRefMessage[1024] = "";
char pszColMessage[1024] = "";
if (!bFoundReference )
{
V_strcat_safe( m_QCInfo_t.pszSMDPath, pszPath );
V_strcat_safe( m_QCInfo_t.pszSMDPath, pszScene );
V_strcat_safe( m_QCInfo_t.pszSMDPath, ".smd" );
Q_snprintf( pszRefMessage, 1024, "Reference SMD not found.\n\nValid default reference SMDs are %s%s_ref*.smd and %s%s.smd\nUsing default of %s. Model will not compile.\n\n", pszPath, pszScene, pszPath, pszScene, m_QCInfo_t.pszSMDPath );
}
if ( !bFoundCollision )
{
Q_snprintf( pszColMessage, 1024, "Collision SMD not found.\n\nThe valid default collision SMD is %s%s_phy*.smd.\nUsing reference SMD as default.\n", pszPath, pszScene );
V_strcpy_safe( m_QCInfo_t.pszCollisionPath, m_QCInfo_t.pszSMDPath );
m_QCInfo_t.bReferenceAsPhys = true;
}
if ( !bFoundReference || !bFoundCollision)
{
V_strcpy_safe( pszMessage, pszRefMessage );
V_strcat_safe( pszMessage, pszColMessage );
VGUIMessageBox( this, "Error Initializing Paths", pszMessage );
}
}
void CQCGenerator::DeleteLOD()
{
int numSelected = m_pLODPanel->GetSelectedItemsCount();
int selected;
for ( int i = numSelected-1; i >= 0; i-- )
{
selected = m_pLODPanel->GetSelectedItem( i );
m_pLODPanel->RemoveItem( selected );
}
}
void CQCGenerator::EditLOD()
{
int numSelected = m_pLODPanel->GetSelectedItemsCount();
if ( numSelected == 1 && !m_pLODPanel->IsInEditMode() )
{
if ( m_pLODEdit )
{
m_pLODEdit->MarkForDeletion();
m_pLODEdit = NULL;
}
m_pLODEdit = new vgui::TextEntry( this, "Edit" );
m_pLODEdit->SendNewLine( true );
m_nSelectedSequence = m_pLODPanel->GetSelectedItem( 0 );
m_nSelectedColumn = m_pLODPanel->GetSelectedColumn();
m_pLODPanel->EnterEditMode( m_nSelectedSequence, m_nSelectedColumn, m_pLODEdit );
}
}
void CQCGenerator::OnNewLODText()
{
KeyValues *pEditItem = m_pLODPanel->GetItem( m_nSelectedSequence );
KeyValues *pListItem = pEditItem;
wchar_t szEditText[MAX_PATH];
pEditItem = pEditItem->GetFirstValue();
const char *name = pEditItem->GetName();
for( int i = 0; i < m_nSelectedColumn; i++ )
{
pEditItem = pEditItem->GetNextValue();
name = pEditItem->GetName();
}
m_pLODEdit->GetText( szEditText, MAX_PATH );
pListItem->SetWString( name, szEditText );
m_pLODPanel->LeaveEditMode();
m_pLODPanel->InvalidateLayout();
return;
}

View File

@ -0,0 +1,47 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "matsys_controls/assetpicker.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// Asset Picker with no preview
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CAssetPicker::CAssetPicker( vgui::Panel *pParent, const char *pAssetType,
const char *pExt, const char *pSubDir, const char *pTextType ) :
BaseClass( pParent, pAssetType, pExt, pSubDir, pTextType )
{
CreateStandardControls( this );
LoadControlSettingsAndUserConfig( "resource/assetpicker.res" );
}
//-----------------------------------------------------------------------------
//
// Purpose: Modal picker frame
//
//-----------------------------------------------------------------------------
CAssetPickerFrame::CAssetPickerFrame( vgui::Panel *pParent, const char *pTitle,
const char *pAssetType, const char *pExt, const char *pSubDir, const char *pTextType ) :
BaseClass( pParent )
{
SetAssetPicker( new CAssetPicker( this, pAssetType, pExt, pSubDir, pTextType ) );
LoadControlSettingsAndUserConfig( "resource/assetpickerframe.res" );
SetTitle( pTitle, false );
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#include "matsys_controls/curveeditorpanel.h"
#include "matsys_controls/matsyscontrols.h"
#include "tier1/KeyValues.h"
#include "vgui/ISurface.h"
#include "vgui/IInput.h"
#include "vgui/MouseCode.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CCurveEditorPanel::CCurveEditorPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName )
{
m_nSelectedPoint = -1;
SetMouseInputEnabled( true );
SetKeyBoardInputEnabled( true );
m_nHighlightedPoint = -1;
}
CCurveEditorPanel::~CCurveEditorPanel()
{
}
//-----------------------------------------------------------------------------
// Converts screen location to normalized values
//-----------------------------------------------------------------------------
void CCurveEditorPanel::ScreenToValue( int x, int y, float *pIn, float *pOut )
{
int w, h;
GetSize( w, h );
*pIn = (float)x / (w-1);
*pOut = 1.0f - ((float)y / (h-1));
}
void CCurveEditorPanel::ValueToScreen( float flIn, float flOut, int *x, int *y )
{
int w, h;
GetSize( w, h );
*x = (int)(flIn * (w-1) + 0.5f);
*y = (h-1) - (int)(flOut * (h-1) + 0.5f);
}
//-----------------------------------------------------------------------------
// Handle input
//-----------------------------------------------------------------------------
void CCurveEditorPanel::OnMousePressed( vgui::MouseCode code )
{
BaseClass::OnMousePressed( code );
int x, y;
input()->GetCursorPos( x, y );
ScreenToLocal( x, y );
if ( code == MOUSE_LEFT )
{
int w, h;
GetSize( w, h );
float flIn, flOut;
ScreenToValue( x, y, &flIn, &flOut );
float flTolerance = 5.0f / (w-1); // +/- 3 pixels to select the point
m_nSelectedPoint = FindOrAddControlPoint( flIn, flTolerance, flOut );
}
}
void CCurveEditorPanel::OnMouseReleased( vgui::MouseCode code )
{
BaseClass::OnMouseReleased( code );
if ( code == MOUSE_LEFT )
{
m_nSelectedPoint = -1;
}
}
void CCurveEditorPanel::OnCursorMoved( int x, int y )
{
BaseClass::OnCursorMoved( x, y );
float flIn, flOut;
ScreenToValue( x, y, &flIn, &flOut );
int w, h;
GetSize( w, h );
float flTolerance = 5.0f / (w-1); // +/- 3 pixels to select the point
m_nHighlightedPoint = FindControlPoint( flIn, flTolerance );
if ( m_nSelectedPoint < 0 )
return;
m_nSelectedPoint = ModifyControlPoint( m_nSelectedPoint, flIn, flOut );
}
//-----------------------------------------------------------------------------
// Handles keypresses
//-----------------------------------------------------------------------------
void CCurveEditorPanel::OnKeyCodePressed( vgui::KeyCode code )
{
BaseClass::OnKeyCodePressed( code );
if ( m_nSelectedPoint >= 0 )
{
RemoveControlPoint( m_nSelectedPoint );
m_nSelectedPoint = -1;
}
}
//-----------------------------------------------------------------------------
// This paints the grid behind the curves
//-----------------------------------------------------------------------------
void CCurveEditorPanel::PaintBackground( void )
{
int w, h;
GetSize( w, h );
vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
vgui::surface()->DrawFilledRect( 0, 0, w, h );
vgui::surface()->DrawSetColor( 128, 128, 128, 255 );
vgui::surface()->DrawLine( 0, h/4, w, h/4 );
vgui::surface()->DrawLine( 0, h/2, w, h/2 );
vgui::surface()->DrawLine( 0, 3*h/4, w, 3*h/4 );
vgui::surface()->DrawLine( w/4, 0, w/4, h );
vgui::surface()->DrawLine( w/2, 0, w/2, h );
vgui::surface()->DrawLine( 3*w/4, 0, 3*w/4, h );
vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
vgui::surface()->DrawLine( 0, 0, w, 0 );
vgui::surface()->DrawLine( w, 0, w, h );
vgui::surface()->DrawLine( w, h, 0, h );
vgui::surface()->DrawLine( 0, h, 0, 0 );
}
//-----------------------------------------------------------------------------
// Sets the color curves operation to edit
//-----------------------------------------------------------------------------
void CCurveEditorPanel::Paint( void )
{
int w, h;
GetSize( w, h );
int x0 = 0, y0 = 0;
// FIXME: Add method to draw multiple lines DrawPolyLine connects the 1st and last points... bleah
vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
for ( int i = 0; i < w; ++i )
{
float flIn = (float)i / (w-1);
float flOut = GetValue( flIn );
int x = i;
int y = (h-1) - (int)(flOut * (h-1) + 0.5f);
y = clamp( y, 0, h-1 );
if ( i != 0 )
{
vgui::surface()->DrawLine( x0, y0, x, y );
}
x0 = x; y0 = y;
}
// This will paint the control points
// The currently selected one will be painted red and filled.
for ( int i = ControlPointCount(); --i >= 0; )
{
float flIn, flOut;
GetControlPoint( i, &flIn, &flOut );
int cx, cy;
ValueToScreen( flIn, flOut, &cx, &cy );
if ( (i == m_nSelectedPoint) || ((m_nSelectedPoint == -1) && (i == m_nHighlightedPoint)) )
{
vgui::surface()->DrawSetColor( 255, 0, 0, 255 );
vgui::surface()->DrawFilledRect( cx-3, cy-3, cx+3, cy+3 );
}
else
{
vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
vgui::surface()->DrawOutlinedRect( cx-3, cy-3, cx+3, cy+3 );
}
}
}

View File

@ -0,0 +1,301 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#if defined(WIN32) && !defined( _X360 )
#include <windows.h>
#endif
#undef PropertySheet
#include "matsys_controls/gamefiletreeview.h"
#include "filesystem.h"
#include "tier1/KeyValues.h"
#include "vgui/ISurface.h"
#include "vgui/Cursor.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// list of all tree view icons
//-----------------------------------------------------------------------------
enum
{
IMAGE_FOLDER = 1,
IMAGE_OPENFOLDER,
IMAGE_FILE,
};
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CGameFileTreeView::CGameFileTreeView( Panel *parent, const char *name, const char *pRootFolderName, const char *pRootDir, const char *pExtension ) : BaseClass(parent, name), m_Images( false )
{
m_RootDir = pRootDir;
m_Ext = pExtension;
m_bUseExt = ( pExtension != NULL );
m_RootFolderName = pRootFolderName;
// build our list of images
m_Images.AddImage( scheme()->GetImage( "resource/icon_folder", false ) );
m_Images.AddImage( scheme()->GetImage( "resource/icon_folder_selected", false ) );
m_Images.AddImage( scheme()->GetImage( "resource/icon_file", false ) );
SetImageList( &m_Images, false );
}
//-----------------------------------------------------------------------------
// Purpose: Refreshes the active file list
//-----------------------------------------------------------------------------
void CGameFileTreeView::RefreshFileList()
{
RemoveAll();
SetFgColor(Color(216, 222, 211, 255));
// add the base node
KeyValues *pkv = new KeyValues( "root" );
pkv->SetString( "text", m_RootFolderName );
pkv->SetInt( "root", 1 );
pkv->SetInt( "expand", 1 );
int iRoot = AddItem( pkv, GetRootItemIndex() );
pkv->deleteThis();
ExpandItem( iRoot, true );
}
//-----------------------------------------------------------------------------
// Selects the root folder
//-----------------------------------------------------------------------------
void CGameFileTreeView::SelectRoot()
{
AddSelectedItem( GetRootItemIndex(), true );
}
//-----------------------------------------------------------------------------
// Gets the number of root directories
//-----------------------------------------------------------------------------
int CGameFileTreeView::GetRootDirectoryCount()
{
return GetNumChildren( GetRootItemIndex() );
}
//-----------------------------------------------------------------------------
// Gets the ith root directory
//-----------------------------------------------------------------------------
const char *CGameFileTreeView::GetRootDirectory( int nIndex )
{
int nItemIndex = GetChild( GetRootItemIndex(), nIndex );
KeyValues *kv = GetItemData( nItemIndex );
if ( !kv )
return NULL;
return kv->GetString( "path", NULL );
}
//-----------------------------------------------------------------------------
// Populate the root node (necessary since tree view can't have multiple roots)
//-----------------------------------------------------------------------------
void CGameFileTreeView::PopulateRootNode( int itemIndex )
{
AddDirectoriesOfNode( itemIndex, m_RootDir );
if ( m_bUseExt )
{
AddFilesOfNode( itemIndex, m_RootDir, m_Ext );
}
}
//-----------------------------------------------------------------------------
// Populate the root node with directories
//-----------------------------------------------------------------------------
bool CGameFileTreeView::DoesDirectoryHaveSubdirectories( const char *pFilePath )
{
char pSearchString[MAX_PATH];
Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pFilePath );
// get the list of files
FileFindHandle_t findHandle;
// generate children
// add all the items
const char *pszFileName = g_pFullFileSystem->FindFirstEx( pSearchString, "GAME", &findHandle );
while ( pszFileName )
{
bool bIsDirectory = g_pFullFileSystem->FindIsDirectory( findHandle );
if ( bIsDirectory && Q_strnicmp( pszFileName, ".", 2 ) && Q_strnicmp( pszFileName, "..", 3 ) )
return true;
pszFileName = g_pFullFileSystem->FindNext( findHandle );
}
g_pFullFileSystem->FindClose( findHandle );
return false;
}
//-----------------------------------------------------------------------------
// Populate the root node with directories
//-----------------------------------------------------------------------------
void CGameFileTreeView::AddDirectoriesOfNode( int itemIndex, const char *pFilePath )
{
char pSearchString[MAX_PATH];
Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pFilePath );
// get the list of files
FileFindHandle_t findHandle;
// generate children
// add all the items
const char *pszFileName = g_pFullFileSystem->FindFirstEx( pSearchString, "GAME", &findHandle );
while ( pszFileName )
{
bool bIsDirectory = g_pFullFileSystem->FindIsDirectory( findHandle );
if ( bIsDirectory && Q_strnicmp( pszFileName, ".", 2 ) && Q_strnicmp( pszFileName, "..", 3 ) )
{
KeyValues *kv = new KeyValues( "node", "text", pszFileName );
char pFullPath[MAX_PATH];
Q_snprintf( pFullPath, sizeof(pFullPath), "%s/%s", pFilePath, pszFileName );
Q_FixSlashes( pFullPath );
Q_strlower( pFullPath );
bool bHasSubdirectories = DoesDirectoryHaveSubdirectories( pFullPath );
kv->SetString( "path", pFullPath );
kv->SetInt( "expand", bHasSubdirectories );
kv->SetInt( "dir", 1 );
kv->SetInt( "image", IMAGE_FOLDER );
int itemID = AddItem(kv, itemIndex);
kv->deleteThis();
// mark directories in orange
SetItemColorForDirectories( itemID );
}
pszFileName = g_pFullFileSystem->FindNext( findHandle );
}
g_pFullFileSystem->FindClose( findHandle );
}
//-----------------------------------------------------------------------------
// Populate the root node with files
//-----------------------------------------------------------------------------
void CGameFileTreeView::AddFilesOfNode( int itemIndex, const char *pFilePath, const char *pExt )
{
char pSearchString[MAX_PATH];
Q_snprintf( pSearchString, MAX_PATH, "%s\\*.%s", pFilePath, pExt );
// get the list of files
FileFindHandle_t findHandle;
// generate children
// add all the items
const char *pszFileName = g_pFullFileSystem->FindFirst( pSearchString, &findHandle );
while ( pszFileName )
{
if ( !g_pFullFileSystem->FindIsDirectory( findHandle ) )
{
KeyValues *kv = new KeyValues( "node", "text", pszFileName );
char pFullPath[MAX_PATH];
Q_snprintf( pFullPath, MAX_PATH, "%s\\%s", pFilePath, pszFileName );
kv->SetString( "path", pFullPath );
kv->SetInt( "image", IMAGE_FILE );
AddItem(kv, itemIndex);
kv->deleteThis();
}
pszFileName = g_pFullFileSystem->FindNext( findHandle );
}
g_pFullFileSystem->FindClose( findHandle );
}
//-----------------------------------------------------------------------------
// override to incremental request and show p4 directories
//-----------------------------------------------------------------------------
void CGameFileTreeView::GenerateChildrenOfNode(int itemIndex)
{
KeyValues *pkv = GetItemData(itemIndex);
if ( pkv->GetInt("root") )
{
PopulateRootNode( itemIndex );
return;
}
if (!pkv->GetInt("dir"))
return;
const char *pFilePath = pkv->GetString("path", "");
if (!pFilePath[0])
return;
surface()->SetCursor(dc_waitarrow);
AddDirectoriesOfNode( itemIndex, pFilePath );
if ( m_bUseExt )
{
AddFilesOfNode( itemIndex, pFilePath, m_Ext );
}
}
//-----------------------------------------------------------------------------
// setup a context menu whenever a directory is clicked on
//-----------------------------------------------------------------------------
void CGameFileTreeView::GenerateContextMenu( int itemIndex, int x, int y )
{
return;
/*
KeyValues *pkv = GetItemData(itemIndex);
const char *pFilePath = pkv->GetString("path", "");
if (!pFilePath[0])
return;
Menu *pContext = new Menu(this, "FileContext");
pContext->AddMenuItem("Cloak folder", new KeyValues("CloakFolder", "item", itemIndex), GetParent(), NULL);
// show the context menu
pContext->SetPos(x, y);
pContext->SetVisible(true);
*/
}
//-----------------------------------------------------------------------------
// Sets an item to be colored as if its a menu
//-----------------------------------------------------------------------------
void CGameFileTreeView::SetItemColorForDirectories( int itemID )
{
// mark directories in orange
SetItemFgColor( itemID, Color(224, 192, 0, 255) );
}
//-----------------------------------------------------------------------------
// setup a smaller font
//-----------------------------------------------------------------------------
void CGameFileTreeView::ApplySchemeSettings(IScheme *pScheme)
{
BaseClass::ApplySchemeSettings(pScheme);
SetFont( pScheme->GetFont("DefaultSmall") );
}

View File

@ -0,0 +1,201 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#include "matsys_controls/manipulator.h"
#include "materialsystem/imaterialsystem.h"
#include "vgui/IVGui.h"
#include "vgui/IInput.h"
#include "vgui/ISystem.h"
#include "vgui/MouseCode.h"
#include "mathlib/vector.h"
#include "mathlib/vmatrix.h"
#include "mathlib/mathlib.h"
#include <float.h>
using namespace vgui;
//-----------------------------------------------------------------------------
// local helper functions
//-----------------------------------------------------------------------------
static float UpdateTime( float &flLastTime )
{
float flTime = vgui::system()->GetFrameTime();
float dt = flTime - flLastTime;
flLastTime = flTime;
return dt;
}
//-----------------------------------------------------------------------------
// Base class for manipulators which operate on transforms
//-----------------------------------------------------------------------------
CTransformManipulator::CTransformManipulator( matrix3x4_t *pTransform ) :
m_pTransform( pTransform )
{
}
void CTransformManipulator::SetTransform( matrix3x4_t *pTransform )
{
m_pTransform = pTransform;
}
matrix3x4_t *CTransformManipulator::GetTransform( void )
{
return m_pTransform;
}
//-----------------------------------------------------------------------------
// CPotteryWheelManip - nendo-style camera manipulator
//-----------------------------------------------------------------------------
CPotteryWheelManip::CPotteryWheelManip( matrix3x4_t *pTransform ) :
CTransformManipulator( pTransform ),
m_lastx( -1 ), m_lasty( -1 ),
m_zoom( 100.0f ), m_altitude( 0.0f ), m_azimuth( 0.0f ),
m_prevZoom( 100.0f ), m_prevAltitude( 0.0f ), m_prevAzimuth( 0.0f ),
m_flLastMouseTime( 0.0f ), m_flLastTickTime( 0.0f ),
m_flSpin( 0.0f ), m_bSpin( false )
{
}
void CPotteryWheelManip::OnBeginManipulation( void )
{
m_prevZoom = m_zoom;
m_prevAltitude = m_altitude;
m_prevAzimuth = m_azimuth;
m_flLastMouseTime = m_flLastTickTime = vgui::system()->GetFrameTime();
m_flSpin = 0.0f;
m_bSpin = false;
}
// Sets the zoom level
void CPotteryWheelManip::SetZoom( float flZoom )
{
m_prevZoom = m_zoom = flZoom;
}
void CPotteryWheelManip::OnAcceptManipulation( void )
{
m_flSpin = 0.0f;
m_bSpin = false;
}
void CPotteryWheelManip::OnCancelManipulation( void )
{
m_zoom = m_prevZoom;
m_altitude = m_prevAltitude;
m_azimuth = m_prevAzimuth;
m_flSpin = 0.0f;
m_bSpin = false;
UpdateTransform();
}
void CPotteryWheelManip::OnTick( void )
{
float dt = UpdateTime( m_flLastTickTime );
if ( m_bSpin )
{
m_azimuth += dt * m_flSpin;
UpdateTransform();
}
}
void CPotteryWheelManip::OnCursorMoved( int x, int y )
{
float dt = UpdateTime( m_flLastMouseTime );
if ( m_bSpin )
{
m_lastx = x;
m_lasty = y;
return;
}
if ( input()->IsMouseDown( MOUSE_MIDDLE ) )
{
int dy = y - m_lasty;
int dx = x - m_lastx;
if ( abs( dx ) < 2 * abs( dy ) )
{
UpdateZoom( 0.2f * dy );
}
else
{
m_flSpin = (dt != 0.0f) ? 0.002f * dx / dt : 0.0f;
m_azimuth += 0.002f * dx;
}
}
else
{
m_azimuth += 0.002f * ( x - m_lastx );
m_altitude -= 0.002f * ( y - m_lasty );
m_altitude = max( (float)-M_PI/2, min( (float)M_PI/2, m_altitude ) );
}
m_lastx = x;
m_lasty = y;
UpdateTransform();
}
void CPotteryWheelManip::OnMousePressed( vgui::MouseCode code, int x, int y )
{
UpdateTime( m_flLastMouseTime );
m_lastx = x;
m_lasty = y;
m_bSpin = false;
m_flSpin = 0.0f;
}
void CPotteryWheelManip::OnMouseReleased( vgui::MouseCode code, int x, int y )
{
UpdateTime( m_flLastMouseTime );
if ( code == MOUSE_MIDDLE )
{
m_bSpin = ( fabs( m_flSpin ) > 1.0f );
}
m_lastx = x;
m_lasty = y;
}
void CPotteryWheelManip::OnMouseWheeled( int delta )
{
UpdateTime( m_flLastMouseTime );
UpdateZoom( -10.0f * delta );
UpdateTransform();
}
void CPotteryWheelManip::UpdateTransform()
{
if ( !m_pTransform )
return;
float y = m_zoom * sin( m_altitude );
float xz = m_zoom * cos( m_altitude );
float x = xz * sin( m_azimuth );
float z = xz * cos( m_azimuth );
Vector position(x, y, z);
AngleMatrix( RadianEuler( -m_altitude, m_azimuth, 0 ), position, *m_pTransform );
}
void CPotteryWheelManip::UpdateZoom( float delta )
{
m_zoom *= pow( 1.01f, delta );
}

View File

@ -0,0 +1,66 @@
//-----------------------------------------------------------------------------
// MATSYS_CONTROLS.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$macro SRCDIR "..\.."
$include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
$Project "matsys_controls"
{
$Folder "Source Files"
{
$File "assetpicker.cpp"
$File "baseassetpicker.cpp"
$File "colorpickerpanel.cpp"
$File "curveeditorpanel.cpp"
$File "gamefiletreeview.cpp"
$File "manipulator.cpp"
$File "matsyscontrols.cpp"
$File "mdlpanel.cpp"
$File "mdlpicker.cpp"
$File "mdlsequencepicker.cpp"
$File "picker.cpp"
$File "potterywheelpanel.cpp"
$File "proceduraltexturepanel.cpp"
$File "QCGenerator.cpp"
$File "sequencepicker.cpp"
$File "tgapreviewpanel.cpp"
$File "vmtpicker.cpp"
$File "vmtpreviewpanel.cpp"
$File "vtfpicker.cpp"
$File "vtfpreviewpanel.cpp"
$File "vmtpanel.cpp"
}
$Folder "Header Files"
{
$File "$SRCDIR\public\matsys_controls\assetpicker.h"
$File "$SRCDIR\public\matsys_controls\baseassetpicker.h"
$File "$SRCDIR\public\matsys_controls\colorpickerpanel.h"
$File "$SRCDIR\public\matsys_controls\gamefiletreeview.h"
$File "$SRCDIR\public\matsys_controls\manipulator.h"
$File "$SRCDIR\public\matsys_controls\matsyscontrols.h"
$File "$SRCDIR\public\matsys_controls\mdlpanel.h"
$File "$SRCDIR\public\matsys_controls\mdlpicker.h"
$File "$SRCDIR\public\matsys_controls\mdlsequencepicker.h"
$File "$SRCDIR\public\matsys_controls\picker.h"
$File "$SRCDIR\public\matsys_controls\potterywheelpanel.h"
$File "$SRCDIR\public\matsys_controls\proceduraltexturepanel.h"
$File "$SRCDIR\public\matsys_controls\QCGenerator.h"
$File "$SRCDIR\public\matsys_controls\sequencepicker.h"
$File "$SRCDIR\public\matsys_controls\tgapreviewpanel.h"
$File "$SRCDIR\public\matsys_controls\vmtpicker.h"
$File "$SRCDIR\public\matsys_controls\vmtpreviewpanel.h"
$File "$SRCDIR\public\matsys_controls\vtfpicker.h"
$File "$SRCDIR\public\matsys_controls\vtfpreviewpanel.h"
$File "$SRCDIR\public\matsys_controls\vmtpanel.h"
}
$Folder "Link Libraries"
{
$Lib bitmap [$WIN32]
}
}

View File

@ -0,0 +1,100 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "matsys_controls/matsyscontrols.h"
#include <materialsystem/imaterialsystem.h>
#include <materialsystem/imaterialsystemhardwareconfig.h>
#include <datacache/imdlcache.h>
#include <VGuiMatSurface/IMatSystemSurface.h>
#include <istudiorender.h>
#include "vgui_controls/Controls.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
namespace vgui
{
IMaterialSystem *g_pMaterialSystem = NULL;
IMaterialSystem *MaterialSystem()
{
return g_pMaterialSystem;
}
IMaterialSystemHardwareConfig *g_pMaterialSystemHardwareConfig = NULL;
IMaterialSystemHardwareConfig *MaterialSystemHardwareConfig()
{
return g_pMaterialSystemHardwareConfig;
}
IMDLCache *g_pMDLCache = NULL;
IMDLCache *MDLCache()
{
return g_pMDLCache;
}
IMatSystemSurface *g_pMatSystemSurface = NULL;
IMatSystemSurface *MatSystemSurface()
{
return g_pMatSystemSurface;
}
IStudioRender *g_pStudioRender = NULL;
IStudioRender *StudioRender()
{
return g_pStudioRender;
}
//-----------------------------------------------------------------------------
// Purpose: finds a particular interface in the factory set
//-----------------------------------------------------------------------------
static void *InitializeInterface( char const *interfaceName, CreateInterfaceFn *factoryList, int numFactories )
{
void *retval;
for ( int i = 0; i < numFactories; i++ )
{
CreateInterfaceFn factory = factoryList[ i ];
if ( !factory )
continue;
retval = factory( interfaceName, NULL );
if ( retval )
return retval;
}
// No provider for requested interface!!!
// Assert( !"No provider for requested interface!!!" );
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Initializes the controls
//-----------------------------------------------------------------------------
bool VGui_InitMatSysInterfacesList( const char *moduleName, CreateInterfaceFn *factoryList, int numFactories )
{
if ( !vgui::VGui_InitInterfacesList( moduleName, factoryList, numFactories ) )
return false;
g_pMaterialSystem = (IMaterialSystem *)InitializeInterface( MATERIAL_SYSTEM_INTERFACE_VERSION, factoryList, numFactories );
g_pMatSystemSurface = (IMatSystemSurface *)InitializeInterface( MAT_SYSTEM_SURFACE_INTERFACE_VERSION, factoryList, numFactories );
g_pMDLCache = (IMDLCache *)InitializeInterface( MDLCACHE_INTERFACE_VERSION, factoryList, numFactories );
g_pStudioRender = (IStudioRender *)InitializeInterface( STUDIO_RENDER_INTERFACE_VERSION, factoryList, numFactories );
g_pMaterialSystemHardwareConfig = (IMaterialSystemHardwareConfig *)InitializeInterface( MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION, factoryList, numFactories );
// MDL cache + studiorender are optional
return ( g_pMaterialSystem && g_pMatSystemSurface && g_pMaterialSystemHardwareConfig );
}
} // namespace vgui

View File

@ -0,0 +1,981 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "matsys_controls/mdlpanel.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"
#include "materialsystem/imesh.h"
#include "vgui/IVGui.h"
#include "tier1/KeyValues.h"
#include "vgui_controls/Frame.h"
#include "tier1/convar.h"
#include "tier0/dbg.h"
#include "tier1/fmtstr.h"
#include "istudiorender.h"
#include "matsys_controls/matsyscontrols.h"
#include "vcollide.h"
#include "vcollide_parse.h"
#include "bone_setup.h"
#include "vphysics_interface.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
DECLARE_BUILD_FACTORY( CMDLPanel );
static const int THUMBNAIL_SAFE_ZONE_SIZE = 512;
static const int THUMBNAIL_SAFE_ZONE_HEIGHT = 92;
static const float THUMBNAIL_SAFE_ZONE_HEIGHT_SCALE = (float)THUMBNAIL_SAFE_ZONE_HEIGHT / THUMBNAIL_SAFE_ZONE_SIZE;
//-----------------------------------------------------------------------------
// Purpose: Keeps a global clock to autoplay sequences to run from
// Also deals with speedScale changes
//-----------------------------------------------------------------------------
float GetAutoPlayTime( void )
{
static int g_prevTicks;
static float g_time;
int ticks = Plat_MSTime();
// limit delta so that float time doesn't overflow
if (g_prevTicks == 0)
{
g_prevTicks = ticks;
}
g_time += ( ticks - g_prevTicks ) / 1000.0f;
g_prevTicks = ticks;
return g_time;
}
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CMDLPanel::CMDLPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName )
{
SetVisible( true );
// Used to poll input
vgui::ivgui()->AddTickSignal( GetVPanel() );
// Deal with the default cubemap
ITexture *pCubemapTexture = vgui::MaterialSystem()->FindTexture( "editor/cubemap", NULL, true );
m_DefaultEnvCubemap.Init( pCubemapTexture );
pCubemapTexture = vgui::MaterialSystem()->FindTexture( "editor/cubemap.hdr", NULL, true );
m_DefaultHDREnvCubemap.Init( pCubemapTexture );
SetIdentityMatrix( m_RootMDL.m_MDLToWorld );
m_RootMDL.m_pStudioHdr = NULL;
m_RootMDL.m_unMdlCacheSerial = 0;
m_bDrawCollisionModel = false;
m_bWireFrame = false;
m_bGroundGrid = false;
m_bLockView = false;
m_bLookAtCamera = true;
m_bThumbnailSafeZone = false;
m_nNumSequenceLayers = 0;
ResetAnimationEventState( &m_EventState );
}
CMDLPanel::~CMDLPanel()
{
m_aMergeMDLs.Purge();
m_DefaultEnvCubemap.Shutdown( );
m_DefaultHDREnvCubemap.Shutdown();
if ( m_RootMDL.m_pStudioHdr )
{
delete m_RootMDL.m_pStudioHdr;
m_RootMDL.m_pStudioHdr = NULL;
}
}
//-----------------------------------------------------------------------------
// Scheme settings
//-----------------------------------------------------------------------------
void CMDLPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
SetBackgroundColor( GetBgColor() );
SetBorder( pScheme->GetBorder( "MenuBorder") );
}
//-----------------------------------------------------------------------------
// Rendering options
//-----------------------------------------------------------------------------
void CMDLPanel::SetCollsionModel( bool bVisible )
{
m_bDrawCollisionModel = bVisible;
}
void CMDLPanel::SetGroundGrid( bool bVisible )
{
m_bGroundGrid = bVisible;
}
void CMDLPanel::SetWireFrame( bool bVisible )
{
m_bWireFrame = bVisible;
}
void CMDLPanel::SetLockView( bool bLocked )
{
m_bLockView = bLocked;
}
void CMDLPanel::SetLookAtCamera( bool bLookAtCamera )
{
m_bLookAtCamera = bLookAtCamera;
}
void CMDLPanel::SetIgnoreDoubleClick( bool bState )
{
m_bIgnoreDoubleClick = bState;
}
void CMDLPanel::SetThumbnailSafeZone( bool bVisible )
{
m_bThumbnailSafeZone = bVisible;
}
//-----------------------------------------------------------------------------
// Stores the clip
//-----------------------------------------------------------------------------
void CMDLPanel::SetMDL( MDLHandle_t handle, void *pProxyData )
{
m_RootMDL.m_MDL.SetMDL( handle );
if ( m_RootMDL.m_pStudioHdr )
{
delete m_RootMDL.m_pStudioHdr;
}
m_RootMDL.m_pStudioHdr = new CStudioHdr( m_RootMDL.m_MDL.GetStudioHdr(), g_pMDLCache );
m_RootMDL.m_MDL.m_pProxyData = pProxyData;
Vector vecMins, vecMaxs;
GetMDLBoundingBox( &vecMins, &vecMaxs, handle, m_RootMDL.m_MDL.m_nSequence );
m_RootMDL.m_MDL.m_bWorldSpaceViewTarget = false;
m_RootMDL.m_MDL.m_vecViewTarget.Init( 100.0f, 0.0f, vecMaxs.z );
m_RootMDL.m_flCycleStartTime = 0.f;
// Set the pose parameters to the default for the mdl
SetPoseParameters( NULL, 0 );
// Clear any sequence layers
SetSequenceLayers( NULL, 0 );
ResetAnimationEventState( &m_EventState );
}
//-----------------------------------------------------------------------------
// An MDL was selected
//-----------------------------------------------------------------------------
void CMDLPanel::SetMDL( const char *pMDLName, void *pProxyData )
{
MDLHandle_t hMDLFindResult = vgui::MDLCache()->FindMDL( pMDLName );
MDLHandle_t hMDL = pMDLName ? hMDLFindResult : MDLHANDLE_INVALID;
if ( vgui::MDLCache()->IsErrorModel( hMDL ) )
{
hMDL = MDLHANDLE_INVALID;
}
SetMDL( hMDL, pProxyData );
// FindMDL takes a reference and the the CMDL will also hold a reference for as long as it sticks around. Release the FindMDL reference.
int nRef = vgui::MDLCache()->Release( hMDLFindResult );
(void)nRef; // Avoid unreferenced variable warning
AssertMsg( hMDL == MDLHANDLE_INVALID || nRef > 0, "CMDLPanel::SetMDL referenced a model that has a zero ref count." );
}
//-----------------------------------------------------------------------------
// Purpose: Returns a model bounding box.
//-----------------------------------------------------------------------------
bool CMDLPanel::GetBoundingBox( Vector &vecBoundsMin, Vector &vecBoundsMax )
{
// Check to see if we have a valid model to look at.
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
return false;
GetMDLBoundingBox( &vecBoundsMin, &vecBoundsMax, m_RootMDL.m_MDL.GetMDL(), m_RootMDL.m_MDL.m_nSequence );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Returns a more accurate bounding sphere
//-----------------------------------------------------------------------------
bool CMDLPanel::GetBoundingSphere( Vector &vecCenter, float &flRadius )
{
// Check to see if we have a valid model to look at.
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
return false;
Vector vecEngineCenter;
GetMDLBoundingSphere( &vecEngineCenter, &flRadius, m_RootMDL.m_MDL.GetMDL(), m_RootMDL.m_MDL.m_nSequence );
VectorTransform( vecEngineCenter, m_RootMDL.m_MDLToWorld, vecCenter );
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos )
{
SetIdentityMatrix( m_RootMDL.m_MDLToWorld );
AngleMatrix( angRot, vecPos, m_RootMDL.m_MDLToWorld );
}
//-----------------------------------------------------------------------------
// Sets the camera to look at the model
//-----------------------------------------------------------------------------
void CMDLPanel::LookAtMDL()
{
// Check to see if we have a valid model to look at.
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
return;
if ( m_bLockView )
return;
float flRadius;
Vector vecCenter;
GetBoundingSphere( vecCenter, flRadius );
LookAt( vecCenter, flRadius );
}
//-----------------------------------------------------------------------------
// FIXME: This should be moved into studiorender
//-----------------------------------------------------------------------------
static ConVar r_showenvcubemap( "r_showenvcubemap", "0", FCVAR_CHEAT );
static ConVar r_eyegloss ( "r_eyegloss", "1", FCVAR_ARCHIVE ); // wet eyes
static ConVar r_eyemove ( "r_eyemove", "1", FCVAR_ARCHIVE ); // look around
static ConVar r_eyeshift_x ( "r_eyeshift_x", "0", FCVAR_ARCHIVE ); // eye X position
static ConVar r_eyeshift_y ( "r_eyeshift_y", "0", FCVAR_ARCHIVE ); // eye Y position
static ConVar r_eyeshift_z ( "r_eyeshift_z", "0", FCVAR_ARCHIVE ); // eye Z position
static ConVar r_eyesize ( "r_eyesize", "0", FCVAR_ARCHIVE ); // adjustment to iris textures
static ConVar mat_softwareskin( "mat_softwareskin", "0", FCVAR_CHEAT );
static ConVar r_nohw ( "r_nohw", "0", FCVAR_CHEAT );
static ConVar r_nosw ( "r_nosw", "0", FCVAR_CHEAT );
static ConVar r_teeth ( "r_teeth", "1" );
static ConVar r_drawentities ( "r_drawentities", "1", FCVAR_CHEAT );
static ConVar r_flex ( "r_flex", "1" );
static ConVar r_eyes ( "r_eyes", "1" );
static ConVar r_skin ( "r_skin","0", FCVAR_CHEAT );
static ConVar r_maxmodeldecal ( "r_maxmodeldecal", "50" );
static ConVar r_modelwireframedecal ( "r_modelwireframedecal", "0", FCVAR_CHEAT );
static ConVar mat_normals ( "mat_normals", "0", FCVAR_CHEAT );
static ConVar r_eyeglintlodpixels ( "r_eyeglintlodpixels", "0", FCVAR_CHEAT );
static ConVar r_rootlod ( "r_rootlod", "0" );
static StudioRenderConfig_t s_StudioRenderConfig;
void CMDLPanel::UpdateStudioRenderConfig( void )
{
memset( &s_StudioRenderConfig, 0, sizeof(s_StudioRenderConfig) );
s_StudioRenderConfig.bEyeMove = !!r_eyemove.GetInt();
s_StudioRenderConfig.fEyeShiftX = r_eyeshift_x.GetFloat();
s_StudioRenderConfig.fEyeShiftY = r_eyeshift_y.GetFloat();
s_StudioRenderConfig.fEyeShiftZ = r_eyeshift_z.GetFloat();
s_StudioRenderConfig.fEyeSize = r_eyesize.GetFloat();
if( mat_softwareskin.GetInt() || m_bWireFrame )
{
s_StudioRenderConfig.bSoftwareSkin = true;
}
else
{
s_StudioRenderConfig.bSoftwareSkin = false;
}
s_StudioRenderConfig.bNoHardware = !!r_nohw.GetInt();
s_StudioRenderConfig.bNoSoftware = !!r_nosw.GetInt();
s_StudioRenderConfig.bTeeth = !!r_teeth.GetInt();
s_StudioRenderConfig.drawEntities = r_drawentities.GetInt();
s_StudioRenderConfig.bFlex = !!r_flex.GetInt();
s_StudioRenderConfig.bEyes = !!r_eyes.GetInt();
s_StudioRenderConfig.bWireframe = m_bWireFrame;
s_StudioRenderConfig.bDrawNormals = mat_normals.GetBool();
s_StudioRenderConfig.skin = r_skin.GetInt();
s_StudioRenderConfig.maxDecalsPerModel = r_maxmodeldecal.GetInt();
s_StudioRenderConfig.bWireframeDecals = r_modelwireframedecal.GetInt() != 0;
s_StudioRenderConfig.fullbright = false;
s_StudioRenderConfig.bSoftwareLighting = false;
s_StudioRenderConfig.bShowEnvCubemapOnly = r_showenvcubemap.GetInt() ? true : false;
s_StudioRenderConfig.fEyeGlintPixelWidthLODThreshold = r_eyeglintlodpixels.GetFloat();
StudioRender()->UpdateConfig( s_StudioRenderConfig );
}
void CMDLPanel::DrawCollisionModel()
{
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
{
return;
}
vcollide_t *pCollide = MDLCache()->GetVCollide( m_RootMDL.m_MDL.GetMDL() );
if ( !pCollide || pCollide->solidCount <= 0 )
return;
static color32 color = {255,0,0,0};
IVPhysicsKeyParser *pParser = g_pPhysicsCollision->VPhysicsKeyParserCreate( pCollide->pKeyValues );
CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr;
matrix3x4_t pBoneToWorld[MAXSTUDIOBONES];
m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, MAXSTUDIOBONES, pBoneToWorld );
// PERFORMANCE: Just parse the script each frame. It's fast enough for tools. If you need
// this to go faster then cache off the bone index mapping in an array like HLMV does
while ( !pParser->Finished() )
{
const char *pBlock = pParser->GetCurrentBlockName();
if ( !stricmp( pBlock, "solid" ) )
{
solid_t solid;
pParser->ParseSolid( &solid, NULL );
int boneIndex = Studio_BoneIndexByName( &studioHdr, solid.name );
Vector *outVerts;
int vertCount = g_pPhysicsCollision->CreateDebugMesh( pCollide->solids[solid.index], &outVerts );
if ( vertCount )
{
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
// NOTE: assumes these have been set up already by the model render code
// So this is a little bit of a back door to a cache of the bones
// this code wouldn't work unless you draw the model this frame before calling
// this routine. CMDLPanel always does this, but it's worth noting.
// A better solution would be to move the ragdoll visulization into the CDmeMdl
// and either draw it there or make it queryable and query/draw here.
matrix3x4_t xform;
SetIdentityMatrix( xform );
if ( boneIndex >= 0 )
{
MatrixCopy( pBoneToWorld[ boneIndex ], xform );
}
IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_Wireframe );
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, vertCount/3 );
for ( int j = 0; j < vertCount; j++ )
{
Vector out;
VectorTransform( outVerts[j].Base(), xform, out.Base() );
meshBuilder.Position3fv( out.Base() );
meshBuilder.Color4ub( color.r, color.g, color.b, color.a );
meshBuilder.TexCoord2f( 0, 0, 0 );
meshBuilder.AdvanceVertex();
}
meshBuilder.End();
pMesh->Draw();
}
g_pPhysicsCollision->DestroyDebugMesh( vertCount, outVerts );
}
else
{
pParser->SkipBlock();
}
}
g_pPhysicsCollision->VPhysicsKeyParserDestroy( pParser );
}
void CMDLPanel::SetupRenderState( int nDisplayWidth, int nDisplayHeight )
{
int iWidth = nDisplayWidth;
int iHeight = nDisplayHeight;
if ( m_bThumbnailSafeZone )
{
iWidth = THUMBNAIL_SAFE_ZONE_SIZE;
iHeight = THUMBNAIL_SAFE_ZONE_SIZE;
}
BaseClass::SetupRenderState( iWidth, iHeight );
}
//-----------------------------------------------------------------------------
// paint it!
//-----------------------------------------------------------------------------
void CMDLPanel::OnPaint3D()
{
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
return;
// FIXME: Move this call into DrawModel in StudioRender
StudioRenderConfig_t oldStudioRenderConfig;
StudioRender()->GetCurrentConfig( oldStudioRenderConfig );
UpdateStudioRenderConfig();
CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() );
if ( vgui::MaterialSystemHardwareConfig()->GetHDRType() == HDR_TYPE_NONE )
{
ITexture *pMyCube = HasLightProbe() ? GetLightProbeCubemap( false ) : m_DefaultEnvCubemap;
pRenderContext->BindLocalCubemap( pMyCube );
}
else
{
ITexture *pMyCube = HasLightProbe() ? GetLightProbeCubemap( true ) : m_DefaultHDREnvCubemap;
pRenderContext->BindLocalCubemap( pMyCube );
}
PrePaint3D( pRenderContext );
if ( m_bGroundGrid )
{
DrawGrid();
}
if ( m_bLookAtCamera )
{
matrix3x4_t worldToCamera;
ComputeCameraTransform( &worldToCamera );
Vector vecPosition;
MatrixGetColumn( worldToCamera, 3, vecPosition );
m_RootMDL.m_MDL.m_bWorldSpaceViewTarget = true;
m_RootMDL.m_MDL.m_vecViewTarget = vecPosition;
}
// Draw the MDL
CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr;
SetupFlexWeights();
matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( studioHdr.numbones() );
m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, studioHdr.numbones(), pBoneToWorld, m_PoseParameters, m_SequenceLayers, m_nNumSequenceLayers );
g_pStudioRender->UnlockBoneMatrices();
IMaterial* pOverrideMaterial = GetOverrideMaterial( m_RootMDL.m_MDL.GetMDL() );
if ( pOverrideMaterial != NULL )
g_pStudioRender->ForcedMaterialOverride( pOverrideMaterial );
m_RootMDL.m_MDL.Draw( m_RootMDL.m_MDLToWorld, pBoneToWorld );
if ( pOverrideMaterial != NULL )
g_pStudioRender->ForcedMaterialOverride( NULL );
pOverrideMaterial = NULL;
// Draw the merge MDLs.
matrix3x4_t matMergeBoneToWorld[MAXSTUDIOBONES];
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[iMerge].m_bDisabled )
continue;
// Get the merge studio header.
CStudioHdr *pMergeHdr = m_aMergeMDLs[iMerge].m_pStudioHdr;
matrix3x4_t *pMergeBoneToWorld = &matMergeBoneToWorld[0];
// If we have a valid mesh, bonemerge it. If we have an invalid mesh we can't bonemerge because
// it'll crash trying to pull data from the missing header.
if ( pMergeHdr != NULL )
{
CStudioHdr &mergeHdr = *pMergeHdr;
m_aMergeMDLs[iMerge].m_MDL.SetupBonesWithBoneMerge( &mergeHdr, pMergeBoneToWorld, &studioHdr, pBoneToWorld, m_RootMDL.m_MDLToWorld );
pOverrideMaterial = GetOverrideMaterial( m_aMergeMDLs[iMerge].m_MDL.GetMDL() );
if ( pOverrideMaterial != NULL )
g_pStudioRender->ForcedMaterialOverride( pOverrideMaterial );
m_aMergeMDLs[iMerge].m_MDL.Draw( m_aMergeMDLs[iMerge].m_MDLToWorld, pMergeBoneToWorld );
if ( pOverrideMaterial != NULL )
g_pStudioRender->ForcedMaterialOverride( NULL );
// Notify of model render
RenderingMergedModel( pRenderContext, &mergeHdr, m_aMergeMDLs[iMerge].m_MDL.GetMDL(), pMergeBoneToWorld );
}
}
RenderingRootModel( pRenderContext, &studioHdr, m_RootMDL.m_MDL.GetMDL(), pBoneToWorld );
PostPaint3D( pRenderContext );
if ( m_bDrawCollisionModel )
{
DrawCollisionModel();
}
pRenderContext->Flush();
StudioRender()->UpdateConfig( oldStudioRenderConfig );
}
//-----------------------------------------------------------------------------
// Sets the current LOD
//-----------------------------------------------------------------------------
void CMDLPanel::SetLOD( int nLOD )
{
m_RootMDL.m_MDL.m_nLOD = nLOD;
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
m_aMergeMDLs[iMerge].m_MDL.m_nLOD = nLOD;
}
}
//-----------------------------------------------------------------------------
// Sets the current sequence
//-----------------------------------------------------------------------------
void CMDLPanel::SetSequence( int nSequence, bool bResetSequence )
{
m_RootMDL.m_MDL.m_nSequence = nSequence;
if ( bResetSequence )
{
m_RootMDL.m_flCycleStartTime = GetAutoPlayTime();
}
}
//-----------------------------------------------------------------------------
// Set the current pose parameters. If NULL the pose parameters will be reset
// to the default values.
//-----------------------------------------------------------------------------
void CMDLPanel::SetPoseParameters( const float *pPoseParameters, int nCount )
{
if ( pPoseParameters )
{
int nParameters = MIN( MAXSTUDIOPOSEPARAM, nCount );
for ( int iParam = 0; iParam < nParameters; ++iParam )
{
m_PoseParameters[ iParam ] = pPoseParameters[ iParam ];
}
}
else if ( m_RootMDL.m_MDL.GetMDL() != MDLHANDLE_INVALID )
{
CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr;
Studio_CalcDefaultPoseParameters( &studioHdr, m_PoseParameters, MAXSTUDIOPOSEPARAM );
}
}
//-----------------------------------------------------------------------------
// Set a pose parameter by name
//-----------------------------------------------------------------------------
bool CMDLPanel::SetPoseParameterByName( const char *pszName, float fValue )
{
if ( !m_RootMDL.m_pStudioHdr )
return false;
CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr;
int nPoseCount = studioHdr.GetNumPoseParameters();
for ( int i = 0; i < nPoseCount; ++i )
{
const mstudioposeparamdesc_t &Pose = studioHdr.pPoseParameter( i );
if ( V_strcasecmp( pszName, Pose.pszName() ) == 0 )
{
m_PoseParameters[ i ] = fValue;
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Set the overlay sequence layers
//-----------------------------------------------------------------------------
void CMDLPanel::SetSequenceLayers( const MDLSquenceLayer_t *pSequenceLayers, int nCount )
{
if ( pSequenceLayers )
{
m_nNumSequenceLayers = MIN( MAX_SEQUENCE_LAYERS, nCount );
for ( int iLayer = 0; iLayer < m_nNumSequenceLayers; ++iLayer )
{
m_SequenceLayers[ iLayer ] = pSequenceLayers[ iLayer ];
ResetAnimationEventState( &m_SequenceLayerEventState[ iLayer ] );
}
}
else
{
m_nNumSequenceLayers = 0;
V_memset( m_SequenceLayers, 0, sizeof( m_SequenceLayers ) );
}
}
//-----------------------------------------------------------------------------
// Set the current skin
//-----------------------------------------------------------------------------
void CMDLPanel::SetSkin( int nSkin )
{
m_RootMDL.m_MDL.m_nSkin = nSkin;
}
//-----------------------------------------------------------------------------
// called when we're ticked...
//-----------------------------------------------------------------------------
void CMDLPanel::OnTick()
{
BaseClass::OnTick();
if ( m_RootMDL.m_MDL.GetMDL() != MDLHANDLE_INVALID )
{
ValidateMDLs();
m_RootMDL.m_MDL.m_flTime = ( GetAutoPlayTime() - m_RootMDL.m_flCycleStartTime );
DoAnimationEvents();
}
}
void CMDLPanel::Paint()
{
BaseClass::Paint();
if ( m_bThumbnailSafeZone )
{
int iWidth, iHeight;
GetSize( iWidth, iHeight );
CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() );
IMaterial *safezone = materials->FindMaterial( "vgui/thumbnails_safezone", TEXTURE_GROUP_VGUI, true );
if ( safezone )
{
safezone->IncrementReferenceCount();
}
int screenposx = 0;
int screenposy = 0;
LocalToScreen( screenposx, screenposy );
int iScaledHeight = THUMBNAIL_SAFE_ZONE_HEIGHT_SCALE * iHeight;
int iRemappedHeight = RemapVal( iScaledHeight, 0, THUMBNAIL_SAFE_ZONE_HEIGHT, 0, iScaledHeight );
pRenderContext->DrawScreenSpaceRectangle( safezone, screenposx, screenposy, iWidth, iRemappedHeight,
0, 0,
THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_HEIGHT,
THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_SIZE );
screenposx = 0;
screenposy = iHeight - iRemappedHeight;
LocalToScreen( screenposx, screenposy );
pRenderContext->DrawScreenSpaceRectangle( safezone, screenposx, screenposy, iWidth, iRemappedHeight,
0, 0,
THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_HEIGHT,
THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_SIZE );
if ( safezone )
{
safezone->DecrementReferenceCount();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::DoAnimationEvents()
{
if ( !m_RootMDL.m_pStudioHdr )
return;
CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr;
// If we don't have any sequences, don't do anything
if ( studioHdr.GetNumSeq() < 1 )
{
Assert( studioHdr.GetNumSeq() >= 1 );
return;
}
// we're holding onto model data that can be forced reloaded when importing workshop items
// detect the vmodel change here and force an update if so, until we fix the real issue of the studioHdr not being updated itself
if ( studioHdr.GetVirtualModel() != nullptr && studioHdr.GetVirtualModel() != studioHdr.GetRenderHdr()->GetVirtualModel() )
{
studioHdr.ResetVModel( studioHdr.GetRenderHdr()->GetVirtualModel() );
}
DoAnimationEvents( &studioHdr, m_RootMDL.m_MDL.m_nSequence, m_RootMDL.m_MDL.m_flTime, false, &m_EventState );
for ( int i = 0; i < m_nNumSequenceLayers; ++i )
{
float flTime = m_RootMDL.m_MDL.m_flTime - m_SequenceLayers[ i ].m_flCycleBeganAt;
//Plat_DebugString( CFmtStr("Animation: time = %f, started = %f, delta = %f\n",m_RootMDL.m_MDL.m_flTime,m_SequenceLayers[ i ].m_flCycleBeganAt,flTime ) );
DoAnimationEvents( &studioHdr, m_SequenceLayers[ i ].m_nSequenceIndex, flTime, m_SequenceLayers[ i ].m_bNoLoop, &m_SequenceLayerEventState[ i ] );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::DoAnimationEvents( CStudioHdr *pStudioHdr, int nSeqNum, float flTime, bool bNoLoop, MDLAnimEventState_t *pEventState )
{
if ( nSeqNum < 0 || nSeqNum >= pStudioHdr->GetNumSeq() )
{
return;
}
mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSeqNum );
if ( seqdesc.numevents == 0 )
{
return;
}
mstudioevent_t *pevent = seqdesc.pEvent( 0 );
int nFrameCount = Studio_MaxFrame( pStudioHdr, nSeqNum, m_PoseParameters );
if ( nFrameCount == 0 )
{
nFrameCount = 1;
}
float flEventCycle = ( flTime * m_RootMDL.m_MDL.m_flPlaybackRate ) / nFrameCount;
//Plat_DebugString( CFmtStr("Event cycle: %f, playback rate: %f, frame count: %d\n", flEventCycle, m_RootMDL.m_MDL.m_flPlaybackRate, nFrameCount ) );
if ( bNoLoop )
{
flEventCycle = MIN(flEventCycle, 1.0f);
}
else
{
flEventCycle -= (int)(flEventCycle);
}
if ( pEventState->m_nEventSequence != nSeqNum )
{
pEventState->m_nEventSequence = nSeqNum;
flEventCycle = 0.0f;
pEventState->m_flPrevEventCycle = -0.01f; // back up to get 0'th frame animations
}
if ( flEventCycle == pEventState->m_flPrevEventCycle )
{
return;
}
// check for looping
BOOL bLooped = (flEventCycle < pEventState->m_flPrevEventCycle);
// This makes sure events that occur at the end of a sequence occur are
// sent before events that occur at the beginning of a sequence.
if (bLooped)
{
for (int i = 0; i < (int)seqdesc.numevents; i++)
{
if ( pevent[i].cycle <= pEventState->m_flPrevEventCycle )
continue;
FireEvent( pevent[ i ].pszEventName(), pevent[ i ].pszOptions() );
}
// Necessary to get the next loop working
pEventState->m_flPrevEventCycle = -0.01f;
}
for (int i = 0; i < (int)seqdesc.numevents; i++)
{
if ( (pevent[i].cycle > pEventState->m_flPrevEventCycle && pevent[i].cycle <= flEventCycle) )
{
FireEvent( pevent[ i ].pszEventName(), pevent[ i ].pszOptions() );
}
}
pEventState->m_flPrevEventCycle = flEventCycle;
}
void CMDLPanel::FireEvent( const char *pszEventName, const char *pszEventOptions )
{
KeyValues* pKVEvent = new KeyValues( "AnimEvent" );
pKVEvent->SetString( "name", pszEventName );
pKVEvent->SetString( "options", pszEventOptions );
PostActionSignal( pKVEvent );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::ResetAnimationEventState( MDLAnimEventState_t *pEventState )
{
pEventState->m_nEventSequence = -1;
pEventState->m_flPrevEventCycle = -0.01f;
}
//-----------------------------------------------------------------------------
// input
//-----------------------------------------------------------------------------
void CMDLPanel::OnMouseDoublePressed( vgui::MouseCode code )
{
if ( m_bIgnoreDoubleClick )
return;
float flRadius;
Vector vecCenter;
GetBoundingSphere( vecCenter, flRadius );
LookAt( vecCenter, flRadius );
BaseClass::OnMouseDoublePressed( code );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::SetMergeMDL( MDLHandle_t handle, void *pProxyData, int nSkin /*= -1 */ )
{
// Verify that we have a root model to merge to.
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
return;
int iIndex = m_aMergeMDLs.AddToTail();
if ( !m_aMergeMDLs.IsValidIndex( iIndex ) )
return;
m_aMergeMDLs[iIndex].m_MDL.SetMDL( handle );
if ( nSkin != -1 )
{
m_aMergeMDLs[iIndex].m_MDL.m_nSkin = nSkin;
}
m_aMergeMDLs[iIndex].m_MDL.m_nLOD = m_RootMDL.m_MDL.m_nLOD;
m_aMergeMDLs[iIndex].m_MDL.m_pProxyData = pProxyData;
SetIdentityMatrix( m_aMergeMDLs[iIndex].m_MDLToWorld );
m_aMergeMDLs[iIndex].m_bDisabled = false;
m_aMergeMDLs[iIndex].m_pStudioHdr = new CStudioHdr( m_aMergeMDLs[iIndex].m_MDL.GetStudioHdr(), g_pMDLCache );
// Need to invalidate the layout so the panel will adjust is LookAt for the new model.
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
MDLHandle_t CMDLPanel::SetMergeMDL( const char *pMDLName, void *pProxyData, int nSkin /*= -1 */ )
{
MDLHandle_t hMDLFindResult = vgui::MDLCache()->FindMDL( pMDLName );
MDLHandle_t hMDL = pMDLName ? hMDLFindResult : MDLHANDLE_INVALID;
if ( vgui::MDLCache()->IsErrorModel( hMDL ) )
{
hMDL = MDLHANDLE_INVALID;
}
SetMergeMDL( hMDL, pProxyData, nSkin );
// FindMDL takes a reference and the the CMDL will also hold a reference for as long as it sticks around. Release the FindMDL reference.
int nRef = vgui::MDLCache()->Release( hMDLFindResult );
(void)nRef; // Avoid unreferenced variable warning
AssertMsg( hMDL == MDLHANDLE_INVALID || nRef > 0, "CMDLPanel::SetMergeMDL referenced a model that has a zero ref count." );
return hMDL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CMDLPanel::GetMergeMDLIndex( void *pProxyData )
{
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[iMerge].m_MDL.m_pProxyData == pProxyData )
return iMerge;
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CMDLPanel::GetMergeMDLIndex( MDLHandle_t handle )
{
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[iMerge].m_MDL.GetMDL() == handle )
return iMerge;
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CMDL *CMDLPanel::GetMergeMDL( MDLHandle_t handle )
{
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[iMerge].m_MDL.GetMDL() == handle )
return (&m_aMergeMDLs[iMerge].m_MDL);
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CStudioHdr *CMDLPanel::GetMergeMDLStudioHdr( MDLHandle_t handle )
{
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[ iMerge ].m_MDL.GetMDL() == handle )
return ( m_aMergeMDLs[ iMerge ].m_pStudioHdr );
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::ClearMergeMDLs( void )
{
const int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( !m_aMergeMDLs[iMerge].m_pStudioHdr )
{
continue;
}
delete m_aMergeMDLs[iMerge].m_pStudioHdr;
m_aMergeMDLs[iMerge].m_pStudioHdr = NULL;
}
m_aMergeMDLs.Purge();
}
void CMDLPanel::ValidateMDLs()
{
uint32 uMdlCacheSerial = vgui::ivgui()->GetMdlCacheSerial();
if ( m_RootMDL.m_pStudioHdr && m_RootMDL.m_unMdlCacheSerial != uMdlCacheSerial )
{
m_RootMDL.m_pStudioHdr = new CStudioHdr( m_RootMDL.m_MDL.GetStudioHdr(), g_pMDLCache );
m_RootMDL.m_unMdlCacheSerial = uMdlCacheSerial;
}
const int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[iMerge].m_pStudioHdr && m_aMergeMDLs[iMerge].m_unMdlCacheSerial != uMdlCacheSerial )
{
m_aMergeMDLs[iMerge].m_pStudioHdr = new CStudioHdr( m_aMergeMDLs[iMerge].m_MDL.GetStudioHdr(), g_pMDLCache );
m_aMergeMDLs[iMerge].m_unMdlCacheSerial = uMdlCacheSerial;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,539 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "matsys_controls/mdlsequencepicker.h"
#include "tier1/KeyValues.h"
#include "tier1/utldict.h"
#include "datacache/imdlcache.h"
#include "filesystem.h"
#include "studio.h"
#include "vgui/IVGui.h"
#include "vgui/Cursor.h"
#include "vgui/ISurface.h"
#include "vgui_controls/Splitter.h"
#include "vgui_controls/ComboBox.h"
#include "vgui_controls/PropertySheet.h"
#include "vgui_controls/PropertyPage.h"
#include "vgui_controls/ToolWindow.h"
#include "vgui_controls/Button.h"
#include "matsys_controls/gamefiletreeview.h"
#include "matsys_controls/matsyscontrols.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// MDL Sequence Picker
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CMDLSequencePicker::CMDLSequencePicker( vgui::Panel *pParent ) : BaseClass(pParent, "MDLSequencePicker"), m_Images(false)
{
vgui::ivgui()->AddTickSignal( GetVPanel() );
m_hSelectedMDL = MDLHANDLE_INVALID;
// Horizontal splitter for mdls
m_pMDLSplitter = new Splitter( this, "MDLSplitter", SPLITTER_MODE_VERTICAL, 1 );
vgui::Panel *pSplitterLeftSide = m_pMDLSplitter->GetChild( 0 );
vgui::Panel *pSplitterRightSide = m_pMDLSplitter->GetChild( 1 );
// filter selection
m_pFilterList = new ComboBox( pSplitterLeftSide, "FilterList", 16, true );
m_pFilterList->AddActionSignalTarget( this );
// file browser tree controls
m_pFileTree = new CGameFileTreeView( pSplitterLeftSide, "FileTree", "All .MDLs", "models", "mdl" );
// build our list of images
m_Images.AddImage( scheme()->GetImage( "resource/icon_folder", false ) );
m_Images.AddImage( scheme()->GetImage( "resource/icon_folder_selected", false ) );
m_Images.AddImage( scheme()->GetImage( "resource/icon_file", false ) );
m_pFileTree->SetImageList( &m_Images, false );
m_pFileTree->AddActionSignalTarget( this );
// property sheet - revisions, changes, etc.
m_pSequenceSplitter = new Splitter( pSplitterRightSide, "SequenceSplitter", SPLITTER_MODE_HORIZONTAL, 1 );
vgui::Panel *pSplitterTopSide = m_pSequenceSplitter->GetChild( 0 );
vgui::Panel *pSplitterBottomSide = m_pSequenceSplitter->GetChild( 1 );
// MDL preview
m_pMDLPreview = new CMDLPanel( pSplitterTopSide, "MDLPreview" );
SetSkipChildDuringPainting( m_pMDLPreview );
m_pViewsSheet = new vgui::PropertySheet( pSplitterBottomSide, "ViewsSheet" );
m_pViewsSheet->AddActionSignalTarget( this );
// sequences
m_pSequencesPage = new PropertyPage( m_pViewsSheet, "SequencesPage" );
m_pViewsSheet->AddPage( m_pSequencesPage, "Sequences" );
m_pSequencesList = new ListPanel( m_pSequencesPage, "SequencesList" );
m_pSequencesList->AddColumnHeader( 0, "sequence", "sequence", 52, 0 );
m_pSequencesList->AddActionSignalTarget( this );
m_pSequencesList->SetSelectIndividualCells( true );
m_pSequencesList->SetEmptyListText("No .MDL file currently selected.");
m_pSequencesList->SetDragEnabled( true );
m_pSequencesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
// Activities
m_pActivitiesPage = new PropertyPage( m_pViewsSheet, "ActivitiesPage" );
m_pViewsSheet->AddPage( m_pActivitiesPage, "Activities" );
m_pActivitiesList = new ListPanel( m_pActivitiesPage, "ActivitiesList" );
m_pActivitiesList->AddColumnHeader( 0, "activity", "activity", 52, 0 );
m_pActivitiesList->AddActionSignalTarget( this );
m_pActivitiesList->SetSelectIndividualCells( true );
m_pActivitiesList->SetEmptyListText( "No .MDL file currently selected." );
m_pActivitiesList->SetDragEnabled( true );
m_pActivitiesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
// Load layout settings; has to happen before pinning occurs in code
LoadControlSettingsAndUserConfig( "resource/mdlsequencepicker.res" );
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CMDLSequencePicker::~CMDLSequencePicker()
{
}
//-----------------------------------------------------------------------------
// Purpose: This is a bit of a hack to make sure that the ToolWindow containing this picker punches
// a hold for the rendering viewport, too
// Input : -
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnTick()
{
BaseClass::OnTick();
if ( GetParent() )
{
ToolWindow *tw = dynamic_cast< ToolWindow * >( GetParent()->GetParent() );
if ( tw )
{
tw->SetSkipChildDuringPainting( IsVisible() ? m_pMDLPreview : NULL );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: stops app on close
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnClose()
{
BaseClass::OnClose();
}
//-----------------------------------------------------------------------------
// Purpose: called to open
//-----------------------------------------------------------------------------
void CMDLSequencePicker::Activate()
{
RefreshFileList();
RefreshActivitiesAndSequencesList();
}
//-----------------------------------------------------------------------------
// Performs layout
//-----------------------------------------------------------------------------
void CMDLSequencePicker::PerformLayout()
{
// NOTE: This call should cause auto-resize to occur
// which should fix up the width of the panels
BaseClass::PerformLayout();
int w, h;
GetSize( w, h );
// Layout the mdl splitter
m_pMDLSplitter->SetBounds( 0, 0, w, h );
}
//-----------------------------------------------------------------------------
// Purpose: Refreshes the active file list
//-----------------------------------------------------------------------------
void CMDLSequencePicker::RefreshFileList()
{
m_pFileTree->RefreshFileList();
}
//-----------------------------------------------------------------------------
// Purpose: rebuilds the list of activities
//-----------------------------------------------------------------------------
void CMDLSequencePicker::RefreshActivitiesAndSequencesList()
{
m_pActivitiesList->RemoveAll();
m_pSequencesList->RemoveAll();
m_pMDLPreview->SetSequence( 0 );
if ( m_hSelectedMDL == MDLHANDLE_INVALID )
{
m_pActivitiesList->SetEmptyListText("No .MDL file currently selected");
m_pSequencesList->SetEmptyListText("No .MDL file currently selected");
return;
}
m_pActivitiesList->SetEmptyListText(".MDL file contains no activities");
m_pSequencesList->SetEmptyListText(".MDL file contains no sequences");
studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
CUtlDict<int, unsigned short> activityNames( true, 0, hdr->GetNumSeq() );
for (int j = 0; j < hdr->GetNumSeq(); j++)
{
if ( /*g_viewerSettings.showHidden ||*/ !(hdr->pSeqdesc(j).flags & STUDIO_HIDDEN))
{
const char *pActivityName = hdr->pSeqdesc(j).pszActivityName();
if ( pActivityName && pActivityName[0] )
{
// Multiple sequences can have the same activity name; only add unique activity names
if ( activityNames.Find( pActivityName ) == activityNames.InvalidIndex() )
{
KeyValues *pkv = new KeyValues("node", "activity", pActivityName );
int nItemID = m_pActivitiesList->AddItem( pkv, 0, false, false );
KeyValues *pDrag = new KeyValues( "drag", "text", pActivityName );
pDrag->SetString( "texttype", "activityName" );
pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
m_pActivitiesList->SetItemDragData( nItemID, pDrag );
activityNames.Insert( pActivityName, j );
}
}
const char *pSequenceName = hdr->pSeqdesc(j).pszLabel();
if ( pSequenceName && pSequenceName[0] )
{
KeyValues *pkv = new KeyValues("node", "sequence", pSequenceName);
pkv->SetInt( "seqindex", j );
int nItemID = m_pSequencesList->AddItem( pkv, 0, false, false );
KeyValues *pDrag = new KeyValues( "drag", "text", pSequenceName );
pDrag->SetString( "texttype", "sequenceName" );
pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
m_pSequencesList->SetItemDragData( nItemID, pDrag );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: refreshes dialog on text changing
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnTextChanged( vgui::Panel *pPanel, const char *pText )
{
// m_pFileTree->SetFilter( pText );
RefreshFileList();
}
/*
//-----------------------------------------------------------------------------
// Purpose: Selects an sequence based on an activity
//-----------------------------------------------------------------------------
int SelectWeightedSequence( studiohdr_t *pstudiohdr, int activity, int curSequence )
{
if (! pstudiohdr)
return 0;
VerifySequenceIndex( pstudiohdr );
int weighttotal = 0;
int seq = ACTIVITY_NOT_AVAILABLE;
int weight = 0;
for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
{
int curActivity = GetSequenceActivity( pstudiohdr, i, &weight );
if (curActivity == activity)
{
if ( curSequence == i && weight < 0 )
{
seq = i;
break;
}
weighttotal += iabs(weight);
int randomValue;
if ( IsInPrediction() )
randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1, i );
else
randomValue = RandomInt( 0, weighttotal - 1 );
if (!weighttotal || randomValue < iabs(weight))
seq = i;
}
}
return seq;
}
*/
//-----------------------------------------------------------------------------
// Plays the selected activity
//-----------------------------------------------------------------------------
void CMDLSequencePicker::PlaySelectedActivity( )
{
int nIndex = m_pActivitiesList->GetSelectedItem( 0 );
if ( nIndex < 0 )
return;
KeyValues *pkv = m_pActivitiesList->GetItem( nIndex );
const char *pActivityName = pkv->GetString( "activity", NULL );
if ( !pActivityName )
return;
studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ )
{
mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
if ( stricmp( seqdesc.pszActivityName(), pActivityName ) == 0 )
{
// FIXME: Add weighted sequence selection logic?
m_pMDLPreview->SetSequence( i );
break;
}
}
}
//-----------------------------------------------------------------------------
// Plays the selected sequence
//-----------------------------------------------------------------------------
void CMDLSequencePicker::PlaySelectedSequence( )
{
int nIndex = m_pSequencesList->GetSelectedItem( 0 );
if ( nIndex < 0 )
return;
KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
const char *pSequenceName = pkv->GetString( "sequence", NULL );
if ( !pSequenceName )
return;
studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
{
mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
if ( !Q_stricmp( seqdesc.pszLabel(), pSequenceName ) )
{
m_pMDLPreview->SetSequence( i );
break;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Called when a page is shown
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnPageChanged( )
{
if ( m_pViewsSheet->GetActivePage() == m_pSequencesPage )
{
PlaySelectedSequence();
return;
}
if ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage )
{
PlaySelectedActivity();
return;
}
}
//-----------------------------------------------------------------------------
// Purpose: refreshes dialog on text changing
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnItemSelected( KeyValues *kv )
{
Panel *pPanel = (Panel *)kv->GetPtr("panel", NULL);
if ( pPanel == m_pSequencesList )
{
PlaySelectedSequence();
return;
}
if ( pPanel == m_pActivitiesList )
{
PlaySelectedActivity();
return;
}
}
//-----------------------------------------------------------------------------
// An MDL was selected
//-----------------------------------------------------------------------------
void CMDLSequencePicker::SelectMDL( const char *pMDLName )
{
m_hSelectedMDL = pMDLName ? vgui::MDLCache()->FindMDL( pMDLName ) : MDLHANDLE_INVALID;
if ( vgui::MDLCache()->IsErrorModel( m_hSelectedMDL ) )
{
m_hSelectedMDL = MDLHANDLE_INVALID;
}
m_pMDLPreview->SetMDL( m_hSelectedMDL );
m_pMDLPreview->LookAtMDL();
RefreshActivitiesAndSequencesList();
}
//-----------------------------------------------------------------------------
// Purpose: updates revision view on a file being selected
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnFileSelected()
{
// update list
int iItem = m_pFileTree->GetFirstSelectedItem();
if ( iItem < 0 )
return;
// Don't bother to change if a directory was selected
KeyValues *pkv = m_pFileTree->GetItemData(iItem);
if ( pkv->GetInt("dir") || pkv->GetInt("root") )
return;
surface()->SetCursor(dc_waitarrow);
const char *pFullPathName = pkv->GetString( "path" );
char pRelativePathName[MAX_PATH];
g_pFullFileSystem->FullPathToRelativePath( pFullPathName, pRelativePathName, sizeof(pRelativePathName) );
// FIXME: Check that we're not actually opening the wrong file!!
SelectMDL( pRelativePathName );
}
char const *CMDLSequencePicker::GetModelName()
{
if ( MDLHANDLE_INVALID == m_hSelectedMDL )
{
return "";
}
return vgui::MDLCache()->GetModelName( m_hSelectedMDL );
}
char const *CMDLSequencePicker::GetSequenceName()
{
int nIndex = m_pSequencesList->GetSelectedItem( 0 );
if ( nIndex < 0 )
return "";
KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
const char *pSequenceName = pkv->GetString( "sequence", NULL );
if ( !pSequenceName )
return "";
return pSequenceName;
}
int CMDLSequencePicker::GetSequenceNumber()
{
int nIndex = m_pSequencesList->GetSelectedItem( 0 );
if ( nIndex < 0 )
return -1;
KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
return pkv->GetInt( "seqindex", -1 );
}
//-----------------------------------------------------------------------------
// Sequence picker frame
//-----------------------------------------------------------------------------
CMDLSequencePickerFrame::CMDLSequencePickerFrame( vgui::Panel *parent, char const *title ) :
BaseClass( parent, "MDLSequencePickerFrame" )
{
m_pMDLSequencePicker = new CMDLSequencePicker( this );
SetTitle( title, true );
SetSizeable( false );
SetCloseButtonVisible( false );
SetMoveable( true );
SetMinimumSize( 640, 480 );
Activate();
m_pMDLSequencePicker->Activate();
m_pOK = new Button( this, "OK", "#vgui_ok", this );
m_pOK->SetCommand( new KeyValues( "OnOK" ) );
m_pCancel= new Button( this, "Cancel", "#vgui_cancel", this );
m_pOK->SetCommand( new KeyValues( "OnCancel" ) );
m_pOK->SetEnabled( false );
vgui::ivgui()->AddTickSignal( GetVPanel(), 0 );
}
CMDLSequencePickerFrame::~CMDLSequencePickerFrame()
{
}
void CMDLSequencePickerFrame::OnTick()
{
BaseClass::OnTick();
bool bHasModel = m_pMDLSequencePicker->GetModelName()[ 0 ] != 0 ? true : false;
bool bHasSequence = m_pMDLSequencePicker->GetSequenceNumber() != -1 ? true : false;
m_pOK->SetEnabled( bHasModel && bHasSequence );
}
void CMDLSequencePickerFrame::PerformLayout()
{
BaseClass::PerformLayout();
int x, y, w, h;
GetClientArea( x, y, w, h );
h -= 24;
m_pMDLSequencePicker->SetBounds( x, y, w, h );
h += 5;
int bw = 120;
int bwwithGap = 2 * bw + 10;
x = ( w - bwwithGap ) / 2;
m_pOK->SetBounds( x, y + h, bw, 16 );
x += bw + 10;
m_pCancel->SetBounds( x, y + h, bw, 16 );
}
void CMDLSequencePickerFrame::OnCancel()
{
KeyValues *pActionKeys = new KeyValues( "AssetSelected" );
pActionKeys->SetString( "ModelName", m_pMDLSequencePicker->GetModelName() );
pActionKeys->SetString( "SequenceName", m_pMDLSequencePicker->GetSequenceName() );
pActionKeys->SetInt( "SequenceNumber", m_pMDLSequencePicker->GetSequenceNumber() );
PostActionSignal( pActionKeys );
CloseModal();
}
void CMDLSequencePickerFrame::OnOK()
{
CloseModal();
}

View File

@ -0,0 +1,318 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "filesystem.h"
#include "matsys_controls/picker.h"
#include "tier1/KeyValues.h"
#include "vgui_controls/ListPanel.h"
#include "vgui_controls/TextEntry.h"
#include "vgui_controls/Button.h"
#include "vgui/ISurface.h"
#include "vgui/IInput.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// Base asset Picker
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Sort by asset name
//-----------------------------------------------------------------------------
static int __cdecl PickerBrowserSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
{
const char *string1 = item1.kv->GetString("choice");
const char *string2 = item2.kv->GetString("choice");
return stricmp( string1, string2 );
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CPicker::CPicker( vgui::Panel *pParent, const char *pColumnHeader, const char *pTextType ) :
BaseClass( pParent, "Picker" )
{
m_pPickerType = pColumnHeader;
m_pPickerTextType = pTextType;
// FIXME: Make this an image browser
m_pPickerBrowser = new vgui::ListPanel( this, "Browser" );
m_pPickerBrowser->AddColumnHeader( 0, "choice", m_pPickerType, 52, 0 );
m_pPickerBrowser->SetSelectIndividualCells( true );
m_pPickerBrowser->SetEmptyListText( "Nothing to pick" );
m_pPickerBrowser->SetDragEnabled( true );
m_pPickerBrowser->AddActionSignalTarget( this );
m_pPickerBrowser->SetSortFunc( 0, PickerBrowserSortFunc );
m_pPickerBrowser->SetSortColumn( 0 );
// filter selection
m_pFilterList = new TextEntry( this, "FilterList" );
m_pFilterList->AddActionSignalTarget( this );
m_pFilterList->RequestFocus();
LoadControlSettingsAndUserConfig( "resource/picker.res" );
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CPicker::~CPicker()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPicker::OnKeyCodePressed( KeyCode code )
{
if (( code == KEY_UP ) || ( code == KEY_DOWN ) || ( code == KEY_PAGEUP ) || ( code == KEY_PAGEDOWN ))
{
KeyValues *pMsg = new KeyValues("KeyCodePressed", "code", code);
vgui::ipanel()->SendMessage( m_pPickerBrowser->GetVPanel(), pMsg, GetVPanel());
pMsg->deleteThis();
}
else
{
BaseClass::OnKeyCodePressed( code );
}
}
//-----------------------------------------------------------------------------
// Purpose: refreshes the asset list
//-----------------------------------------------------------------------------
void CPicker::SetStringList( const PickerList_t &list )
{
m_Type = list.m_Type;
m_pPickerBrowser->RemoveAll();
int nCount = list.Count();
for ( int i = 0; i < nCount; ++i )
{
const char *pPickerName = list[i].m_pChoiceString;
KeyValues *kv = new KeyValues( "node", "choice", pPickerName );
if ( m_Type == PICKER_CHOICE_STRING )
{
kv->SetString( "value", list[i].m_pChoiceValue );
}
else
{
kv->SetPtr( "value", list[i].m_pChoiceValuePtr );
}
int nItemID = m_pPickerBrowser->AddItem( kv, 0, false, false );
if ( m_Type == PICKER_CHOICE_STRING )
{
KeyValues *pDrag = new KeyValues( "drag", "text", list[i].m_pChoiceValue );
if ( m_pPickerTextType )
{
pDrag->SetString( "texttype", m_pPickerTextType );
}
m_pPickerBrowser->SetItemDragData( nItemID, pDrag );
}
}
RefreshChoiceList();
}
//-----------------------------------------------------------------------------
// Purpose: refreshes the choice list
//-----------------------------------------------------------------------------
void CPicker::RefreshChoiceList( )
{
// Check the filter matches
int nMatchingCount = 0;
int nTotalCount = 0;
for ( int nItemID = m_pPickerBrowser->FirstItem(); nItemID != m_pPickerBrowser->InvalidItemID(); nItemID = m_pPickerBrowser->NextItem( nItemID ) )
{
KeyValues *kv = m_pPickerBrowser->GetItem( nItemID );
const char *pPickerName = kv->GetString( "choice" );
bool bVisible = !m_Filter.Length() || Q_stristr( pPickerName, m_Filter.Get() );
m_pPickerBrowser->SetItemVisible( nItemID, bVisible );
if ( bVisible )
{
++nMatchingCount;
}
++nTotalCount;
}
char pColumnTitle[512];
Q_snprintf( pColumnTitle, sizeof(pColumnTitle), "%s (%d/%d)",
m_pPickerType, nMatchingCount, nTotalCount );
m_pPickerBrowser->SetColumnHeaderText( 0, pColumnTitle );
m_pPickerBrowser->SortList();
if ( ( m_pPickerBrowser->GetSelectedItemsCount() == 0 ) && ( m_pPickerBrowser->GetItemCount() > 0 ) )
{
int nItemID = m_pPickerBrowser->GetItemIDFromRow( 0 );
m_pPickerBrowser->SetSelectedCell( nItemID, 0 );
}
}
//-----------------------------------------------------------------------------
// Purpose: refreshes dialog on text changing
//-----------------------------------------------------------------------------
void CPicker::OnTextChanged( )
{
int nLength = m_pFilterList->GetTextLength();
m_Filter.SetLength( nLength );
if ( nLength > 0 )
{
m_pFilterList->GetText( m_Filter.GetForModify(), nLength+1 );
}
RefreshChoiceList();
}
//-----------------------------------------------------------------------------
// Returns the selected string
//-----------------------------------------------------------------------------
PickerChoiceType_t CPicker::GetSelectionType() const
{
return m_Type;
}
const char *CPicker::GetSelectedString( ) const
{
if ( m_pPickerBrowser->GetSelectedItemsCount() == 0 )
return NULL;
if ( m_Type != PICKER_CHOICE_STRING )
return NULL;
int nIndex = m_pPickerBrowser->GetSelectedItem( 0 );
KeyValues *pItemKeyValues = m_pPickerBrowser->GetItem( nIndex );
return pItemKeyValues->GetString( "value" );
}
void *CPicker::GetSelectedPtr( ) const
{
if ( m_pPickerBrowser->GetSelectedItemsCount() == 0 )
return NULL;
if ( m_Type != PICKER_CHOICE_PTR )
return NULL;
int nIndex = m_pPickerBrowser->GetSelectedItem( 0 );
KeyValues *pItemKeyValues = m_pPickerBrowser->GetItem( nIndex );
return pItemKeyValues->GetPtr( "value" );
}
//-----------------------------------------------------------------------------
// Returns the index of the selected string
//-----------------------------------------------------------------------------
int CPicker::GetSelectedIndex()
{
if ( m_pPickerBrowser->GetSelectedItemsCount() == 0 )
return -1;
return m_pPickerBrowser->GetSelectedItem( 0 );
}
//-----------------------------------------------------------------------------
//
// Purpose: Modal picker frame
//
//-----------------------------------------------------------------------------
CPickerFrame::CPickerFrame( vgui::Panel *pParent, const char *pTitle, const char *pPickerType, const char *pTextType ) :
BaseClass( pParent, "PickerFrame" )
{
m_pContextKeyValues = NULL;
SetDeleteSelfOnClose( true );
m_pPicker = new CPicker( this, pPickerType, pTextType );
m_pPicker->AddActionSignalTarget( this );
m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this, "Open" );
m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this, "Cancel" );
SetBlockDragChaining( true );
LoadControlSettingsAndUserConfig( "resource/pickerframe.res" );
SetTitle( pTitle, false );
}
CPickerFrame::~CPickerFrame()
{
CleanUpMessage();
}
//-----------------------------------------------------------------------------
// Deletes the message
//-----------------------------------------------------------------------------
void CPickerFrame::CleanUpMessage()
{
if ( m_pContextKeyValues )
{
m_pContextKeyValues->deleteThis();
m_pContextKeyValues = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose: Activate the dialog
//-----------------------------------------------------------------------------
void CPickerFrame::DoModal( const PickerList_t &list, KeyValues *pContextKeyValues )
{
CleanUpMessage();
m_pContextKeyValues = pContextKeyValues;
m_pPicker->SetStringList( list );
BaseClass::DoModal();
}
//-----------------------------------------------------------------------------
// On command
//-----------------------------------------------------------------------------
void CPickerFrame::OnCommand( const char *pCommand )
{
if ( !Q_stricmp( pCommand, "Open" ) )
{
KeyValues *pActionKeys = new KeyValues( "Picked" );
pActionKeys->SetInt( "choiceIndex", m_pPicker->GetSelectedIndex( ) );
if ( m_pPicker->GetSelectionType() == PICKER_CHOICE_STRING )
{
const char *pPickerName = m_pPicker->GetSelectedString( );
pActionKeys->SetString( "choice", pPickerName );
}
else
{
void *pPickerPtr = m_pPicker->GetSelectedPtr( );
pActionKeys->SetPtr( "choice", pPickerPtr );
}
if ( m_pContextKeyValues )
{
pActionKeys->AddSubKey( m_pContextKeyValues );
m_pContextKeyValues = NULL;
}
PostActionSignal( pActionKeys );
CloseModal();
return;
}
if ( !Q_stricmp( pCommand, "Cancel" ) )
{
CloseModal();
return;
}
BaseClass::OnCommand( pCommand );
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,239 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#include "matsys_controls/proceduraltexturepanel.h"
#include "matsys_controls/matsyscontrols.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/itexture.h"
#include "VGuiMatSurface/IMatSystemSurface.h"
#include "tier1/KeyValues.h"
#include "pixelwriter.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CProceduralTexturePanel::CProceduralTexturePanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName )
{
m_pImageBuffer = NULL;
m_bMaintainProportions = false;
m_bUsePaintRect = false;
m_PaintRect.x = m_PaintRect.y = 0;
m_PaintRect.width = m_PaintRect.height = 0;
}
CProceduralTexturePanel::~CProceduralTexturePanel()
{
CleanUp();
}
//-----------------------------------------------------------------------------
// initialization, shutdown
//-----------------------------------------------------------------------------
bool CProceduralTexturePanel::Init( int nWidth, int nHeight, bool bAllocateImageBuffer )
{
m_nWidth = nWidth;
m_nHeight = nHeight;
if ( bAllocateImageBuffer )
{
m_pImageBuffer = new BGRA8888_t[nWidth * nHeight];
}
m_TextureSubRect.x = m_TextureSubRect.y = 0;
m_TextureSubRect.width = nWidth;
m_TextureSubRect.height = nHeight;
char pTemp[512];
Q_snprintf( pTemp, 512, "__%s", GetName() );
ITexture *pTex = MaterialSystem()->CreateProceduralTexture( pTemp, TEXTURE_GROUP_VGUI,
m_nWidth, m_nHeight, IMAGE_FORMAT_BGRX8888,
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_NOMIP |
TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY );
pTex->SetTextureRegenerator( this );
m_ProceduralTexture.Init( pTex );
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
pVMTKeyValues->SetString( "$basetexture", pTemp );
pVMTKeyValues->SetInt( "$nocull", 1 );
pVMTKeyValues->SetInt( "$nodebug", 1 );
m_ProceduralMaterial.Init( MaterialSystem()->CreateMaterial( pTemp, pVMTKeyValues ));
m_nTextureID = MatSystemSurface()->CreateNewTextureID( false );
MatSystemSurface()->DrawSetTextureMaterial( m_nTextureID, m_ProceduralMaterial );
return true;
}
void CProceduralTexturePanel::Shutdown()
{
CleanUp();
}
//-----------------------------------------------------------------------------
// Maintain proportions when drawing
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::MaintainProportions( bool bEnable )
{
m_bMaintainProportions = bEnable;
}
//-----------------------------------------------------------------------------
// Returns the image buffer + dimensions
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::CleanUp()
{
if ( (ITexture*)m_ProceduralTexture )
{
m_ProceduralTexture->SetTextureRegenerator( NULL );
}
m_ProceduralTexture.Shutdown();
m_ProceduralMaterial.Shutdown();
if ( m_pImageBuffer )
{
delete[] m_pImageBuffer;
m_pImageBuffer = NULL;
}
}
//-----------------------------------------------------------------------------
// Default implementation of regenerate texture bits
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
{
Assert( m_pImageBuffer );
Assert( pVTFTexture->FrameCount() == 1 );
Assert( pVTFTexture->FaceCount() == 1 );
Assert( !pTexture->IsMipmapped() );
int nWidth, nHeight, nDepth;
pVTFTexture->ComputeMipLevelDimensions( 0, &nWidth, &nHeight, &nDepth );
Assert( nDepth == 1 );
Assert( nWidth == m_nWidth && nHeight == m_nHeight );
CPixelWriter pixelWriter;
pixelWriter.SetPixelMemory( pVTFTexture->Format(),
pVTFTexture->ImageData( 0, 0, 0 ), pVTFTexture->RowSizeInBytes( 0 ) );
for ( int y = 0; y < nHeight; ++y )
{
pixelWriter.Seek( 0, y );
BGRA8888_t *pTexel = &m_pImageBuffer[y * m_nWidth];
for ( int x = 0; x < nWidth; ++x, ++pTexel )
{
pixelWriter.WritePixel( pTexel->r, pTexel->g, pTexel->b, pTexel->a );
}
}
}
//-----------------------------------------------------------------------------
// Returns the image buffer + dimensions
//-----------------------------------------------------------------------------
BGRA8888_t *CProceduralTexturePanel::GetImageBuffer()
{
Assert( m_pImageBuffer );
return m_pImageBuffer;
}
int CProceduralTexturePanel::GetImageWidth() const
{
return m_nWidth;
}
int CProceduralTexturePanel::GetImageHeight() const
{
return m_nHeight;
}
//-----------------------------------------------------------------------------
// Sets the paint rect
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::SetPaintRect( const Rect_t *pPaintRect )
{
m_bUsePaintRect = ( pPaintRect != NULL );
if ( m_bUsePaintRect )
{
m_PaintRect = *pPaintRect;
}
}
//-----------------------------------------------------------------------------
// Sets the draw rect
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::SetTextureSubRect( const Rect_t &subRect )
{
m_TextureSubRect = subRect;
}
//-----------------------------------------------------------------------------
// Redownloads the procedural texture
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::DownloadTexture()
{
m_ProceduralTexture->Download();
}
//-----------------------------------------------------------------------------
// Paints the texture
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::Paint( void )
{
vgui::surface()->DrawSetTexture( m_nTextureID );
vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
int x = 0;
int y = 0;
int w, h;
GetSize( w, h );
if ( m_bUsePaintRect )
{
x = m_PaintRect.x;
y = m_PaintRect.y;
w = m_PaintRect.width;
h = m_PaintRect.height;
}
if ( m_bMaintainProportions )
{
if ( m_TextureSubRect.width > m_TextureSubRect.height )
{
h = w * m_TextureSubRect.height / m_TextureSubRect.width;
}
else
{
w = h * m_TextureSubRect.width / m_TextureSubRect.height;
}
}
// Rotated version of the bitmap!
// Rotate about the center of the bitmap
vgui::Vertex_t verts[4];
verts[0].m_Position.Init( x, y );
verts[0].m_TexCoord.Init( (float)m_TextureSubRect.x / m_nWidth, (float)m_TextureSubRect.y / m_nHeight );
verts[1].m_Position.Init( w+x, y );
verts[1].m_TexCoord.Init( (float)(m_TextureSubRect.x + m_TextureSubRect.width) / m_nWidth, (float)m_TextureSubRect.y / m_nHeight );
verts[2].m_Position.Init( w+x, h+y );
verts[2].m_TexCoord.Init( (float)(m_TextureSubRect.x + m_TextureSubRect.width) / m_nWidth, (float)(m_TextureSubRect.y + m_TextureSubRect.height) / m_nHeight );
verts[3].m_Position.Init( x, h+y );
verts[3].m_TexCoord.Init( (float)m_TextureSubRect.x / m_nWidth, (float)(m_TextureSubRect.y + m_TextureSubRect.height) / m_nHeight );
vgui::surface()->DrawTexturedPolygon( 4, verts );
}

View File

@ -0,0 +1,485 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "matsys_controls/sequencepicker.h"
#include "tier1/utldict.h"
#include "tier1/KeyValues.h"
#include "studio.h"
#include "vgui/IInput.h"
#include "vgui/ISurface.h"
#include "vgui_controls/Splitter.h"
#include "vgui_controls/PropertyPage.h"
#include "vgui_controls/PropertySheet.h"
#include "vgui_controls/ListPanel.h"
#include "vgui_controls/Button.h"
#include "matsys_controls/matsyscontrols.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// Sequence Picker
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Sort by sequence name
//-----------------------------------------------------------------------------
static int __cdecl SequenceSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
{
const char *string1 = item1.kv->GetString("sequence");
const char *string2 = item2.kv->GetString("sequence");
return stricmp( string1, string2 );
}
static int __cdecl ActivitySortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
{
const char *string1 = item1.kv->GetString("activity");
const char *string2 = item2.kv->GetString("activity");
return stricmp( string1, string2 );
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CSequencePicker::CSequencePicker( vgui::Panel *pParent, int nFlags ) : BaseClass( pParent, "SequencePicker" )
{
m_hSelectedMDL = MDLHANDLE_INVALID;
// property sheet - revisions, changes, etc.
m_pPreviewSplitter = new Splitter( this, "PreviewSplitter", SPLITTER_MODE_HORIZONTAL, 1 );
vgui::Panel *pSplitterTopSide = m_pPreviewSplitter->GetChild( 0 );
vgui::Panel *pSplitterBottomSide = m_pPreviewSplitter->GetChild( 1 );
// MDL preview
m_pMDLPreview = new CMDLPanel( pSplitterTopSide, "MDLPreview" );
SetSkipChildDuringPainting( m_pMDLPreview );
m_pViewsSheet = new vgui::PropertySheet( pSplitterBottomSide, "ViewsSheet" );
m_pViewsSheet->AddActionSignalTarget( this );
// sequences
m_pSequencesPage = NULL;
m_pSequencesList = NULL;
if ( nFlags & PICK_SEQUENCES )
{
m_pSequencesPage = new PropertyPage( m_pViewsSheet, "SequencesPage" );
m_pViewsSheet->AddPage( m_pSequencesPage, "Sequences" );
m_pSequencesList = new ListPanel( m_pSequencesPage, "SequencesList" );
m_pSequencesList->AddColumnHeader( 0, "sequence", "sequence", 52, 0 );
m_pSequencesList->AddActionSignalTarget( this );
m_pSequencesList->SetSelectIndividualCells( true );
m_pSequencesList->SetEmptyListText(".MDL file contains no activities");
m_pSequencesList->SetDragEnabled( true );
m_pSequencesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
m_pSequencesList->SetSortFunc( 0, SequenceSortFunc );
m_pSequencesList->SetSortColumn( 0 );
}
// Activities
m_pActivitiesPage = NULL;
m_pActivitiesList = NULL;
if ( nFlags & PICK_ACTIVITIES )
{
m_pActivitiesPage = new PropertyPage( m_pViewsSheet, "ActivitiesPage" );
m_pViewsSheet->AddPage( m_pActivitiesPage, "Activities" );
m_pActivitiesList = new ListPanel( m_pActivitiesPage, "ActivitiesList" );
m_pActivitiesList->AddColumnHeader( 0, "activity", "activity", 52, 0 );
m_pActivitiesList->AddActionSignalTarget( this );
m_pActivitiesList->SetSelectIndividualCells( true );
m_pActivitiesList->SetEmptyListText( ".MDL file contains no activities" );
m_pActivitiesList->SetDragEnabled( true );
m_pActivitiesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
m_pActivitiesList->SetSortFunc( 0, ActivitySortFunc );
m_pActivitiesList->SetSortColumn( 0 );
}
// Load layout settings; has to happen before pinning occurs in code
LoadControlSettingsAndUserConfig( "resource/sequencepicker.res" );
SETUP_PANEL( this );
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CSequencePicker::~CSequencePicker()
{
}
//-----------------------------------------------------------------------------
// Performs layout
//-----------------------------------------------------------------------------
void CSequencePicker::PerformLayout()
{
// NOTE: This call should cause auto-resize to occur
// which should fix up the width of the panels
BaseClass::PerformLayout();
int w, h;
GetSize( w, h );
// Layout the mdl splitter
m_pPreviewSplitter->SetBounds( 0, 0, w, h );
}
//-----------------------------------------------------------------------------
// Purpose: rebuilds the list of activities + sequences
//-----------------------------------------------------------------------------
void CSequencePicker::RefreshActivitiesAndSequencesList()
{
if ( m_pActivitiesList )
{
m_pActivitiesList->RemoveAll();
}
if ( m_pSequencesList )
{
m_pSequencesList->RemoveAll();
}
m_pMDLPreview->SetSequence( 0 );
if ( m_hSelectedMDL == MDLHANDLE_INVALID )
return;
studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
CUtlDict<int, unsigned short> activityNames( true, 0, hdr->GetNumSeq() );
for (int j = 0; j < hdr->GetNumSeq(); j++)
{
if ( /*g_viewerSettings.showHidden ||*/ !(hdr->pSeqdesc(j).flags & STUDIO_HIDDEN))
{
const char *pActivityName = hdr->pSeqdesc(j).pszActivityName();
if ( m_pActivitiesList && pActivityName && pActivityName[0] )
{
// Multiple sequences can have the same activity name; only add unique activity names
if ( activityNames.Find( pActivityName ) == activityNames.InvalidIndex() )
{
KeyValues *pkv = new KeyValues("node", "activity", pActivityName );
int nItemID = m_pActivitiesList->AddItem( pkv, 0, false, false );
KeyValues *pDrag = new KeyValues( "drag", "text", pActivityName );
pDrag->SetString( "texttype", "activityName" );
pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
m_pActivitiesList->SetItemDragData( nItemID, pDrag );
activityNames.Insert( pActivityName, j );
}
}
const char *pSequenceName = hdr->pSeqdesc(j).pszLabel();
if ( m_pSequencesList && pSequenceName && pSequenceName[0] )
{
KeyValues *pkv = new KeyValues("node", "sequence", pSequenceName);
int nItemID = m_pSequencesList->AddItem( pkv, 0, false, false );
KeyValues *pDrag = new KeyValues( "drag", "text", pSequenceName );
pDrag->SetString( "texttype", "sequenceName" );
pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
m_pSequencesList->SetItemDragData( nItemID, pDrag );
}
}
}
if ( m_pSequencesList )
{
m_pSequencesList->SortList();
}
if ( m_pActivitiesList )
{
m_pActivitiesList->SortList();
}
}
/*
//-----------------------------------------------------------------------------
// Purpose: Selects an sequence based on an activity
//-----------------------------------------------------------------------------
int SelectWeightedSequence( studiohdr_t *pstudiohdr, int activity, int curSequence )
{
if (! pstudiohdr)
return 0;
VerifySequenceIndex( pstudiohdr );
int weighttotal = 0;
int seq = ACTIVITY_NOT_AVAILABLE;
int weight = 0;
for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
{
int curActivity = GetSequenceActivity( pstudiohdr, i, &weight );
if (curActivity == activity)
{
if ( curSequence == i && weight < 0 )
{
seq = i;
break;
}
weighttotal += iabs(weight);
int randomValue;
if ( IsInPrediction() )
randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1, i );
else
randomValue = RandomInt( 0, weighttotal - 1 );
if (!weighttotal || randomValue < iabs(weight))
seq = i;
}
}
return seq;
}
*/
//-----------------------------------------------------------------------------
// Gets the selected activity/sequence
//-----------------------------------------------------------------------------
CSequencePicker::PickType_t CSequencePicker::GetSelectedSequenceType( )
{
if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) )
return PICK_SEQUENCES;
if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) )
return PICK_ACTIVITIES;
return PICK_NONE;
}
const char *CSequencePicker::GetSelectedSequenceName( )
{
if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) )
{
int nIndex = m_pSequencesList->GetSelectedItem( 0 );
if ( nIndex >= 0 )
{
KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
return pkv->GetString( "sequence", NULL );
}
return NULL;
}
if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) )
{
int nIndex = m_pActivitiesList->GetSelectedItem( 0 );
if ( nIndex >= 0 )
{
KeyValues *pkv = m_pActivitiesList->GetItem( nIndex );
return pkv->GetString( "activity", NULL );
}
return NULL;
}
return NULL;
}
//-----------------------------------------------------------------------------
// Plays the selected activity
//-----------------------------------------------------------------------------
void CSequencePicker::PlayActivity( const char *pActivityName )
{
studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ )
{
mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
if ( stricmp( seqdesc.pszActivityName(), pActivityName ) == 0 )
{
// FIXME: Add weighted sequence selection logic?
m_pMDLPreview->SetSequence( i );
break;
}
}
}
//-----------------------------------------------------------------------------
// Plays the selected sequence
//-----------------------------------------------------------------------------
void CSequencePicker::PlaySequence( const char *pSequenceName )
{
studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
{
mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
if ( !Q_stricmp( seqdesc.pszLabel(), pSequenceName ) )
{
m_pMDLPreview->SetSequence( i );
break;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Called when a page is shown
//-----------------------------------------------------------------------------
void CSequencePicker::OnPageChanged( )
{
if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) )
{
const char *pSequenceName = GetSelectedSequenceName();
if ( pSequenceName )
{
PlaySequence( pSequenceName );
PostActionSignal( new KeyValues( "SequencePreviewChanged", "sequence", pSequenceName ) );
}
return;
}
if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) )
{
const char *pActivityName = GetSelectedSequenceName();
if ( pActivityName )
{
PlayActivity( pActivityName );
PostActionSignal( new KeyValues( "SequencePreviewChanged", "activity", pActivityName ) );
}
return;
}
}
//-----------------------------------------------------------------------------
// Purpose: refreshes dialog on text changing
//-----------------------------------------------------------------------------
void CSequencePicker::OnItemSelected( KeyValues *kv )
{
Panel *pPanel = (Panel *)kv->GetPtr("panel", NULL);
if ( m_pSequencesList && (pPanel == m_pSequencesList ) )
{
const char *pSequenceName = GetSelectedSequenceName();
if ( pSequenceName )
{
PlaySequence( pSequenceName );
PostActionSignal( new KeyValues( "SequencePreviewChanged", "sequence", pSequenceName ) );
}
return;
}
if ( m_pActivitiesList && ( pPanel == m_pActivitiesList ) )
{
const char *pActivityName = GetSelectedSequenceName();
if ( pActivityName )
{
PlayActivity( pActivityName );
PostActionSignal( new KeyValues( "SequencePreviewChanged", "activity", pActivityName ) );
}
return;
}
}
//-----------------------------------------------------------------------------
// Sets the MDL to select sequences in
//-----------------------------------------------------------------------------
void CSequencePicker::SetMDL( const char *pMDLName )
{
m_hSelectedMDL = pMDLName ? vgui::MDLCache()->FindMDL( pMDLName ) : MDLHANDLE_INVALID;
if ( vgui::MDLCache()->IsErrorModel( m_hSelectedMDL ) )
{
m_hSelectedMDL = MDLHANDLE_INVALID;
}
m_pMDLPreview->SetMDL( m_hSelectedMDL );
m_pMDLPreview->LookAtMDL();
RefreshActivitiesAndSequencesList();
}
//-----------------------------------------------------------------------------
//
// Purpose: Modal picker frame
//
//-----------------------------------------------------------------------------
CSequencePickerFrame::CSequencePickerFrame( vgui::Panel *pParent, int nFlags ) : BaseClass( pParent, "SequencePickerFrame" )
{
SetDeleteSelfOnClose( true );
m_pPicker = new CSequencePicker( this, nFlags );
m_pPicker->AddActionSignalTarget( this );
m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this, "Open" );
m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this, "Cancel" );
SetBlockDragChaining( true );
LoadControlSettingsAndUserConfig( "resource/sequencepickerframe.res" );
m_pOpenButton->SetEnabled( false );
}
//-----------------------------------------------------------------------------
// Purpose: Activate the dialog
//-----------------------------------------------------------------------------
void CSequencePickerFrame::DoModal( const char *pMDLName )
{
m_pPicker->SetMDL( pMDLName );
BaseClass::DoModal();
}
//-----------------------------------------------------------------------------
// On mdl preview changed
//-----------------------------------------------------------------------------
void CSequencePickerFrame::OnSequencePreviewChanged( KeyValues *pKeyValues )
{
const char *pSequence = pKeyValues->GetString( "sequence", NULL );
const char *pActivity = pKeyValues->GetString( "activity", NULL );
m_pOpenButton->SetEnabled( pSequence || pActivity );
}
//-----------------------------------------------------------------------------
// On command
//-----------------------------------------------------------------------------
void CSequencePickerFrame::OnCommand( const char *pCommand )
{
if ( !Q_stricmp( pCommand, "Open" ) )
{
CSequencePicker::PickType_t type = m_pPicker->GetSelectedSequenceType( );
if (( type == CSequencePicker::PICK_SEQUENCES ) || ( type == CSequencePicker::PICK_ACTIVITIES ))
{
const char *pSequenceName = m_pPicker->GetSelectedSequenceName();
if ( pSequenceName )
{
if ( type == CSequencePicker::PICK_SEQUENCES )
{
PostActionSignal( new KeyValues("SequenceSelected", "sequence", pSequenceName ) );
}
else
{
PostActionSignal( new KeyValues("SequenceSelected", "activity", pSequenceName ) );
}
CloseModal();
return;
}
}
return;
}
if ( !Q_stricmp( pCommand, "Cancel" ) )
{
CloseModal();
return;
}
BaseClass::OnCommand( pCommand );
}

View File

@ -0,0 +1,72 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#include "matsys_controls/tgapreviewpanel.h"
#include "bitmap/tgaloader.h"
#include "tier1/utlbuffer.h"
#include "filesystem.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// TGA Preview panel
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CTGAPreviewPanel::CTGAPreviewPanel( vgui::Panel *pParent, const char *pName ) :
BaseClass( pParent, pName )
{
}
//-----------------------------------------------------------------------------
// Sets the current TGA
//-----------------------------------------------------------------------------
void CTGAPreviewPanel::SetTGA( const char *pFullPath )
{
int nWidth, nHeight;
ImageFormat format;
float flGamma;
CUtlBuffer buf;
if ( !g_pFullFileSystem->ReadFile( pFullPath, NULL, buf ) )
{
Warning( "Can't open TGA file: %s\n", pFullPath );
return;
}
TGALoader::GetInfo( buf, &nWidth, &nHeight, &format, &flGamma );
Shutdown();
Init( nWidth, nHeight, true );
m_TGAName = pFullPath;
buf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
if ( !TGALoader::Load( (unsigned char*)GetImageBuffer(), buf,
nWidth, nHeight, IMAGE_FORMAT_BGRA8888, flGamma, false ) )
{
Shutdown();
}
else
{
DownloadTexture();
}
}
//-----------------------------------------------------------------------------
// Gets the current TGA
//-----------------------------------------------------------------------------
const char *CTGAPreviewPanel::GetTGA() const
{
return m_TGAName;
}

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