2025-05-17 14:11:58 -04:00
//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============//
2010-07-22 01:46:14 -05:00
//
// Purpose: Client handler implementations for instruction players how to play
//
//=============================================================================//
# include "cbase.h"
# include "c_gameinstructor.h"
# include "c_baselesson.h"
# include "filesystem.h"
# include "vprof.h"
# include "ixboxsystem.h"
# include "tier0/icommandline.h"
# include "iclientmode.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
PRECACHE_REGISTER_BEGIN ( GLOBAL , GameinstructorIcons )
PRECACHE ( KV_DEP_FILE , " scripts/instructor_texturemanifest.txt " )
PRECACHE_REGISTER_END ( )
# define MOD_DIR "MOD"
# define GAMEINSTRUCTOR_SCRIPT_FILE "scripts / instructor_lessons.txt"
# define GAMEINSTRUCTOR_MOD_SCRIPT_FILE "scripts / mod_lessons.txt"
// Game instructor auto game system instantiation
C_GameInstructor g_GameInstructor [ MAX_SPLITSCREEN_PLAYERS ] ;
C_GameInstructor & GetGameInstructor ( )
{
ASSERT_LOCAL_PLAYER_RESOLVABLE ( ) ;
return g_GameInstructor [ GET_ACTIVE_SPLITSCREEN_SLOT ( ) ] ;
}
ConVar gameinstructor_verbose ( " gameinstructor_verbose " , " 0 " , FCVAR_CHEAT , " Set to 1 for standard debugging or 2 (in combo with gameinstructor_verbose_lesson) to show update actions . " ) ;
ConVar gameinstructor_verbose_lesson ( " gameinstructor_verbose_lesson " , " " , FCVAR_CHEAT , " Display more verbose information for lessons have this name. " ) ;
ConVar gameinstructor_find_errors ( " gameinstructor_find_errors " , " 0 " , FCVAR_CHEAT , " Set to 1 and the game instructor will run EVERY scripted command to uncover errors. " ) ;
void GameInstructorEnable_ChangeCallback ( IConVar * var , const char * pOldValue , float flOldValue ) ;
ConVar gameinstructor_enable ( " gameinstructor_enable " , " 1 " , FCVAR_CLIENTDLL | FCVAR_ARCHIVE , " Display in game lessons that teach new players. " , GameInstructorEnable_ChangeCallback ) ;
extern ConVar sv_gameinstructor_disable ;
ConVar gameinstructor_start_sound_cooldown ( " gameinstructor_start_sound_cooldown " , " 4.0 " , FCVAR_NONE , " Number of seconds forced between similar lesson start sounds. " ) ;
// Enable or Disable the game instructor based on the client setting
void EnableDisableInstructor ( void )
{
bool bEnabled = ( ! sv_gameinstructor_disable . GetBool ( ) & & gameinstructor_enable . GetBool ( ) ) ;
if ( bEnabled )
{
// Game instructor has been enabled, so init it!
GetGameInstructor ( ) . Init ( ) ;
}
else
{
// Game instructor has been disabled, so shut it down!
GetGameInstructor ( ) . Shutdown ( ) ;
}
}
void GameInstructorEnable_ChangeCallback ( IConVar * var , const char * pOldValue , float flOldValue )
{
for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS ; + + i )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( i ) ;
if ( ( flOldValue ! = 0.0f ) ! = gameinstructor_enable . GetBool ( ) )
{
EnableDisableInstructor ( ) ;
}
}
}
void SVGameInstructorDisable_ChangeCallback ( IConVar * var , const char * pOldValue , float flOldValue ) ;
ConVar sv_gameinstructor_disable ( " sv_gameinstructor_disable " , " 0 " , FCVAR_REPLICATED , " Force all clients to disable their game instructors. " , SVGameInstructorDisable_ChangeCallback ) ;
void SVGameInstructorDisable_ChangeCallback ( IConVar * var , const char * pOldValue , float flOldValue )
{
if ( ! engine )
return ;
for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS ; + + i )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( i ) ;
EnableDisableInstructor ( ) ;
}
}
//
// C_GameInstructor
//
bool C_GameInstructor : : Init ( void )
{
// Make sure split slot is up to date
for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS ; + + i )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( i ) ;
if ( & GetGameInstructor ( ) = = this )
{
SetSlot ( i ) ;
break ;
}
}
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
if ( ! gameinstructor_enable . GetBool ( ) | | sv_gameinstructor_disable . GetBool ( ) )
{
// Don't init if it's disabled
return true ;
}
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Initializing... \n " ) ;
}
m_bNoDraw = false ;
m_bHiddenDueToOtherElements = false ;
m_iCurrentPriority = 0 ;
m_hLastSpectatedPlayer = NULL ;
m_bSpectatedPlayerChanged = false ;
m_szPreviousStartSound [ 0 ] = ' \0 ' ;
m_fNextStartSoundTime = 0 ;
ReadLessonsFromFile ( GAMEINSTRUCTOR_MOD_SCRIPT_FILE ) ;
ReadLessonsFromFile ( GAMEINSTRUCTOR_SCRIPT_FILE ) ;
InitLessonPrerequisites ( ) ;
ReadSaveData ( ) ;
ListenForGameEvent ( " gameinstructor_draw " ) ;
ListenForGameEvent ( " gameinstructor_nodraw " ) ;
ListenForGameEvent ( " round_end " ) ;
ListenForGameEvent ( " round_start " ) ;
ListenForGameEvent ( " player_death " ) ;
ListenForGameEvent ( " player_team " ) ;
ListenForGameEvent ( " player_disconnect " ) ;
ListenForGameEvent ( " map_transition " ) ;
ListenForGameEvent ( " game_newmap " ) ;
ListenForGameEvent ( " set_instructor_group_enabled " ) ;
EvaluateLessonsForGameRules ( ) ;
return true ;
}
void C_GameInstructor : : Shutdown ( void )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Shutting down... \n " ) ;
}
CloseAllOpenOpportunities ( ) ;
WriteSaveData ( ) ;
// Clear out all the lessons
for ( int i = 0 ; i < m_Lessons . Count ( ) ; + + i )
{
if ( m_Lessons [ i ] )
{
m_Lessons [ i ] - > StopListeningForAllEvents ( ) ;
delete m_Lessons [ i ] ;
m_Lessons [ i ] = NULL ;
}
}
m_Lessons . RemoveAll ( ) ;
m_LessonGroupConVarToggles . RemoveAll ( ) ;
// Stop listening for events
StopListeningForAllEvents ( ) ;
}
void C_GameInstructor : : UpdateHiddenByOtherElements ( void )
{
bool bHidden = Mod_HiddenByOtherElements ( ) ;
if ( bHidden & & ! m_bHiddenDueToOtherElements )
{
StopAllLessons ( ) ;
}
m_bHiddenDueToOtherElements = bHidden ;
}
void C_GameInstructor : : Update ( float frametime )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
VPROF_BUDGET ( " C_GameInstructor::Update " , " GameInstructor " ) ;
UpdateHiddenByOtherElements ( ) ;
if ( ! gameinstructor_enable . GetBool ( ) | | m_bNoDraw | | m_bHiddenDueToOtherElements )
{
// Don't update if disabled or hidden
return ;
}
if ( gameinstructor_find_errors . GetBool ( ) )
{
FindErrors ( ) ;
gameinstructor_find_errors . SetValue ( 0 ) ;
}
if ( IsConsole ( ) )
{
// On X360 we want to save when they're not connected
if ( ! engine - > IsInGame ( ) )
{
// They aren't in game
WriteSaveData ( ) ;
}
else
{
const char * levelName = engine - > GetLevelName ( ) ;
if ( levelName & & levelName [ 0 ] & & engine - > IsLevelMainMenuBackground ( ) )
{
// The are in game, but it's a background map
WriteSaveData ( ) ;
}
}
}
if ( m_bSpectatedPlayerChanged )
{
// Safe spot to clean out stale lessons if spectator changed
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Spectated player changed... \n " ) ;
}
CloseAllOpenOpportunities ( ) ;
m_bSpectatedPlayerChanged = false ;
}
// Loop through all the lesson roots and reset their active status
for ( int i = m_OpenOpportunities . Count ( ) - 1 ; i > = 0 ; - - i )
{
CBaseLesson * pLesson = m_OpenOpportunities [ i ] ;
CBaseLesson * pRootLesson = pLesson - > GetRoot ( ) ;
if ( pRootLesson - > InstanceType ( ) = = LESSON_INSTANCE_SINGLE_ACTIVE )
{
pRootLesson - > SetInstanceActive ( false ) ;
}
}
int iCurrentPriority = 0 ;
// Loop through all the open lessons
for ( int i = m_OpenOpportunities . Count ( ) - 1 ; i > = 0 ; - - i )
{
CBaseLesson * pLesson = m_OpenOpportunities [ i ] ;
if ( ! pLesson - > IsOpenOpportunity ( ) | | pLesson - > IsTimedOut ( ) )
{
// This opportunity has closed
CloseOpportunity ( pLesson ) ;
continue ;
}
// Lesson should be displayed, so it can affect priority
CBaseLesson * pRootLesson = pLesson - > GetRoot ( ) ;
bool bShouldDisplay = pLesson - > ShouldDisplay ( ) ;
bool bIsLocked = pLesson - > IsLocked ( ) ;
if ( ( bShouldDisplay | | bIsLocked ) & &
( pLesson - > GetPriority ( ) > = m_iCurrentPriority | | pLesson - > NoPriority ( ) | | bIsLocked ) & &
( pRootLesson & & ( pRootLesson - > InstanceType ( ) ! = LESSON_INSTANCE_SINGLE_ACTIVE | | ! pRootLesson - > IsInstanceActive ( ) ) ) )
{
// Lesson is at the highest priority level, isn't violating instance rules, and has met all the prerequisites
if ( UpdateActiveLesson ( pLesson , pRootLesson ) | | pRootLesson - > IsLearned ( ) )
{
// Lesson is active
if ( pLesson - > IsVisible ( ) | | pRootLesson - > IsLearned ( ) )
{
pRootLesson - > SetInstanceActive ( true ) ;
if ( iCurrentPriority < pLesson - > GetPriority ( ) & & ! pLesson - > NoPriority ( ) )
{
// This active or learned lesson has the highest priority so far
iCurrentPriority = pLesson - > GetPriority ( ) ;
}
}
}
else
{
// On second thought, this shouldn't have been displayed
bShouldDisplay = false ;
}
}
else
{
// Lesson shouldn't be displayed right now
UpdateInactiveLesson ( pLesson ) ;
}
}
// Set the priority for next frame
if ( gameinstructor_verbose . GetInt ( ) > 1 & & m_iCurrentPriority ! = iCurrentPriority )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Priority changed from " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseClose , " %i " , m_iCurrentPriority ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " to " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseOpen , " %i " , iCurrentPriority ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " . \n " ) ;
}
m_iCurrentPriority = iCurrentPriority ;
}
void C_GameInstructor : : FireGameEvent ( IGameEvent * event )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
VPROF_BUDGET ( " C_GameInstructor::FireGameEvent " , " GameInstructor " ) ;
const char * name = event - > GetName ( ) ;
if ( Q_strcmp ( name , " gameinstructor_draw " ) = = 0 )
{
if ( m_bNoDraw )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Set to draw... \n " ) ;
}
m_bNoDraw = false ;
}
}
else if ( Q_strcmp ( name , " gameinstructor_nodraw " ) = = 0 )
{
if ( ! m_bNoDraw )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Set to not draw... \n " ) ;
}
m_bNoDraw = true ;
StopAllLessons ( ) ;
}
}
else if ( Q_strcmp ( name , " round_end " ) = = 0 )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Round ended... \n " ) ;
}
CloseAllOpenOpportunities ( ) ;
if ( IsPC ( ) )
{
// Good place to backup our counts
WriteSaveData ( ) ;
}
}
else if ( Q_strcmp ( name , " round_start " ) = = 0 )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Round started... \n " ) ;
}
CloseAllOpenOpportunities ( ) ;
EvaluateLessonsForGameRules ( ) ;
}
else if ( Q_strcmp ( name , " player_death " ) = = 0 )
{
# if !defined(NO_STEAM) && defined(USE_CEG)
Steamworks_TestSecret ( ) ;
Steamworks_SelfCheck ( ) ;
# endif
C_BasePlayer * pLocalPlayer = GetLocalPlayer ( ) ;
if ( pLocalPlayer & & pLocalPlayer = = UTIL_PlayerByUserId ( event - > GetInt ( " userid " ) ) )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Local player died... \n " ) ;
}
for ( int i = m_OpenOpportunities . Count ( ) - 1 ; i > = 0 ; - - i )
{
CBaseLesson * pLesson = m_OpenOpportunities [ i ] ;
CBaseLesson * pRootLesson = pLesson - > GetRoot ( ) ;
if ( ! pRootLesson - > CanOpenWhenDead ( ) )
{
CloseOpportunity ( pLesson ) ;
}
}
}
}
else if ( Q_strcmp ( name , " player_team " ) = = 0 )
{
C_BasePlayer * pLocalPlayer = GetLocalPlayer ( ) ;
if ( pLocalPlayer & & pLocalPlayer = = UTIL_PlayerByUserId ( event - > GetInt ( " userid " ) ) & &
( event - > GetInt ( " team " ) ! = event - > GetInt ( " oldteam " ) | | event - > GetBool ( " disconnect " ) ) )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Local player changed team (or disconnected)... \n " ) ;
}
CloseAllOpenOpportunities ( ) ;
}
EvaluateLessonsForGameRules ( ) ;
}
else if ( Q_strcmp ( name , " player_disconnect " ) = = 0 )
{
C_BasePlayer * pLocalPlayer = GetLocalPlayer ( ) ;
if ( pLocalPlayer & & pLocalPlayer = = UTIL_PlayerByUserId ( event - > GetInt ( " userid " ) ) )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Local player disconnected... \n " ) ;
}
CloseAllOpenOpportunities ( ) ;
}
}
else if ( Q_strcmp ( name , " map_transition " ) = = 0 )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Map transition... \n " ) ;
}
CloseAllOpenOpportunities ( ) ;
if ( m_bNoDraw )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( Color ( 255 , 128 , 64 , 255 ) , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( Color ( 64 , 128 , 255 , 255 ) , " Set to draw... \n " ) ;
}
m_bNoDraw = false ;
}
if ( IsPC ( ) )
{
// Good place to backup our counts
WriteSaveData ( ) ;
}
}
else if ( Q_strcmp ( name , " game_newmap " ) = = 0 )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " New map... \n " ) ;
}
CloseAllOpenOpportunities ( ) ;
if ( m_bNoDraw )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( Color ( 255 , 128 , 64 , 255 ) , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( Color ( 64 , 128 , 255 , 255 ) , " Set to draw... \n " ) ;
}
m_bNoDraw = false ;
}
if ( IsPC ( ) )
{
// Good place to backup our counts
WriteSaveData ( ) ;
}
}
else if ( Q_strcmp ( name , " set_instructor_group_enabled " ) = = 0 )
{
const char * pszGroup = event - > GetString ( " group " ) ;
bool bEnabled = event - > GetInt ( " enabled " ) ! = 0 ;
if ( pszGroup & & pszGroup [ 0 ] )
{
SetLessonGroupEnabled ( pszGroup , bEnabled ) ;
}
}
}
void C_GameInstructor : : DefineLesson ( CBaseLesson * pLesson )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Lesson " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseName , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " defined. \n " ) ;
}
m_Lessons . AddToTail ( pLesson ) ;
}
const CBaseLesson * C_GameInstructor : : GetLesson ( const char * pchLessonName )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
return GetLesson_Internal ( pchLessonName ) ;
}
bool C_GameInstructor : : IsLessonOfSameTypeOpen ( const CBaseLesson * pLesson ) const
{
for ( int i = 0 ; i < m_OpenOpportunities . Count ( ) ; + + i )
{
CBaseLesson * pOpenOpportunity = m_OpenOpportunities [ i ] ;
if ( pOpenOpportunity - > GetNameSymbol ( ) = = pLesson - > GetNameSymbol ( ) )
{
return true ;
}
}
return false ;
}
bool C_GameInstructor : : ReadSaveData ( void )
{
// for external playtests, don't ever read in persisted instructor state, always start fresh
if ( CommandLine ( ) - > FindParm ( " -playtest " ) )
return true ;
if ( m_bHasLoadedSaveData )
return true ;
// Always reset state first in case storage device
// was declined or ends up in faulty state
ResetDisplaysAndSuccesses ( ) ;
m_bHasLoadedSaveData = true ;
# ifdef _X360
DevMsg ( " Read Game Instructor for splitscreen slot %d \n " , m_nSplitScreenSlot ) ;
if ( m_nSplitScreenSlot < 0 )
return false ;
if ( m_nSplitScreenSlot > = ( int ) XBX_GetNumGameUsers ( ) )
return false ;
int iController = XBX_GetUserId ( m_nSplitScreenSlot ) ;
if ( iController < 0 | | XBX_GetUserIsGuest ( iController ) )
{
// Can't read data for guests
return false ;
}
DWORD nStorageDevice = XBX_GetStorageDeviceId ( iController ) ;
if ( ! XBX_DescribeStorageDevice ( nStorageDevice ) )
return false ;
# endif
char szFilename [ _MAX_PATH ] ;
# ifdef _X360
if ( IsX360 ( ) )
{
XBX_MakeStorageContainerRoot ( iController , XBX_USER_SETTINGS_CONTAINER_DRIVE , szFilename , sizeof ( szFilename ) ) ;
int nLen = strlen ( szFilename ) ;
Q_snprintf ( szFilename + nLen , sizeof ( szFilename ) - nLen , " : \\ game_instructor_counts.txt " ) ;
}
else
# endif
{
Q_snprintf ( szFilename , sizeof ( szFilename ) , " save/game_instructor_counts.txt " ) ;
}
KeyValues * data = new KeyValues ( " Game Instructor Counts " ) ;
KeyValues : : AutoDelete autoDelete ( data ) ;
if ( data - > LoadFromFile ( g_pFullFileSystem , szFilename , NULL ) )
{
int nVersion = 0 ;
for ( KeyValues * pKey = data - > GetFirstSubKey ( ) ; pKey ; pKey = pKey - > GetNextTrueSubKey ( ) )
{
CBaseLesson * pLesson = GetLesson_Internal ( pKey - > GetName ( ) ) ;
if ( pLesson )
{
pLesson - > SetDisplayCount ( pKey - > GetInt ( " display " , 0 ) ) ;
pLesson - > SetSuccessCount ( pKey - > GetInt ( " success " , 0 ) ) ;
if ( Q_strcmp ( pKey - > GetName ( ) , " version number " ) = = 0 )
{
nVersion = pLesson - > GetSuccessCount ( ) ;
}
}
}
CBaseLesson * pLessonVersionNumber = GetLesson_Internal ( " version number " ) ;
if ( pLessonVersionNumber & & ! pLessonVersionNumber - > IsLearned ( ) )
{
ResetDisplaysAndSuccesses ( ) ;
pLessonVersionNumber - > SetSuccessCount ( pLessonVersionNumber - > GetSuccessLimit ( ) ) ;
m_bDirtySaveData = true ;
}
return true ;
}
// Couldn't read from the file
return false ;
}
bool C_GameInstructor : : WriteSaveData ( void )
{
if ( engine - > IsPlayingDemo ( ) )
return false ;
if ( ! m_bDirtySaveData )
return true ;
# ifdef _X360
float flPlatTime = Plat_FloatTime ( ) ;
static ConVarRef host_write_last_time ( " host_write_last_time " ) ;
if ( host_write_last_time . IsValid ( ) )
{
float flTimeSinceLastWrite = flPlatTime - host_write_last_time . GetFloat ( ) ;
if ( flTimeSinceLastWrite < 3.5f )
{
// Prevent writing to the same storage device twice in less than 3 second succession for TCR success!
// This happens after leaving a game in splitscreen.
//DevMsg( "Waiting to write Game Instructor for splitscreen slot %d... (%.1f seconds remain)\n", m_nSplitScreenSlot, 3.5f - flTimeSinceLastWrite );
return false ;
}
}
# endif
// Always mark as clean state to avoid re-entry on
// subsequent frames when storage device might be
// in a yet-unmounted state.
m_bDirtySaveData = false ;
# ifdef _X360
DevMsg ( " Write Game Instructor for splitscreen slot %d at time: %.1f \n " , m_nSplitScreenSlot , flPlatTime ) ;
if ( m_nSplitScreenSlot < 0 )
return false ;
if ( m_nSplitScreenSlot > = ( int ) XBX_GetNumGameUsers ( ) )
return false ;
int iController = XBX_GetUserId ( m_nSplitScreenSlot ) ;
if ( iController < 0 | | XBX_GetUserIsGuest ( iController ) )
{
// Can't save data for guests
return false ;
}
DWORD nStorageDevice = XBX_GetStorageDeviceId ( iController ) ;
if ( ! XBX_DescribeStorageDevice ( nStorageDevice ) )
return false ;
# endif
// Build key value data to save
KeyValues * data = new KeyValues ( " Game Instructor Counts " ) ;
KeyValues : : AutoDelete autoDelete ( data ) ;
for ( int i = 0 ; i < m_Lessons . Count ( ) ; + + i )
{
CBaseLesson * pLesson = m_Lessons [ i ] ;
int iDisplayCount = pLesson - > GetDisplayCount ( ) ;
int iSuccessCount = pLesson - > GetSuccessCount ( ) ;
if ( iDisplayCount | | iSuccessCount )
{
// We've got some data worth saving
KeyValues * pKVData = new KeyValues ( pLesson - > GetName ( ) ) ;
if ( iDisplayCount )
{
pKVData - > SetInt ( " display " , iDisplayCount ) ;
}
if ( iSuccessCount )
{
pKVData - > SetInt ( " success " , iSuccessCount ) ;
}
data - > AddSubKey ( pKVData ) ;
}
}
// Save it!
CUtlBuffer buf ( 0 , 0 , CUtlBuffer : : TEXT_BUFFER ) ;
data - > RecursiveSaveToFile ( buf , 0 ) ;
char szFilename [ _MAX_PATH ] ;
# ifdef _X360
if ( IsX360 ( ) )
{
XBX_MakeStorageContainerRoot ( iController , XBX_USER_SETTINGS_CONTAINER_DRIVE , szFilename , sizeof ( szFilename ) ) ;
int nLen = strlen ( szFilename ) ;
Q_snprintf ( szFilename + nLen , sizeof ( szFilename ) - nLen , " : \\ game_instructor_counts.txt " ) ;
}
else
# endif
{
Q_snprintf ( szFilename , sizeof ( szFilename ) , " save/game_instructor_counts.txt " ) ;
filesystem - > CreateDirHierarchy ( " save " , " MOD " ) ;
}
bool bWriteSuccess = filesystem - > WriteFile ( szFilename , MOD_DIR , buf ) ;
# ifdef _X360
if ( xboxsystem )
{
xboxsystem - > FinishContainerWrites ( iController ) ;
}
# endif
return bWriteSuccess ;
}
void C_GameInstructor : : RefreshDisplaysAndSuccesses ( void )
{
m_bHasLoadedSaveData = false ;
ReadSaveData ( ) ;
}
void C_GameInstructor : : ResetDisplaysAndSuccesses ( void )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Reset all lesson display and success counts. \n " ) ;
}
for ( int i = 0 ; i < m_Lessons . Count ( ) ; + + i )
{
m_Lessons [ i ] - > ResetDisplaysAndSuccesses ( ) ;
}
m_bDirtySaveData = false ;
}
void C_GameInstructor : : MarkDisplayed ( const char * pchLessonName )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
CBaseLesson * pLesson = GetLesson_Internal ( pchLessonName ) ;
if ( ! pLesson )
return ;
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Lesson " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseOpen , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " marked as displayed. \n " ) ;
}
if ( pLesson - > IncDisplayCount ( ) )
{
m_bDirtySaveData = true ;
}
}
void C_GameInstructor : : MarkSucceeded ( const char * pchLessonName )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
CBaseLesson * pLesson = GetLesson_Internal ( pchLessonName ) ;
if ( ! pLesson )
return ;
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Lesson " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseSuccess , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " marked as succeeded. \n " ) ;
}
if ( pLesson - > IncSuccessCount ( ) )
{
m_bDirtySaveData = true ;
}
}
void C_GameInstructor : : PlaySound ( const char * pchSoundName )
{
// emit alert sound
C_BasePlayer * pLocalPlayer = C_BasePlayer : : GetLocalPlayer ( ) ;
if ( pLocalPlayer )
{
// Local player exists
if ( pchSoundName [ 0 ] ! = ' \0 ' & & Q_strcmp ( m_szPreviousStartSound , pchSoundName ) ! = 0 )
{
Q_strcpy ( m_szPreviousStartSound , pchSoundName ) ;
m_fNextStartSoundTime = 0.0f ;
}
if ( gpGlobals - > curtime > = m_fNextStartSoundTime & & pchSoundName [ 0 ] ! = ' \0 ' )
{
// A sound was specified, so play it!
pLocalPlayer - > EmitSound ( pchSoundName ) ;
m_fNextStartSoundTime = gpGlobals - > curtime + gameinstructor_start_sound_cooldown . GetFloat ( ) ;
}
}
}
bool C_GameInstructor : : OpenOpportunity ( CBaseLesson * pLesson )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
// Get the root lesson
CBaseLesson * pRootLesson = pLesson - > GetRoot ( ) ;
if ( ! pRootLesson )
{
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Opportunity " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseClose , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " NOT opened (because root lesson could not be found). \n " ) ;
}
delete pLesson ;
return false ;
}
C_BasePlayer * pLocalPlayer = GetLocalPlayer ( ) ;
if ( ! pRootLesson - > CanOpenWhenDead ( ) & & ( ! pLocalPlayer | | ! pLocalPlayer - > IsAlive ( ) ) )
{
// If the player is dead don't allow lessons that can't be opened when dead
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Opportunity " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseClose , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " NOT opened (because player is dead and can_open_when_dead not set). \n " ) ;
}
delete pLesson ;
return false ;
}
if ( ! pRootLesson - > PrerequisitesHaveBeenMet ( ) )
{
// If the prereqs haven't been met, don't open it
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Opportunity " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseClose , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " NOT opened (because prereqs haven't been met). \n " ) ;
}
delete pLesson ;
return false ;
}
if ( pRootLesson - > InstanceType ( ) = = LESSON_INSTANCE_FIXED_REPLACE )
{
CBaseLesson * pLessonToReplace = NULL ;
CBaseLesson * pLastReplacableLesson = NULL ;
int iInstanceCount = 0 ;
// Check how many are already open
for ( int i = m_OpenOpportunities . Count ( ) - 1 ; i > = 0 ; - - i )
{
CBaseLesson * pOpenOpportunity = m_OpenOpportunities [ i ] ;
if ( pOpenOpportunity - > GetNameSymbol ( ) = = pLesson - > GetNameSymbol ( ) & &
pOpenOpportunity - > GetReplaceKeySymbol ( ) = = pLesson - > GetReplaceKeySymbol ( ) )
{
iInstanceCount + + ;
if ( pRootLesson - > ShouldReplaceOnlyWhenStopped ( ) )
{
if ( ! pOpenOpportunity - > IsInstructing ( ) )
{
pLastReplacableLesson = pOpenOpportunity ;
}
}
else
{
pLastReplacableLesson = pOpenOpportunity ;
}
if ( iInstanceCount > = pRootLesson - > GetFixedInstancesMax ( ) )
{
pLessonToReplace = pLastReplacableLesson ;
break ;
}
}
}
if ( pLessonToReplace )
{
// Take the place of the previous instance
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Opportunity " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseOpen , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " replacing open lesson of same type. \n " ) ;
}
pLesson - > TakePlaceOf ( pLessonToReplace ) ;
CloseOpportunity ( pLessonToReplace ) ;
}
else if ( iInstanceCount > = pRootLesson - > GetFixedInstancesMax ( ) )
{
// Don't add another lesson of this type
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Opportunity " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseClose , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " NOT opened (there is too many started lessons of this type). \n " ) ;
}
delete pLesson ;
return false ;
}
}
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Opportunity " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseOpen , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " opened. \n " ) ;
}
m_OpenOpportunities . AddToTail ( pLesson ) ;
return true ;
}
void C_GameInstructor : : DumpOpenOpportunities ( void )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Open lessons... \n " ) ;
for ( int i = m_OpenOpportunities . Count ( ) - 1 ; i > = 0 ; - - i )
{
CBaseLesson * pLesson = m_OpenOpportunities [ i ] ;
CBaseLesson * pRootLesson = pLesson - > GetRoot ( ) ;
Color color ;
if ( pLesson - > IsInstructing ( ) )
{
// Green
color = CBaseLesson : : m_rgbaVerboseOpen ;
}
else if ( pRootLesson - > IsLearned ( ) & & pLesson - > GetPriority ( ) > = m_iCurrentPriority )
{
// Yellow
color = CBaseLesson : : m_rgbaVerboseSuccess ;
}
else
{
// Red
color = CBaseLesson : : m_rgbaVerboseClose ;
}
ConColorMsg ( color , " \t %s \n " , pLesson - > GetName ( ) ) ;
}
}
KeyValues * C_GameInstructor : : GetScriptKeys ( void )
{
return m_pScriptKeys ;
}
C_BasePlayer * C_GameInstructor : : GetLocalPlayer ( void )
{
C_BasePlayer * pLocalPlayer = C_BasePlayer : : GetLocalPlayer ( ) ;
// If we're not a developer, don't do the special spectator hook ups
if ( ! developer . GetBool ( ) )
return pLocalPlayer ;
// If there is no local player and we're not spectating, just return that
if ( ! pLocalPlayer | | pLocalPlayer - > GetTeamNumber ( ) ! = TEAM_SPECTATOR )
return pLocalPlayer ;
// We're purely a spectator let's get lessons of the person we're spectating
C_BasePlayer * pSpectatedPlayer = NULL ;
if ( pLocalPlayer - > GetObserverMode ( ) = = OBS_MODE_IN_EYE | | pLocalPlayer - > GetObserverMode ( ) = = OBS_MODE_CHASE )
{
pSpectatedPlayer = ToBasePlayer ( pLocalPlayer - > GetObserverTarget ( ) ) ;
}
if ( m_hLastSpectatedPlayer ! = pSpectatedPlayer )
{
// We're spectating someone new! Close all the stale lessons!
m_bSpectatedPlayerChanged = true ;
m_hLastSpectatedPlayer = pSpectatedPlayer ;
}
return pSpectatedPlayer ;
}
void C_GameInstructor : : EvaluateLessonsForGameRules ( void )
{
// Enable everything by default
for ( int i = 0 ; i < m_Lessons . Count ( ) ; + + i )
{
m_Lessons [ i ] - > SetEnabled ( true ) ;
}
// Then see if we should disable anything
for ( int nConVar = 0 ; nConVar < m_LessonGroupConVarToggles . Count ( ) ; + + nConVar )
{
LessonGroupConVarToggle_t * pLessonGroupConVarToggle = & ( m_LessonGroupConVarToggles [ nConVar ] ) ;
if ( pLessonGroupConVarToggle - > var . IsValid ( ) )
{
if ( pLessonGroupConVarToggle - > var . GetBool ( ) )
{
SetLessonGroupEnabled ( pLessonGroupConVarToggle - > szLessonGroupName , false ) ;
}
}
}
}
void C_GameInstructor : : SetLessonGroupEnabled ( const char * pszGroup , bool bEnabled )
{
for ( int i = 0 ; i < m_Lessons . Count ( ) ; + + i )
{
if ( ! Q_stricmp ( pszGroup , m_Lessons [ i ] - > GetGroup ( ) ) )
{
m_Lessons [ i ] - > SetEnabled ( bEnabled ) ;
}
}
}
void C_GameInstructor : : FindErrors ( void )
{
// Loop through all the lesson and run all their scripted actions
for ( int i = 0 ; i < m_Lessons . Count ( ) ; + + i )
{
CScriptedIconLesson * pLesson = dynamic_cast < CScriptedIconLesson * > ( m_Lessons [ i ] ) ;
if ( pLesson )
{
// Process all open events
for ( int iLessonEvent = 0 ; iLessonEvent < pLesson - > GetOpenEvents ( ) . Count ( ) ; + + iLessonEvent )
{
const LessonEvent_t * pLessonEvent = & ( pLesson - > GetOpenEvents ( ) [ iLessonEvent ] ) ;
pLesson - > ProcessElements ( NULL , & ( pLessonEvent - > elements ) ) ;
}
// Process all close events
for ( int iLessonEvent = 0 ; iLessonEvent < pLesson - > GetCloseEvents ( ) . Count ( ) ; + + iLessonEvent )
{
const LessonEvent_t * pLessonEvent = & ( pLesson - > GetCloseEvents ( ) [ iLessonEvent ] ) ;
pLesson - > ProcessElements ( NULL , & ( pLessonEvent - > elements ) ) ;
}
// Process all success events
for ( int iLessonEvent = 0 ; iLessonEvent < pLesson - > GetSuccessEvents ( ) . Count ( ) ; + + iLessonEvent )
{
const LessonEvent_t * pLessonEvent = & ( pLesson - > GetSuccessEvents ( ) [ iLessonEvent ] ) ;
pLesson - > ProcessElements ( NULL , & ( pLessonEvent - > elements ) ) ;
}
// Process all on open events
for ( int iLessonEvent = 0 ; iLessonEvent < pLesson - > GetOnOpenEvents ( ) . Count ( ) ; + + iLessonEvent )
{
const LessonEvent_t * pLessonEvent = & ( pLesson - > GetOnOpenEvents ( ) [ iLessonEvent ] ) ;
pLesson - > ProcessElements ( NULL , & ( pLessonEvent - > elements ) ) ;
}
// Process all update events
for ( int iLessonEvent = 0 ; iLessonEvent < pLesson - > GetUpdateEvents ( ) . Count ( ) ; + + iLessonEvent )
{
const LessonEvent_t * pLessonEvent = & ( pLesson - > GetUpdateEvents ( ) [ iLessonEvent ] ) ;
pLesson - > ProcessElements ( NULL , & ( pLessonEvent - > elements ) ) ;
}
}
}
}
bool C_GameInstructor : : UpdateActiveLesson ( CBaseLesson * pLesson , const CBaseLesson * pRootLesson )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
VPROF_BUDGET ( " C_GameInstructor::UpdateActiveLesson " , " GameInstructor " ) ;
bool bIsOpen = pLesson - > IsInstructing ( ) ;
if ( ! bIsOpen & & ! pRootLesson - > IsLearned ( ) )
{
pLesson - > SetStartTime ( ) ;
pLesson - > Start ( ) ;
// Check to see if it successfully started
bIsOpen = ( pLesson - > IsOpenOpportunity ( ) & & pLesson - > ShouldDisplay ( ) ) ;
if ( bIsOpen )
{
// Lesson hasn't been started and hasn't been learned
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Started lesson " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseOpen , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " . \n " ) ;
}
}
else
{
pLesson - > Stop ( ) ;
pLesson - > ResetStartTime ( ) ;
}
}
if ( bIsOpen )
{
// Update the running lesson
pLesson - > Update ( ) ;
return true ;
}
else
{
pLesson - > UpdateInactive ( ) ;
return false ;
}
}
void C_GameInstructor : : UpdateInactiveLesson ( CBaseLesson * pLesson )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
VPROF_BUDGET ( " C_GameInstructor::UpdateInactiveLesson " , " GameInstructor " ) ;
if ( pLesson - > IsInstructing ( ) )
{
// Lesson hasn't been stopped
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Stopped lesson " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseClose , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " . \n " ) ;
}
pLesson - > Stop ( ) ;
pLesson - > ResetStartTime ( ) ;
}
pLesson - > UpdateInactive ( ) ;
}
CBaseLesson * C_GameInstructor : : GetLesson_Internal ( const char * pchLessonName )
{
for ( int i = 0 ; i < m_Lessons . Count ( ) ; + + i )
{
CBaseLesson * pLesson = m_Lessons [ i ] ;
if ( Q_strcmp ( pLesson - > GetName ( ) , pchLessonName ) = = 0 )
{
return pLesson ;
}
}
return NULL ;
}
void C_GameInstructor : : StopAllLessons ( void )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
// Stop all the current lessons
for ( int i = m_OpenOpportunities . Count ( ) - 1 ; i > = 0 ; - - i )
{
CBaseLesson * pLesson = m_OpenOpportunities [ i ] ;
UpdateInactiveLesson ( pLesson ) ;
}
}
void C_GameInstructor : : CloseAllOpenOpportunities ( void )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
// Clear out all the open opportunities
for ( int i = m_OpenOpportunities . Count ( ) - 1 ; i > = 0 ; - - i )
{
CBaseLesson * pLesson = m_OpenOpportunities [ i ] ;
CloseOpportunity ( pLesson ) ;
}
Assert ( m_OpenOpportunities . Count ( ) = = 0 ) ;
}
void C_GameInstructor : : CloseOpportunity ( CBaseLesson * pLesson )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
UpdateInactiveLesson ( pLesson ) ;
if ( pLesson - > WasDisplayed ( ) )
{
MarkDisplayed ( pLesson - > GetName ( ) ) ;
}
if ( gameinstructor_verbose . GetInt ( ) > 0 )
{
ConColorMsg ( CBaseLesson : : m_rgbaVerboseHeader , " GAME INSTRUCTOR: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " Opportunity " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseClose , " \" %s \" " , pLesson - > GetName ( ) ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerbosePlain , " closed for reason: " ) ;
ConColorMsg ( CBaseLesson : : m_rgbaVerboseClose , " %s \n " , pLesson - > GetCloseReason ( ) ) ;
}
pLesson - > StopListeningForAllEvents ( ) ;
m_OpenOpportunities . FindAndRemove ( pLesson ) ;
delete pLesson ;
}
void C_GameInstructor : : ReadLessonsFromFile ( const char * pchFileName )
{
// Static init function
CScriptedIconLesson : : PreReadLessonsFromFile ( ) ;
MEM_ALLOC_CREDIT ( ) ;
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( m_nSplitScreenSlot ) ;
KeyValues * pLessonKeys = new KeyValues ( " instructor_lessons " ) ;
KeyValues : : AutoDelete autoDelete ( pLessonKeys ) ;
pLessonKeys - > LoadFromFile ( g_pFullFileSystem , pchFileName , NULL ) ;
for ( m_pScriptKeys = pLessonKeys - > GetFirstTrueSubKey ( ) ; m_pScriptKeys ; m_pScriptKeys = m_pScriptKeys - > GetNextTrueSubKey ( ) )
{
if ( Q_stricmp ( m_pScriptKeys - > GetName ( ) , " GroupConVarToggle " ) = = 0 )
{
// Add convar group toggler to the list
int nLessonGroupConVarToggle = m_LessonGroupConVarToggles . AddToTail ( LessonGroupConVarToggle_t ( m_pScriptKeys - > GetString ( " convar " ) ) ) ;
LessonGroupConVarToggle_t * pLessonGroupConVarToggle = & ( m_LessonGroupConVarToggles [ nLessonGroupConVarToggle ] ) ;
Q_strcpy ( pLessonGroupConVarToggle - > szLessonGroupName , m_pScriptKeys - > GetString ( " group " ) ) ;
continue ;
}
// Ensure that lessons aren't added twice
if ( GetLesson_Internal ( m_pScriptKeys - > GetName ( ) ) )
{
DevWarning ( " Lesson \" %s \" defined twice! \n " , m_pScriptKeys - > GetName ( ) ) ;
continue ;
}
CScriptedIconLesson * pNewLesson = new CScriptedIconLesson ( m_pScriptKeys - > GetName ( ) , false , false , m_nSplitScreenSlot ) ;
GetGameInstructor ( ) . DefineLesson ( pNewLesson ) ;
}
m_pScriptKeys = NULL ;
}
void C_GameInstructor : : InitLessonPrerequisites ( void )
{
for ( int i = 0 ; i < m_Lessons . Count ( ) ; + + i )
{
m_Lessons [ i ] - > InitPrerequisites ( ) ;
}
}
CON_COMMAND_F ( gameinstructor_reload_lessons , " Shuts down all open lessons and reloads them from the script file. " , FCVAR_CHEAT )
{
for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS ; + + i )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( i ) ;
GetGameInstructor ( ) . Shutdown ( ) ;
GetGameInstructor ( ) . Init ( ) ;
}
}
CON_COMMAND_F ( gameinstructor_reset_counts , " Resets all display and success counts to zero. " , FCVAR_NONE )
{
for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS ; + + i )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( i ) ;
GetGameInstructor ( ) . ResetDisplaysAndSuccesses ( ) ;
}
}
CON_COMMAND_F ( gameinstructor_dump_open_lessons , " Gives a list of all currently open lessons. " , FCVAR_CHEAT )
{
for ( int i = 0 ; i < MAX_SPLITSCREEN_PLAYERS ; + + i )
{
ACTIVE_SPLITSCREEN_PLAYER_GUARD ( i ) ;
GetGameInstructor ( ) . DumpOpenOpportunities ( ) ;
}
}