├── README.md ├── example.jpg ├── game ├── instructor.fgd ├── materials │ └── vgui │ │ └── hud │ │ ├── icon_arrow_down.vmt │ │ ├── icon_arrow_left.vmt │ │ ├── icon_arrow_plain.vmt │ │ ├── icon_arrow_plain.vtf │ │ ├── icon_arrow_right.vmt │ │ ├── icon_arrow_right.vtf │ │ ├── icon_arrow_up.vmt │ │ ├── icon_arrow_up.vtf │ │ ├── icon_key_down.vmt │ │ ├── icon_key_down.vtf │ │ ├── icon_key_left.vmt │ │ ├── icon_key_left.vtf │ │ ├── icon_key_right.vmt │ │ ├── icon_key_right.vtf │ │ ├── icon_key_up.vmt │ │ ├── icon_key_up.vtf │ │ ├── icon_locator_arrow.vmt │ │ ├── icon_locator_arrow.vtf │ │ ├── icon_locator_generic.vmt │ │ ├── icon_locator_generic.vtf │ │ ├── iconsheet.vmt │ │ └── iconsheet.vtf ├── resource │ ├── clientscheme.res │ ├── modevents.res │ └── ui │ │ └── locator.res └── scripts │ ├── instructor_lessons.txt │ ├── instructor_texturemanifest.txt │ └── instructor_textures.txt └── src ├── game ├── client │ ├── c_baselesson.cpp │ ├── c_baselesson.h │ ├── c_gameinstructor.cpp │ ├── c_gameinstructor.h │ ├── hud_locator_target.cpp │ └── hud_locator_target.h └── server │ └── env_instructor_hint.cpp └── public └── tier1 └── utlsymbol.h /README.md: -------------------------------------------------------------------------------- 1 | # Game Instructor 2 | 3 | This repository contains the code and assets needed to add the Source Engine Alien Swarm game instructor to the Source SDK 2013. 4 | 5 | ## ⭐ About 6 | 7 | The Game Instructor is a clientside system in charge of showing instructions on how to play or perform certain actions during gameplay. It made its first appearance in the Left 4 Dead branch of the engine and has been featured in all major Valve titles since then. 8 | 9 | ![](https://developer.valvesoftware.com/w/images/e/ef/Hint_017_show_key_bindings.jpg) 10 | 11 | ## 👨‍💻 Installation 12 | 13 | 1. Add the files from the `src` folder to your mod code. 14 | 2. Add the files from the `game` folder to the files/assets of your mod, if these files already exist it is **highly recommended to merge rather than replace**. 15 | 3. Apply the [fixes](#-fixes) to your mod code. 16 | 4. Optional but recommended, add the contents of `game/instructor.fgd` to the fgd of your mod to trigger lessons from the map editor. 17 | 18 | ## ➕ Adding lessons 19 | 20 | Lessons should be added in `game/scripts/instructor_lessons.txt`. 21 | 22 | The current file has an example lesson to show the button that has to be pressed to fire a weapon: 23 | 24 | ``` 25 | "Primary Attack" 26 | { 27 | "instance_type" "2" 28 | "caption" "Press to shoot" 29 | 30 | "onscreen_icon" "use_binding" 31 | "offscreen_icon" "icon_info" 32 | "binding" "+attack" 33 | 34 | "success_limit" "2" 35 | "timeout" "8" 36 | 37 | "open" 38 | { 39 | // Open when the code fires this event. 40 | // Example: Player has picked up a weapon. 41 | "instructor_primaryattack" 42 | { 43 | "local_player is" "player userid" 44 | "icon_target set" "player local_player" 45 | } 46 | } 47 | 48 | "success" 49 | { 50 | // Tutorial successfully completed when the code fires this event. 51 | // Example: Player has pressed the primary mouse button. 52 | "use_primaryattack" 53 | { 54 | "local_player is" "player userid" 55 | "void close" "void" 56 | } 57 | } 58 | } 59 | ``` 60 | 61 | Since there is no documentation on how to create lessons it is recommended to see the `instructor_lessons.txt` of Left 4 Dead and Alien Swarm. 62 | 63 | ## ⚠️ Triggering lessons 64 | 65 | The easiest way is to use the `env_instructor_hint` entity in Hammer, from there you can configure in a user friendly way the icon, text and other basic options. 66 | 67 | For more advanced things it will be necessary to use events triggered from the code. The example above (on how to fire a weapon) uses the `instructor_primaryattack` event to display the lesson and the `use_primaryattack` event to set it as completed. 68 | 69 | Events must be added to `game/resource/modevents.res` before they can be used in code. 70 | 71 | Now you can launch the event with the following code: 72 | 73 | ```c++ 74 | IGameEvent *pEvent = gameeventmanager->CreateEvent("instructor_primaryattack"); 75 | 76 | if (pEvent) 77 | { 78 | pEvent->SetInt("userid", GetUserID()); 79 | gameeventmanager->FireEvent(pEvent); 80 | } 81 | ``` 82 | You can get more information about [creating events here](https://developer.valvesoftware.com/wiki/Networking_Events_%26_Messages). 83 | 84 | ![](example.jpg) 85 | 86 | ## 🔧 Fixes 87 | 88 | For the repository code to work you need to make some changes to the existing code of your mod: 89 | 90 | ### `game/shared/util_shared.cpp` 91 | 92 | Look for `UTIL_StringFieldToInt` and under it add the following: 93 | 94 | ```c++ 95 | static char s_NumBitsInNibble[ 16 ] = 96 | { 97 | 0, // 0000 = 0 98 | 1, // 0001 = 1 99 | 1, // 0010 = 2 100 | 2, // 0011 = 3 101 | 1, // 0100 = 4 102 | 2, // 0101 = 5 103 | 2, // 0110 = 6 104 | 3, // 0111 = 7 105 | 1, // 1000 = 8 106 | 2, // 1001 = 9 107 | 2, // 1010 = 10 108 | 3, // 1011 = 11 109 | 2, // 1100 = 12 110 | 3, // 1101 = 13 111 | 3, // 1110 = 14 112 | 4, // 1111 = 15 113 | }; 114 | 115 | int UTIL_CountNumBitsSet( unsigned int nVar ) 116 | { 117 | int nNumBits = 0; 118 | 119 | while ( nVar > 0 ) 120 | { 121 | // Look up and add in bits in the bottom nibble 122 | nNumBits += s_NumBitsInNibble[ nVar & 0x0f ]; 123 | 124 | // Shift one nibble to the right 125 | nVar >>= 4; 126 | } 127 | 128 | return nNumBits; 129 | } 130 | 131 | int UTIL_CountNumBitsSet( uint64 nVar ) 132 | { 133 | int nNumBits = 0; 134 | 135 | while ( nVar > 0 ) 136 | { 137 | // Look up and add in bits in the bottom nibble 138 | nNumBits += s_NumBitsInNibble[ nVar & 0x0f ]; 139 | 140 | // Shift one nibble to the right 141 | nVar >>= 4; 142 | } 143 | 144 | return nNumBits; 145 | } 146 | ``` 147 | 148 | --- 149 | 150 | ### `game/shared/util_shared.h` 151 | 152 | Look for `UTIL_StringFieldToInt` and under it add the following: 153 | 154 | ```c++ 155 | int UTIL_CountNumBitsSet( unsigned int nVar ); 156 | int UTIL_CountNumBitsSet( uint64 nVar ); 157 | ``` 158 | 159 | --- 160 | 161 | ### `game/client/c_baseentity.h` 162 | 163 | Look for `GetDebugName` and under it add the following: 164 | 165 | ```c++ 166 | virtual const char *GetPlayerName() const { return NULL; } 167 | ``` 168 | 169 | --- 170 | 171 | ### ` game/client/hud.h` 172 | 173 | Look for `extern CHud gHUD;` and under it add the following: 174 | 175 | ```c++ 176 | //----------------------------------------------------------------------------- 177 | // Purpose: CHudIcons 178 | //----------------------------------------------------------------------------- 179 | class CHudIcons 180 | { 181 | public: 182 | CHudIcons(); 183 | ~CHudIcons(); 184 | 185 | void Init(); 186 | void Shutdown(); 187 | 188 | CHudTexture *GetIcon( const char *szIcon ); 189 | 190 | // loads a new icon into the list, without duplicates 191 | CHudTexture *AddUnsearchableHudIconToList( CHudTexture& texture ); 192 | CHudTexture *AddSearchableHudIconToList( CHudTexture& texture ); 193 | 194 | void RefreshHudTextures(); 195 | 196 | private: 197 | 198 | void SetupNewHudTexture( CHudTexture *t ); 199 | bool m_bHudTexturesLoaded; 200 | // Global list of known icons 201 | CUtlDict< CHudTexture *, int > m_Icons; 202 | 203 | }; 204 | 205 | CHudIcons &HudIcons(); 206 | ``` 207 | 208 | --- 209 | 210 | ### `game/client/hud.cpp` 211 | 212 | At the end of the file add: 213 | 214 | ```c++ 215 | CHudIcons::CHudIcons() : 216 | m_bHudTexturesLoaded( false ) 217 | { 218 | } 219 | 220 | CHudIcons::~CHudIcons() 221 | { 222 | int c = m_Icons.Count(); 223 | for ( int i = c - 1; i >= 0; i-- ) 224 | { 225 | CHudTexture *tex = m_Icons[ i ]; 226 | g_HudTextureMemoryPool.Free( tex ); 227 | } 228 | m_Icons.Purge(); 229 | } 230 | 231 | void CHudIcons::Init() 232 | { 233 | if ( m_bHudTexturesLoaded ) 234 | return; 235 | 236 | m_bHudTexturesLoaded = true; 237 | CUtlDict< CHudTexture *, int > textureList; 238 | 239 | // check to see if we have sprites for this res; if not, step down 240 | LoadHudTextures( textureList, "scripts/hud_textures", NULL ); 241 | LoadHudTextures( textureList, "scripts/mod_textures", NULL ); 242 | 243 | LoadHudTextures( textureList, "scripts/instructor_textures", NULL ); 244 | LoadHudTextures( textureList, "scripts/instructor_modtextures", NULL ); 245 | 246 | int c = textureList.Count(); 247 | for ( int index = 0; index < c; index++ ) 248 | { 249 | CHudTexture* tex = textureList[ index ]; 250 | AddSearchableHudIconToList( *tex ); 251 | } 252 | 253 | FreeHudTextureList( textureList ); 254 | } 255 | 256 | void CHudIcons::Shutdown() 257 | { 258 | m_bHudTexturesLoaded = false; 259 | } 260 | 261 | //----------------------------------------------------------------------------- 262 | // Purpose: 263 | //----------------------------------------------------------------------------- 264 | CHudTexture *CHudIcons::AddUnsearchableHudIconToList( CHudTexture& texture ) 265 | { 266 | // These names are composed based on the texture file name 267 | char composedName[ 512 ]; 268 | 269 | if ( texture.bRenderUsingFont ) 270 | { 271 | Q_snprintf( composedName, sizeof( composedName ), "%s_c%i", 272 | texture.szTextureFile, texture.cCharacterInFont ); 273 | } 274 | else 275 | { 276 | Q_snprintf( composedName, sizeof( composedName ), "%s_%i_%i_%i_%i", 277 | texture.szTextureFile, texture.rc.left, texture.rc.top, texture.rc.right, texture.rc.bottom ); 278 | } 279 | 280 | CHudTexture *icon = GetIcon( composedName ); 281 | if ( icon ) 282 | { 283 | return icon; 284 | } 285 | 286 | CHudTexture *newTexture = ( CHudTexture * )g_HudTextureMemoryPool.Alloc(); 287 | *newTexture = texture; 288 | 289 | SetupNewHudTexture( newTexture ); 290 | 291 | int idx = m_Icons.Insert( composedName, newTexture ); 292 | return m_Icons[ idx ]; 293 | } 294 | 295 | //----------------------------------------------------------------------------- 296 | // Purpose: 297 | //----------------------------------------------------------------------------- 298 | CHudTexture *CHudIcons::AddSearchableHudIconToList( CHudTexture& texture ) 299 | { 300 | CHudTexture *icon = GetIcon( texture.szShortName ); 301 | if ( icon ) 302 | { 303 | return icon; 304 | } 305 | 306 | CHudTexture *newTexture = ( CHudTexture * )g_HudTextureMemoryPool.Alloc(); 307 | *newTexture = texture; 308 | 309 | SetupNewHudTexture( newTexture ); 310 | 311 | int idx = m_Icons.Insert( texture.szShortName, newTexture ); 312 | return m_Icons[ idx ]; 313 | } 314 | 315 | //----------------------------------------------------------------------------- 316 | // Purpose: returns a pointer to an icon in the list 317 | //----------------------------------------------------------------------------- 318 | CHudTexture *CHudIcons::GetIcon( const char *szIcon ) 319 | { 320 | int i = m_Icons.Find( szIcon ); 321 | if ( i == m_Icons.InvalidIndex() ) 322 | return NULL; 323 | 324 | return m_Icons[ i ]; 325 | } 326 | 327 | //----------------------------------------------------------------------------- 328 | // Purpose: Gets texture handles for the hud icon 329 | //----------------------------------------------------------------------------- 330 | void CHudIcons::SetupNewHudTexture( CHudTexture *t ) 331 | { 332 | if ( t->bRenderUsingFont ) 333 | { 334 | vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); 335 | t->hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( t->szTextureFile, true ); 336 | t->rc.top = 0; 337 | t->rc.left = 0; 338 | t->rc.right = vgui::surface()->GetCharacterWidth( t->hFont, t->cCharacterInFont ); 339 | t->rc.bottom = vgui::surface()->GetFontTall( t->hFont ); 340 | } 341 | else 342 | { 343 | // Set up texture id and texture coordinates 344 | t->textureId = vgui::surface()->CreateNewTextureID(); 345 | vgui::surface()->DrawSetTextureFile( t->textureId, t->szTextureFile, false, false ); 346 | 347 | int wide, tall; 348 | vgui::surface()->DrawGetTextureSize( t->textureId, wide, tall ); 349 | 350 | t->texCoords[ 0 ] = (float)(t->rc.left + 0.5f) / (float)wide; 351 | t->texCoords[ 1 ] = (float)(t->rc.top + 0.5f) / (float)tall; 352 | t->texCoords[ 2 ] = (float)(t->rc.right - 0.5f) / (float)wide; 353 | t->texCoords[ 3 ] = (float)(t->rc.bottom - 0.5f) / (float)tall; 354 | } 355 | } 356 | 357 | //----------------------------------------------------------------------------- 358 | // Purpose: 359 | //----------------------------------------------------------------------------- 360 | void CHudIcons::RefreshHudTextures() 361 | { 362 | if ( !m_bHudTexturesLoaded ) 363 | { 364 | Assert( 0 ); 365 | return; 366 | } 367 | 368 | CUtlDict< CHudTexture *, int > textureList; 369 | 370 | // check to see if we have sprites for this res; if not, step down 371 | LoadHudTextures( textureList, "scripts/hud_textures", NULL ); 372 | LoadHudTextures( textureList, "scripts/mod_textures", NULL ); 373 | 374 | LoadHudTextures( textureList, "scripts/instructor_textures", NULL ); 375 | LoadHudTextures( textureList, "scripts/instructor_modtextures", NULL ); 376 | 377 | // fix up all the texture icons first 378 | int c = textureList.Count(); 379 | for ( int index = 0; index < c; index++ ) 380 | { 381 | CHudTexture *tex = textureList[ index ]; 382 | Assert( tex ); 383 | 384 | CHudTexture *icon = GetIcon( tex->szShortName ); 385 | if ( !icon ) 386 | continue; 387 | 388 | // Update file 389 | Q_strncpy( icon->szTextureFile, tex->szTextureFile, sizeof( icon->szTextureFile ) ); 390 | 391 | if ( !icon->bRenderUsingFont ) 392 | { 393 | // Update subrect 394 | icon->rc = tex->rc; 395 | 396 | // Keep existing texture id, but now update texture file and texture coordinates 397 | vgui::surface()->DrawSetTextureFile( icon->textureId, icon->szTextureFile, false, false ); 398 | 399 | // Get new texture dimensions in case it changed 400 | int wide, tall; 401 | vgui::surface()->DrawGetTextureSize( icon->textureId, wide, tall ); 402 | 403 | // Assign coords 404 | icon->texCoords[ 0 ] = (float)(icon->rc.left + 0.5f) / (float)wide; 405 | icon->texCoords[ 1 ] = (float)(icon->rc.top + 0.5f) / (float)tall; 406 | icon->texCoords[ 2 ] = (float)(icon->rc.right - 0.5f) / (float)wide; 407 | icon->texCoords[ 3 ] = (float)(icon->rc.bottom - 0.5f) / (float)tall; 408 | } 409 | } 410 | 411 | FreeHudTextureList( textureList ); 412 | 413 | // fixup all the font icons 414 | vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); 415 | for (int i = m_Icons.First(); m_Icons.IsValidIndex(i); i = m_Icons.Next(i)) 416 | { 417 | CHudTexture *icon = m_Icons[i]; 418 | if ( !icon ) 419 | continue; 420 | 421 | // Update file 422 | if ( icon->bRenderUsingFont ) 423 | { 424 | icon->hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( icon->szTextureFile, true ); 425 | icon->rc.top = 0; 426 | icon->rc.left = 0; 427 | icon->rc.right = vgui::surface()->GetCharacterWidth( icon->hFont, icon->cCharacterInFont ); 428 | icon->rc.bottom = vgui::surface()->GetFontTall( icon->hFont ); 429 | } 430 | } 431 | } 432 | 433 | 434 | static CHudIcons g_HudIcons; 435 | 436 | CHudIcons &HudIcons() 437 | { 438 | return g_HudIcons; 439 | } 440 | ``` 441 | 442 | In the same file, look for the function `CHud::Init` and inside at the end add: 443 | 444 | ```c++ 445 | HudIcons().Init(); 446 | ``` 447 | 448 | --- 449 | 450 | ### `public/tier1/convar.h` 451 | 452 | Look for `GetInt( void ) const;` and under it add the following: 453 | 454 | ```c++ 455 | FORCEINLINE_CVAR Color GetColor( void ) const; 456 | ``` 457 | 458 | In the same file, look for: 459 | 460 | ``` 461 | //----------------------------------------------------------------------------- 462 | // Purpose: Return ConVar value as an int 463 | // Output : int 464 | //----------------------------------------------------------------------------- 465 | FORCEINLINE_CVAR int ConVar::GetInt( void ) const 466 | { 467 | return m_pParent->m_nValue; 468 | } 469 | ``` 470 | 471 | and under it add the following: 472 | 473 | ```c++ 474 | //----------------------------------------------------------------------------- 475 | // Purpose: Return ConVar value as a color 476 | // Output : Color 477 | //----------------------------------------------------------------------------- 478 | FORCEINLINE_CVAR Color ConVar::GetColor( void ) const 479 | { 480 | unsigned char *pColorElement = ((unsigned char *)&m_pParent->m_nValue); 481 | return Color( pColorElement[0], pColorElement[1], pColorElement[2], pColorElement[3] ); 482 | } 483 | ``` 484 | 485 | To finish, add the following below the `#include` at the beginning of the file: 486 | 487 | ```c++ 488 | #include "color.h" 489 | ``` -------------------------------------------------------------------------------- /example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/example.jpg -------------------------------------------------------------------------------- /game/instructor.fgd: -------------------------------------------------------------------------------- 1 | @PointClass base(Targetname) = env_instructor_hint : "An entity that allows for creation and control of instructor lessons by map logic" 2 | [ 3 | hint_replace_key(string) : "Replace Key" : : "Unique name so that messages with the same key will replace each other." 4 | hint_target(target_destination) : "Target Entity" : : "The entity to show this hint on top of. The entity used must exist on the client, info_target_instructor_hint can be parented to server only entities for this purpose." 5 | hint_static(Choices) : "Positioning" : 0 : "Either show at the position of the Target Entity. Or show the hint directly on the hud at a fixed position." = 6 | [ 7 | 0 : "Follow the Target Entity" 8 | 1 : "Show on the hud" 9 | ] 10 | 11 | hint_allow_nodraw_target(Choices) : "Allow invisible target" : 1 : "Do we allow the hint to follow entites with nodraw set?" = 12 | [ 13 | 0 : "End immediately on nodraw" 14 | 1 : "Yes" 15 | ] 16 | 17 | hint_caption(string) : "Caption" : : "The text of your hint." 18 | hint_activator_caption(string) : "Activator Caption" : : "The text of your hint shown to only the activating player." 19 | hint_color(color255) : "Caption Color" : "255 255 255" : "The color of the caption text" 20 | hint_forcecaption(Choices) : "Force caption" : 0 : "Do we show the caption text even if the hint is occluded by a wall?" = 21 | [ 22 | 0 : "No" 23 | 1 : "Show when occluded" 24 | ] 25 | 26 | hint_icon_onscreen(Choices) : "Onscreen Icon" : "icon_tip" : "The icon to use when the hint is within the player's view." = 27 | [ 28 | "icon_bulb" : "icon_bulb" 29 | "icon_caution" : "icon_caution" 30 | "icon_alert" : "icon_alert" 31 | "icon_alert_red" : "icon_alert_red" 32 | "icon_tip" : "icon_tip" 33 | "icon_skull" : "icon_skull" 34 | "icon_no" : "icon_no" 35 | "icon_run" : "icon_run" 36 | "icon_interact" : "icon_interact" 37 | "icon_button" : "icon_button" 38 | "icon_door" : "icon_door" 39 | "icon_arrow_plain" : "icon_arrow_plain" 40 | "icon_arrow_plain_white_dn" : "icon_arrow_plain_white_dn" 41 | "icon_arrow_plain_white_up" : "icon_arrow_plain_white_up" 42 | "icon_arrow_up" : "icon_arrow_up" 43 | "icon_arrow_right" : "icon_arrow_right" 44 | "icon_fire" : "icon_fire" 45 | "icon_present" : "icon_present" 46 | "use_binding" : "show key bindings" 47 | ] 48 | 49 | hint_icon_offscreen(Choices) : "Offscreen Icon" : "icon_tip" : "The icon to use when the hint is outside the player's view." = 50 | [ 51 | "icon_bulb" : "icon_bulb" 52 | "icon_caution" : "icon_caution" 53 | "icon_alert" : "icon_alert" 54 | "icon_alert_red" : "icon_alert_red" 55 | "icon_tip" : "icon_tip" 56 | "icon_skull" : "icon_skull" 57 | "icon_no" : "icon_no" 58 | "icon_run" : "icon_run" 59 | "icon_interact" : "icon_interact" 60 | "icon_button" : "icon_button" 61 | "icon_door" : "icon_door" 62 | "icon_arrow_plain" : "icon_arrow_plain" 63 | "icon_arrow_plain_white_dn" : "icon_arrow_plain_white_dn" 64 | "icon_arrow_plain_white_up" : "icon_arrow_plain_white_up" 65 | "icon_arrow_up" : "icon_arrow_up" 66 | "icon_arrow_right" : "icon_arrow_right" 67 | "icon_fire" : "icon_fire" 68 | "icon_present" : "icon_present" 69 | ] 70 | 71 | hint_nooffscreen(Choices) : "Show offscreen" : 0 : "When the hint is offscreen, do we show an icon and arrow?" = 72 | [ 73 | 0 : "Show" 74 | 1 : "Don't show" 75 | ] 76 | 77 | hint_binding(string) : "Bound Command" : : "If using 'show key bindings' for the onscreen icon, this field should be the command we want to show bindings for" 78 | hint_icon_offset(float) : "Icon Height Offset" : 0 : "A height offset from the target entity's origin to display the hint" 79 | hint_pulseoption(Choices) : "Size Pulsing" : 0 : "The icon size can pulsate" = 80 | [ 81 | 0 : "No Pulse" 82 | 1 : "Slow Pulse" 83 | 2 : "Fast Pulse" 84 | 3 : "Urgent Pulse" 85 | ] 86 | 87 | hint_alphaoption(Choices) : "Alpha Pulsing" : 0 : "The icon alpha can pulsate" = 88 | [ 89 | 0 : "No Pulse" 90 | 1 : "Slow Pulse" 91 | 2 : "Fast Pulse" 92 | 3 : "Urgent Pulse" 93 | ] 94 | 95 | hint_shakeoption(Choices) : "Shaking" : 0 : "The icon can shake" = 96 | [ 97 | 0 : "No Shaking" 98 | 1 : "Narrow Shake" 99 | 2 : "Wide Shake" 100 | ] 101 | 102 | hint_local_player_only(boolean) : "Only Local Player" : "No" : "The hint will only be shown to the local player." 103 | 104 | hint_timeout(integer) : "Timeout" : 0 : "The automatic timeout for the hint. 0 will persist until stopped with EndHint." 105 | hint_range(float) : "Display Range" : 0 : "The visible range of the hint." 106 | 107 | input ShowHint(string) : "Start showing the hint. If an entity name is passed as a parameter, the hint is shown only to that entity." 108 | input EndHint(void) : "Stop showing the hint if it hasn't already timed out." 109 | ] 110 | 111 | @PointClass base(Targetname,Parentname) = info_target_instructor_hint : "A generic target that gets replicated to the client for hud hint targeting" 112 | [ 113 | 114 | ] -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_arrow_down.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_arrow_up" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | $basetexturetransform "center .5 .5 scale 1 1 rotate 180 translate 0 0" 11 | } 12 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_arrow_left.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_arrow_right" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | $basetexturetransform "center .5 .5 scale 1 1 rotate 180 translate 0 0" 11 | } 12 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_arrow_plain.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_arrow_plain" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | } 11 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_arrow_plain.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/game/materials/vgui/hud/icon_arrow_plain.vtf -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_arrow_right.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_arrow_right" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | } 11 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_arrow_right.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/game/materials/vgui/hud/icon_arrow_right.vtf -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_arrow_up.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_arrow_up" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | } 11 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_arrow_up.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/game/materials/vgui/hud/icon_arrow_up.vtf -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_key_down.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_key_down" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | } 11 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_key_down.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/game/materials/vgui/hud/icon_key_down.vtf -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_key_left.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_key_left" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | } 11 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_key_left.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/game/materials/vgui/hud/icon_key_left.vtf -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_key_right.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_key_right" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | } 11 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_key_right.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/game/materials/vgui/hud/icon_key_right.vtf -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_key_up.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_key_up" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | } 11 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_key_up.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/game/materials/vgui/hud/icon_key_up.vtf -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_locator_arrow.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_locator_arrow" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | } 11 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_locator_arrow.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/game/materials/vgui/hud/icon_locator_arrow.vtf -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_locator_generic.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\icon_locator_generic" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $no_fullbright 1 8 | $vertexcolor 1 9 | $minsize 100 10 | } 11 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/icon_locator_generic.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/game/materials/vgui/hud/icon_locator_generic.vtf -------------------------------------------------------------------------------- /game/materials/vgui/hud/iconsheet.vmt: -------------------------------------------------------------------------------- 1 | UnlitGeneric 2 | { 3 | $baseTexture "vgui\hud\iconsheet" 4 | $translucent 1 5 | $alpha 1 6 | $vertexalpha 1 7 | $ignorez 1 8 | $no_fullbright 1 9 | $vertexcolor 1 10 | } 11 | -------------------------------------------------------------------------------- /game/materials/vgui/hud/iconsheet.vtf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/game/materials/vgui/hud/iconsheet.vtf -------------------------------------------------------------------------------- /game/resource/clientscheme.res: -------------------------------------------------------------------------------- 1 | Scheme 2 | { 3 | //////////////////////// FONTS ///////////////////////////// 4 | // 5 | // describes all the fonts 6 | Fonts 7 | { 8 | // fonts are used in order that they are listed 9 | // fonts are used in order that they are listed 10 | "InstructorTitle" 11 | { 12 | "1" 13 | { 14 | "Name" "Trade Gothic" 15 | "tall" "16" 16 | "weight" "100" 17 | "antialias" "1" 18 | //"dropshadow" "1" 19 | } 20 | } 21 | "InstructorTitle_ss" 22 | { 23 | "1" 24 | { 25 | "Name" "Trade Gothic" 26 | "tall" "16" 27 | "weight" "100" 28 | "antialias" "1" 29 | //"dropshadow" "1" 30 | } 31 | } 32 | "InstructorTitleGlow" 33 | { 34 | "1" 35 | { 36 | "Name" "Trade Gothic" 37 | "tall" "16" 38 | "weight" "100" 39 | "antialias" "1" 40 | //"dropshadow" "1" 41 | "blur" "2" 42 | } 43 | } 44 | "InstructorTitleGlow_ss" 45 | { 46 | "1" 47 | { 48 | "Name" "Trade Gothic" 49 | "tall" "16" 50 | "weight" "100" 51 | "antialias" "1" 52 | //"dropshadow" "1" 53 | "blur" "2" 54 | } 55 | } 56 | InstructorButtons 57 | { 58 | "1" 59 | { 60 | "bitmap" "1" 61 | "name" "Buttons" 62 | "scalex" "0.65" 63 | "scaley" "0.65" 64 | } 65 | } 66 | "InstructorKeyBindings" 67 | { 68 | "1" 69 | { 70 | "name" "Trade Gothic" 71 | "tall" "11" 72 | "weight" "500" 73 | "antialias" "1" 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /game/resource/modevents.res: -------------------------------------------------------------------------------- 1 | //=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== 2 | // 3 | // The copyright to the contents herein is the property of Valve, L.L.C. 4 | // The contents may be used and/or copied only with the written permission of 5 | // Valve, L.L.C., or in accordance with the terms and conditions stipulated in 6 | // the agreement/contract under which the contents have been supplied. 7 | //============================================================================= 8 | 9 | // No spaces in event names, max length 32 10 | // All strings are case sensitive 11 | // total game event byte length must be < 1024 12 | // 13 | // valid data key types are: 14 | // none : value is not networked 15 | // string : a zero terminated string 16 | // bool : unsigned int, 1 bit 17 | // byte : unsigned int, 8 bit 18 | // short : signed int, 16 bit 19 | // long : signed int, 32 bit 20 | // float : float, 32 bit 21 | 22 | "infestedevents" 23 | { 24 | "set_instructor_group_enabled" 25 | { 26 | "group" "string" 27 | "enabled" "short" 28 | } 29 | 30 | "instructor_server_hint_create" //create a hint using data supplied entirely by the server/map. Intended for hints to smooth playtests before content is ready to make the hint unneccessary. NOT INTENDED AS A SHIPPABLE CRUTCH 31 | { 32 | "hint_name" "string" // what to name the hint. For referencing it again later (e.g. a kill command for the hint instead of a timeout) 33 | "hint_replace_key" "string" // type name so that messages of the same type will replace each other 34 | "hint_target" "long" // entity id that the hint should display at 35 | "hint_activator_userid" "short" // userid id of the activator 36 | "hint_timeout" "short" // how long in seconds until the hint automatically times out, 0 = never 37 | "hint_icon_onscreen" "string" // the hint icon to use when the hint is onscreen. e.g. "icon_alert_red" 38 | "hint_icon_offscreen" "string" // the hint icon to use when the hint is offscreen. e.g. "icon_alert" 39 | "hint_caption" "string" // the hint caption. e.g. "#ThisIsDangerous" 40 | "hint_activator_caption" "string" // the hint caption that only the activator sees e.g. "#YouPushedItGood" 41 | "hint_color" "string" // the hint color in "r,g,b" format where each component is 0-255 42 | "hint_icon_offset" "float" // how far on the z axis to offset the hint from entity origin 43 | "hint_range" "float" // range before the hint is culled 44 | "hint_flags" "long" // hint flags 45 | "hint_binding" "string" // bindings to use when use_binding is the onscreen icon 46 | "hint_allow_nodraw_target" "bool" // if false, the hint will dissappear if the target entity is invisible 47 | "hint_nooffscreen" "bool" // if true, the hint will not show when outside the player view 48 | "hint_forcecaption" "bool" // if true, the hint caption will show even if the hint is occluded 49 | "hint_local_player_only" "bool" // if true, only the local player will see the hint 50 | } 51 | 52 | "instructor_server_hint_stop" //destroys a server/map created hint 53 | { 54 | "hint_name" "string" // The hint to stop. Will stop ALL hints with this name 55 | } 56 | 57 | // Events for the sample lesson, you can edit or delete them. 58 | // See: scripts/instructor_lessons.txt 59 | "instructor_primaryattack" 60 | { 61 | "userid" "short" 62 | } 63 | "use_primaryattack" 64 | { 65 | "userid" "short" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /game/resource/ui/locator.res: -------------------------------------------------------------------------------- 1 | "Resource/UI/Locator.res" 2 | { 3 | "LocatorPanel" 4 | { 5 | "WrapStaticLocators" "1" [ ( $X360LODEF || $X360HIDEF ) ] 6 | } 7 | 8 | "LocatorBG" 9 | { 10 | "ControlName" "ImagePanel" 11 | "fieldName" "LocatorBG" 12 | "xpos" "0" 13 | "ypos" "0" 14 | "zpos" "0" 15 | "wide" "32" 16 | "tall" "32" 17 | "visible" "1" 18 | "enabled" "1" 19 | // "image" "../vgui/hud/icon_locator_generic" 20 | "scaleImage" "1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /game/scripts/instructor_lessons.txt: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------- 2 | // 3 | // This file contains all the scripted lessons used by 4 | // the game instructor. 5 | // 6 | // 7 | // PRIORITY LEVELS 8 | // 9 | // MARINE 10 | // 150 dead... switch your dude 11 | // 145 disturbance triggered 12 | // 140 infested (self) 13 | // 135 infested (other) 14 | // 130 extinguish 15 | // 125 scanner 16 | // 123 dive 17 | // 120 boss battle 18 | // 115 friendly fire 19 | // 110 button usage 20 | // 105 door welding 21 | // 100 heal self 22 | // 95 heal other 23 | // 90 presumed combat 24 | // 85 clip usage 25 | // 80 offhand 26 | // 75 switch weapon 27 | // 70-73build sentry 28 | // 65 pick up item 29 | // 60 get weapon/ammo 30 | // 55 ammo bag 31 | // 50 melee attack 32 | // 45 shoot 33 | // 35 map/general 34 | // 30 movement 35 | // 20 reload 36 | // 37 | // NOTE: Zero (0) priority lessons are NOT affected by, but NEVER affect priority 38 | // 00 notice panic button, notice finale radio, explain disturbance, open/close door, failed to take pills, get money/health/power 39 | // 40 | // INSTANCE TYPES 41 | // 42 | // 0 = multiple lessons of same type can be open at once 43 | // 1 = only one of each lesson type can be open at once 44 | // 2 = replace lesson of the same type and "replace_key" at a fixed amount "fixed_instances_max" 45 | // 3 = only one instance will display at a time (but all instances will be open) 46 | // 47 | // 48 | // FLAGS (use these to build an integer) 49 | // 50 | // 0x00000000 LOCATOR_ICON_FX_NONE 51 | // 0x00000001 LOCATOR_ICON_FX_PULSE_SLOW 52 | // 0x00000002 LOCATOR_ICON_FX_PULSE_FAST 53 | // 0x00000004 LOCATOR_ICON_FX_PULSE_URGENT 54 | // 0x00000008 LOCATOR_ICON_FX_ALPHA_SLOW 55 | // 0x00000010 LOCATOR_ICON_FX_ALPHA_FAST 56 | // 0x00000020 LOCATOR_ICON_FX_ALPHA_URGENT 57 | // 0x00000040 LOCATOR_ICON_FX_SHAKE_NARROW 58 | // 0x00000080 LOCATOR_ICON_FX_SHAKE_WIDE 59 | // 0x00000100 LOCATOR_ICON_FX_STATIC 60 | // 0x00000200 LOCATOR_ICON_FX_NO_OFFSCREEN 61 | // 0x00000400 LOCATOR_ICON_FX_FORCE_CAPTION 62 | // 0x00000800 LOCATOR_ICON_FX_FADE_OUT 63 | // 0x00001000 LOCATOR_ICON_FX_FADE_IN 64 | // 65 | // 66 | // CAPTION COLOR - supply a string in the format "rrr,ggg,bbb" ex. "255,255,255" for white 67 | // 68 | //-------------------------------------------------------- 69 | 70 | "instructor_lessons" 71 | { 72 | "version number" 73 | { 74 | "priority" "0" 75 | "success_limit" "1" // increase this number to force a reset counts for everyone 76 | } 77 | 78 | //-------------------------------------------------------- 79 | // env_instructor_hint lesson 80 | // This lesson listens for the event that is triggered by the map editor entity. 81 | //-------------------------------------------------------- 82 | "Serverside Hint" 83 | { 84 | "priority" "0" 85 | "instance_type" "2" 86 | 87 | //instance name is stored in string1 88 | "timeout" "0" 89 | "onscreen_icon" "icon_none" 90 | "offscreen_icon" "icon_none" 91 | "caption" "No Caption Specified" 92 | "caption_color" "255,255,255" 93 | "icon_offset" "0" 94 | "range" "0" 95 | "flags" "0" 96 | "binding" "" 97 | "allow_nodraw_target" "1" 98 | "no_offscreen" "0" 99 | "force_caption" "0" 100 | 101 | "open" 102 | { 103 | // Non-local player only version 104 | "instructor_server_hint_create" 105 | { 106 | "icon_target set" "player local_player" 107 | "integer1 set" "bool hint_local_player_only" 108 | "integer1 is" "int 0" 109 | "entity2 ?set" "player hint_activator_userid" 110 | "string1 ?set" "string hint_name" 111 | "replace_key ?set" "string hint_replace_key" 112 | "icon_target ?set" "entity hint_target" 113 | "timeout ?set" "int hint_timeout" 114 | "onscreen_icon ?set" "string hint_icon_onscreen" 115 | "offscreen_icon ?set" "string hint_icon_offscreen" 116 | "caption ?set" "string hint_caption" 117 | "void scope in" "void" 118 | // Special message for activator 119 | "local_player is" "player entity2" 120 | "caption ?set" "string hint_activator_caption" 121 | "void scope out" "void" 122 | "caption_color ?set" "string hint_color" 123 | "icon_offset ?set" "float hint_icon_offset" 124 | "range ?set" "float hint_range" 125 | "flags ?set" "int hint_flags" 126 | "binding ?set" "string hint_binding" 127 | "allow_nodraw_target ?set" "bool hint_allow_nodraw_target" 128 | "no_offscreen ?set" "bool hint_nooffscreen" 129 | "force_caption ?set" "bool hint_forcecaption" 130 | } 131 | 132 | // Local player only version 133 | "instructor_server_hint_create" 134 | { 135 | "icon_target set" "player local_player" 136 | "entity2 ?set" "player hint_activator_userid" 137 | "local_player is" "player entity2" 138 | "string1 ?set" "string hint_name" 139 | "replace_key ?set" "string hint_replace_key" 140 | "icon_target ?set" "entity hint_target" 141 | "timeout ?set" "int hint_timeout" 142 | "onscreen_icon ?set" "string hint_icon_onscreen" 143 | "offscreen_icon ?set" "string hint_icon_offscreen" 144 | "caption ?set" "string hint_caption" 145 | "void scope in" "void" 146 | // Special message for activator 147 | "local_player is" "player entity2" 148 | "caption ?set" "string hint_activator_caption" 149 | "void scope out" "void" 150 | "caption_color ?set" "string hint_color" 151 | "icon_offset ?set" "float hint_icon_offset" 152 | "range ?set" "float hint_range" 153 | "flags ?set" "int hint_flags" 154 | "binding ?set" "string hint_binding" 155 | "allow_nodraw_target ?set" "bool hint_allow_nodraw_target" 156 | "no_offscreen ?set" "bool hint_nooffscreen" 157 | "force_caption ?set" "bool hint_forcecaption" 158 | } 159 | } 160 | 161 | "close" 162 | { 163 | "instructor_server_hint_stop" 164 | { 165 | "string1 is" "string hint_name" 166 | } 167 | } 168 | } 169 | 170 | //-------------------------------------------------------- 171 | // Example lesson: Explain how to fire a weapon. 172 | // https://developer.valvesoftware.com/wiki/Adding_the_Game_Instructor 173 | //-------------------------------------------------------- 174 | "Primary Attack" 175 | { 176 | "instance_type" "2" 177 | "caption" "Press to shoot" 178 | 179 | "onscreen_icon" "use_binding" 180 | "offscreen_icon" "icon_info" 181 | "binding" "+attack" 182 | 183 | "success_limit" "2" 184 | "timeout" "8" 185 | 186 | "open" 187 | { 188 | // Open when the code fires this event. 189 | // Example: Player has picked up a weapon. 190 | "instructor_primaryattack" 191 | { 192 | "local_player is" "player userid" 193 | "icon_target set" "player local_player" 194 | } 195 | } 196 | 197 | "success" 198 | { 199 | // Tutorial successfully completed when the code fires this event. 200 | // Example: Player has pressed the primary mouse button. 201 | "use_primaryattack" 202 | { 203 | "local_player is" "player userid" 204 | "void close" "void" 205 | } 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /game/scripts/instructor_texturemanifest.txt: -------------------------------------------------------------------------------- 1 | GAME 2 | { 3 | "material" "vgui/hud/iconsheet" 4 | } -------------------------------------------------------------------------------- /game/scripts/instructor_textures.txt: -------------------------------------------------------------------------------- 1 | "sprites/640_hud" 2 | { 3 | TextureData 4 | { 5 | // Iconsheet from L4D2 6 | "icon_shield" 7 | { 8 | "file" "vgui/hud/iconsheet" 9 | "x" "0" 10 | "y" "0" 11 | "width" "64" 12 | "height" "64" 13 | } 14 | "icon_run" 15 | { 16 | "file" "vgui/hud/iconsheet" 17 | "x" "64" 18 | "y" "0" 19 | "width" "64" 20 | "height" "64" 21 | } 22 | "icon_noMedKit" 23 | { 24 | "file" "vgui/hud/iconsheet" 25 | "x" "128" 26 | "y" "0" 27 | "width" "64" 28 | "height" "64" 29 | } 30 | "icon_no" 31 | { 32 | "file" "vgui/hud/iconsheet" 33 | "x" "192" 34 | "y" "0" 35 | "width" "64" 36 | "height" "64" 37 | } 38 | "icon_mouseRight" 39 | { 40 | "file" "vgui/hud/iconsheet" 41 | "x" "256" 42 | "y" "0" 43 | "width" "64" 44 | "height" "64" 45 | } 46 | "icon_mouseLeft" 47 | { 48 | "file" "vgui/hud/iconsheet" 49 | "x" "320" 50 | "y" "0" 51 | "width" "64" 52 | "height" "64" 53 | } 54 | "icon_medkit" 55 | { 56 | "file" "vgui/hud/iconsheet" 57 | "x" "384" 58 | "y" "0" 59 | "width" "64" 60 | "height" "64" 61 | } 62 | "icon_interact" 63 | { 64 | "file" "vgui/hud/iconsheet" 65 | "x" "448" 66 | "y" "0" 67 | "width" "64" 68 | "height" "64" 69 | } 70 | 71 | // Row 2 72 | "icon_door" 73 | { 74 | "file" "vgui/hud/iconsheet" 75 | "x" "0" 76 | "y" "64" 77 | "width" "64" 78 | "height" "64" 79 | } 80 | "icon_button" 81 | { 82 | "file" "vgui/hud/iconsheet" 83 | "x" "64" 84 | "y" "64" 85 | "width" "64" 86 | "height" "64" 87 | } 88 | "icon_blank" 89 | { 90 | "file" "vgui/hud/iconsheet" 91 | "x" "128" 92 | "y" "64" 93 | "width" "64" 94 | "height" "64" 95 | } 96 | "icon_arrow_up" 97 | { 98 | "file" "vgui/hud/iconsheet" 99 | "x" "192" 100 | "y" "64" 101 | "width" "64" 102 | "height" "64" 103 | } 104 | "icon_arrow_right" 105 | { 106 | "file" "vgui/hud/iconsheet" 107 | "x" "256" 108 | "y" "64" 109 | "width" "64" 110 | "height" "64" 111 | } 112 | "icon_arrow_plain" 113 | { 114 | "file" "vgui/hud/iconsheet" 115 | "x" "320" 116 | "y" "64" 117 | "width" "64" 118 | "height" "64" 119 | } 120 | "icon_alert_red" 121 | { 122 | "file" "vgui/hud/iconsheet" 123 | "x" "384" 124 | "y" "64" 125 | "width" "64" 126 | "height" "64" 127 | } 128 | "icon_tip" 129 | { 130 | "file" "vgui/hud/iconsheet" 131 | "x" "448" 132 | "y" "64" 133 | "width" "64" 134 | "height" "64" 135 | } 136 | 137 | // Row 3 138 | "icon_key_right" 139 | { 140 | "file" "vgui/hud/iconsheet" 141 | "x" "0" 142 | "y" "128" 143 | "width" "64" 144 | "height" "64" 145 | } 146 | "icon_key_left" 147 | { 148 | "file" "vgui/hud/iconsheet" 149 | "x" "64" 150 | "y" "128" 151 | "width" "64" 152 | "height" "64" 153 | } 154 | "icon_key_down" 155 | { 156 | "file" "vgui/hud/iconsheet" 157 | "x" "128" 158 | "y" "128" 159 | "width" "64" 160 | "height" "64" 161 | } 162 | "icon_key_up" 163 | { 164 | "file" "vgui/hud/iconsheet" 165 | "x" "192" 166 | "y" "128" 167 | "width" "64" 168 | "height" "64" 169 | } 170 | "icon_mouseWheel_up" 171 | { 172 | "file" "vgui/hud/iconsheet" 173 | "x" "256" 174 | "y" "128" 175 | "width" "64" 176 | "height" "64" 177 | } 178 | "icon_mouseWheel_down" 179 | { 180 | "file" "vgui/hud/iconsheet" 181 | "x" "320" 182 | "y" "128" 183 | "width" "64" 184 | "height" "64" 185 | } 186 | "icon_alert" 187 | { 188 | "file" "vgui/hud/iconsheet" 189 | "x" "384" 190 | "y" "128" 191 | "width" "64" 192 | "height" "64" 193 | } 194 | "icon_key_generic" 195 | { 196 | "file" "vgui/hud/iconsheet" 197 | "x" "448" 198 | "y" "128" 199 | "width" "64" 200 | "height" "64" 201 | } 202 | 203 | // Row 4 204 | "icon_key_wide" 205 | { 206 | "file" "vgui/hud/iconsheet" 207 | "x" "0" 208 | "y" "192" 209 | "width" "128" 210 | "height" "64" 211 | } 212 | "icon_info" 213 | { 214 | "file" "vgui/hud/iconsheet" 215 | "x" "128" 216 | "y" "192" 217 | "width" "64" 218 | "height" "64" 219 | } 220 | "icon_reviving" 221 | { 222 | "file" "vgui/hud/iconsheet" 223 | "x" "192" 224 | "y" "192" 225 | "width" "64" 226 | "height" "64" 227 | } 228 | "icon_mouseThree" 229 | { 230 | "file" "vgui/hud/iconsheet" 231 | "x" "256" 232 | "y" "192" 233 | "width" "64" 234 | "height" "64" 235 | } 236 | "icon_skull" 237 | { 238 | "file" "vgui/hud/iconsheet" 239 | "x" "320" 240 | "y" "192" 241 | "width" "64" 242 | "height" "64" 243 | } 244 | "icon_arrow_plain_white_dn" 245 | { 246 | "file" "vgui/hud/iconsheet" 247 | "x" "384" 248 | "y" "192" 249 | "width" "64" 250 | "height" "64" 251 | } 252 | "icon_arrow_plain_white_up" 253 | { 254 | "file" "vgui/hud/iconsheet" 255 | "x" "448" 256 | "y" "192" 257 | "width" "64" 258 | "height" "64" 259 | } 260 | // Row 5 261 | "icon_painpills" 262 | { 263 | "file" "vgui/hud/iconsheet" 264 | "x" "0" 265 | "y" "256" 266 | "width" "64" 267 | "height" "64" 268 | } 269 | "icon_healing" 270 | { 271 | "file" "vgui/hud/iconsheet" 272 | "x" "128" 273 | "y" "320" 274 | "width" "64" 275 | "height" "64" 276 | } 277 | "icon_pipebomb" 278 | { 279 | "file" "vgui/hud/iconsheet" 280 | "x" "128" 281 | "y" "256" 282 | "width" "64" 283 | "height" "64" 284 | } 285 | "icon_molotov" 286 | { 287 | "file" "vgui/hud/iconsheet" 288 | "x" "192" 289 | "y" "256" 290 | "width" "64" 291 | "height" "64" 292 | } 293 | "icon_incendiary_ammo" 294 | { 295 | "file" "vgui/hud/iconsheet" 296 | "x" "256" 297 | "y" "448" 298 | "width" "64" 299 | "height" "64" 300 | } 301 | "icon_pistol" 302 | { 303 | "file" "vgui/hud/iconsheet" 304 | "x" "320" 305 | "y" "256" 306 | "width" "64" 307 | "height" "64" 308 | } 309 | "icon_ammo" 310 | { 311 | "file" "vgui/hud/iconsheet" 312 | "x" "256" 313 | "y" "256" 314 | "width" "64" 315 | "height" "64" 316 | } 317 | "icon_equip_flashlight_active" 318 | { 319 | "file" "vgui/hud/iconsheet" 320 | "x" "384" 321 | "y" "256" 322 | "width" "64" 323 | "height" "64" 324 | } 325 | "icon_equip_pipebomb" 326 | { 327 | "file" "vgui/hud/iconsheet" 328 | "x" "448" 329 | "y" "256" 330 | "width" "64" 331 | "height" "64" 332 | } 333 | // Row 6 334 | "icon_equip_molotov" 335 | { 336 | "file" "vgui/hud/iconsheet" 337 | "x" "0" 338 | "y" "320" 339 | "width" "64" 340 | "height" "64" 341 | } 342 | "icon_equip_pills" 343 | { 344 | "file" "vgui/hud/iconsheet" 345 | "x" "64" 346 | "y" "320" 347 | "width" "64" 348 | "height" "64" 349 | } 350 | "icon_equip_medkit" 351 | { 352 | "file" "vgui/hud/iconsheet" 353 | "x" "128" 354 | "y" "320" 355 | "width" "64" 356 | "height" "64" 357 | } 358 | "icon_equip_dualpistols" 359 | { 360 | "file" "vgui/hud/iconsheet" 361 | "x" "192" 362 | "y" "320" 363 | "width" "64" 364 | "height" "64" 365 | } 366 | "icon_equip_pistol" 367 | { 368 | "file" "vgui/hud/iconsheet" 369 | "x" "256" 370 | "y" "320" 371 | "width" "64" 372 | "height" "64" 373 | } 374 | "icon_equip_pumpshotgun" 375 | { 376 | "file" "vgui/hud/iconsheet" 377 | "x" "320" 378 | "y" "320" 379 | "width" "192" 380 | "height" "64" 381 | } 382 | // Row 7 383 | "icon_equip_uzi" 384 | { 385 | "file" "vgui/hud/iconsheet" 386 | "x" "0" 387 | "y" "384" 388 | "width" "128" 389 | "height" "64" 390 | } 391 | "icon_equip_machinegun" 392 | { 393 | "file" "vgui/hud/iconsheet" 394 | "x" "128" 395 | "y" "384" 396 | "width" "192" 397 | "height" "64" 398 | } 399 | "icon_equip_rifle" 400 | { 401 | "file" "vgui/hud/iconsheet" 402 | "x" "320" 403 | "y" "384" 404 | "width" "192" 405 | "height" "64" 406 | } 407 | // Row 8 408 | "icon_equip_autoshotgun" 409 | { 410 | "file" "vgui/hud/iconsheet" 411 | "x" "0" 412 | "y" "448" 413 | "width" "192" 414 | "height" "64" 415 | } 416 | "zombie_team_common" 417 | { 418 | "file" "vgui/hud/iconsheet" 419 | "x" "256" 420 | "y" "448" 421 | "width" "64" 422 | "height" "64" 423 | } 424 | "icon_dpad" 425 | { 426 | "file" "vgui/hud/iconsheet" 427 | "x" "192" 428 | "y" "448" 429 | "width" "64" 430 | "height" "64" 431 | } 432 | "icon_upgrade" 433 | { 434 | "file" "vgui/hud/iconsheet" 435 | "x" "320" 436 | "y" "448" 437 | "width" "64" 438 | "height" "64" 439 | } 440 | "icon_bullet" 441 | { 442 | "file" "vgui/hud/iconsheet" 443 | "x" "384" 444 | "y" "448" 445 | "width" "64" 446 | "height" "64" 447 | } 448 | "icon_equip_molotov_small" 449 | { 450 | "file" "vgui/hud/iconsheet" 451 | "x" "448" 452 | "y" "448" 453 | "width" "32" 454 | "height" "32" 455 | } 456 | "icon_equip_ammopack_small" 457 | { 458 | "file" "vgui/hud/iconsheet" 459 | "x" "480" 460 | "y" "448" 461 | "width" "32" 462 | "height" "32" 463 | } 464 | "icon_equip_adrenaline_small" 465 | { 466 | "file" "vgui/hud/iconsheet" 467 | "x" "448" 468 | "y" "480" 469 | "width" "32" 470 | "height" "32" 471 | } 472 | } 473 | } 474 | -------------------------------------------------------------------------------- /src/game/client/c_baselesson.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/src/game/client/c_baselesson.cpp -------------------------------------------------------------------------------- /src/game/client/c_baselesson.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/src/game/client/c_baselesson.h -------------------------------------------------------------------------------- /src/game/client/c_gameinstructor.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/src/game/client/c_gameinstructor.cpp -------------------------------------------------------------------------------- /src/game/client/c_gameinstructor.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/src/game/client/c_gameinstructor.h -------------------------------------------------------------------------------- /src/game/client/hud_locator_target.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/src/game/client/hud_locator_target.cpp -------------------------------------------------------------------------------- /src/game/client/hud_locator_target.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolessios/source-instructor/94d4e9963b68e9d8e3280a759d9bd8c00b154362/src/game/client/hud_locator_target.h -------------------------------------------------------------------------------- /src/game/server/env_instructor_hint.cpp: -------------------------------------------------------------------------------- 1 | //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// 2 | // 3 | // Purpose: An entity for creating instructor hints entirely with map logic 4 | // 5 | // $NoKeywords: $ 6 | //=============================================================================// 7 | 8 | #include "cbase.h" 9 | #include "baseentity.h" 10 | #include "world.h" 11 | 12 | // memdbgon must be the last include file in a .cpp file!!! 13 | #include "tier0/memdbgon.h" 14 | 15 | //----------------------------------------------------------------------------- 16 | // Purpose: 17 | //----------------------------------------------------------------------------- 18 | class CEnvInstructorHint : public CPointEntity 19 | { 20 | public: 21 | DECLARE_CLASS(CEnvInstructorHint, CPointEntity); 22 | DECLARE_DATADESC(); 23 | 24 | private: 25 | void InputShowHint(inputdata_t &inputdata); 26 | void InputEndHint(inputdata_t &inputdata); 27 | 28 | string_t m_iszReplace_Key; 29 | string_t m_iszHintTargetEntity; 30 | int m_iTimeout; 31 | string_t m_iszIcon_Onscreen; 32 | string_t m_iszIcon_Offscreen; 33 | string_t m_iszCaption; 34 | string_t m_iszActivatorCaption; 35 | color32 m_Color; 36 | float m_fIconOffset; 37 | float m_fRange; 38 | uint8 m_iPulseOption; 39 | uint8 m_iAlphaOption; 40 | uint8 m_iShakeOption; 41 | bool m_bStatic; 42 | bool m_bNoOffscreen; 43 | bool m_bForceCaption; 44 | string_t m_iszBinding; 45 | bool m_bAllowNoDrawTarget; 46 | bool m_bLocalPlayerOnly; 47 | }; 48 | 49 | LINK_ENTITY_TO_CLASS(env_instructor_hint, CEnvInstructorHint); 50 | 51 | BEGIN_DATADESC(CEnvInstructorHint) 52 | 53 | DEFINE_KEYFIELD(m_iszReplace_Key, FIELD_STRING, "hint_replace_key"), 54 | DEFINE_KEYFIELD(m_iszHintTargetEntity, FIELD_STRING, "hint_target"), 55 | DEFINE_KEYFIELD(m_iTimeout, FIELD_INTEGER, "hint_timeout"), 56 | DEFINE_KEYFIELD(m_iszIcon_Onscreen, FIELD_STRING, "hint_icon_onscreen"), 57 | DEFINE_KEYFIELD(m_iszIcon_Offscreen, FIELD_STRING, "hint_icon_offscreen"), 58 | DEFINE_KEYFIELD(m_iszCaption, FIELD_STRING, "hint_caption"), 59 | DEFINE_KEYFIELD(m_iszActivatorCaption, FIELD_STRING, "hint_activator_caption"), 60 | DEFINE_KEYFIELD(m_Color, FIELD_COLOR32, "hint_color"), 61 | DEFINE_KEYFIELD(m_fIconOffset, FIELD_FLOAT, "hint_icon_offset"), 62 | DEFINE_KEYFIELD(m_fRange, FIELD_FLOAT, "hint_range"), 63 | DEFINE_KEYFIELD(m_iPulseOption, FIELD_CHARACTER, "hint_pulseoption"), 64 | DEFINE_KEYFIELD(m_iAlphaOption, FIELD_CHARACTER, "hint_alphaoption"), 65 | DEFINE_KEYFIELD(m_iShakeOption, FIELD_CHARACTER, "hint_shakeoption"), 66 | DEFINE_KEYFIELD(m_bStatic, FIELD_BOOLEAN, "hint_static"), 67 | DEFINE_KEYFIELD(m_bNoOffscreen, FIELD_BOOLEAN, "hint_nooffscreen"), 68 | DEFINE_KEYFIELD(m_bForceCaption, FIELD_BOOLEAN, "hint_forcecaption"), 69 | DEFINE_KEYFIELD(m_iszBinding, FIELD_STRING, "hint_binding"), 70 | DEFINE_KEYFIELD(m_bAllowNoDrawTarget, FIELD_BOOLEAN, "hint_allow_nodraw_target"), 71 | DEFINE_KEYFIELD(m_bLocalPlayerOnly, FIELD_BOOLEAN, "hint_local_player_only"), 72 | 73 | DEFINE_INPUTFUNC(FIELD_STRING, "ShowHint", InputShowHint), DEFINE_INPUTFUNC(FIELD_VOID, "EndHint", InputEndHint), 74 | 75 | END_DATADESC() 76 | 77 | #define LOCATOR_ICON_FX_PULSE_SLOW 0x00000001 78 | #define LOCATOR_ICON_FX_ALPHA_SLOW 0x00000008 79 | #define LOCATOR_ICON_FX_SHAKE_NARROW 0x00000040 80 | #define LOCATOR_ICON_FX_STATIC 0x00000100 // This icon draws at a fixed location on the HUD. 81 | 82 | //----------------------------------------------------------------------------- 83 | // Purpose: Input handler for showing the message and/or playing the sound. 84 | //----------------------------------------------------------------------------- 85 | void CEnvInstructorHint::InputShowHint(inputdata_t &inputdata) 86 | { 87 | IGameEvent *event = 88 | gameeventmanager->CreateEvent("instructor_server_hint_create", false); 89 | if (event) 90 | { 91 | CBaseEntity *pTargetEntity = gEntList.FindEntityByName(NULL, m_iszHintTargetEntity); 92 | if (pTargetEntity == NULL && !m_bStatic) 93 | pTargetEntity = inputdata.pActivator; 94 | 95 | if (pTargetEntity == NULL) 96 | pTargetEntity = GetWorldEntity(); 97 | 98 | char szColorString[128]; 99 | Q_snprintf(szColorString, sizeof(szColorString), "%.3d,%.3d,%.3d", m_Color.r, m_Color.g, m_Color.b); 100 | 101 | int iFlags = 0; 102 | 103 | iFlags |= (m_iPulseOption == 0) ? 0 : (LOCATOR_ICON_FX_PULSE_SLOW << (m_iPulseOption - 1)); 104 | iFlags |= (m_iAlphaOption == 0) ? 0 : (LOCATOR_ICON_FX_ALPHA_SLOW << (m_iAlphaOption - 1)); 105 | iFlags |= (m_iShakeOption == 0) ? 0 : (LOCATOR_ICON_FX_SHAKE_NARROW << (m_iShakeOption - 1)); 106 | iFlags |= m_bStatic ? LOCATOR_ICON_FX_STATIC : 0; 107 | 108 | CBasePlayer *pActivator = NULL; 109 | bool bFilterByActivator = m_bLocalPlayerOnly; 110 | 111 | #ifdef INFESTED_DLL 112 | CASW_Marine *pMarine = dynamic_cast(inputdata.pActivator); 113 | if (pMarine) 114 | { 115 | pActivator = pMarine->GetCommander(); 116 | } 117 | #else 118 | if (inputdata.value.StringID() != NULL_STRING) 119 | { 120 | CBaseEntity *pTarget = gEntList.FindEntityByName(NULL, inputdata.value.String()); 121 | pActivator = dynamic_cast(pTarget); 122 | if (pActivator) 123 | { 124 | bFilterByActivator = true; 125 | } 126 | } 127 | else 128 | { 129 | if (GameRules()->IsMultiplayer() == false) 130 | { 131 | pActivator = UTIL_GetLocalPlayer(); 132 | } 133 | else 134 | { 135 | Warning("Failed to play server side instructor hint: no player specified for hint\n"); 136 | Assert(0); 137 | } 138 | } 139 | #endif 140 | 141 | const char *pActivatorCaption = m_iszActivatorCaption.ToCStr(); 142 | if (!pActivatorCaption || pActivatorCaption[0] == '\0') 143 | { 144 | pActivatorCaption = m_iszCaption.ToCStr(); 145 | } 146 | 147 | event->SetString("hint_name", GetEntityName().ToCStr()); 148 | event->SetString("hint_replace_key", m_iszReplace_Key.ToCStr()); 149 | event->SetInt("hint_target", pTargetEntity->entindex()); 150 | event->SetInt("hint_activator_userid", (pActivator ? pActivator->GetUserID() : 0)); 151 | event->SetInt("hint_timeout", m_iTimeout); 152 | event->SetString("hint_icon_onscreen", m_iszIcon_Onscreen.ToCStr()); 153 | event->SetString("hint_icon_offscreen", m_iszIcon_Offscreen.ToCStr()); 154 | event->SetString("hint_caption", m_iszCaption.ToCStr()); 155 | event->SetString("hint_activator_caption", pActivatorCaption); 156 | event->SetString("hint_color", szColorString); 157 | event->SetFloat("hint_icon_offset", m_fIconOffset); 158 | event->SetFloat("hint_range", m_fRange); 159 | event->SetInt("hint_flags", iFlags); 160 | event->SetString("hint_binding", m_iszBinding.ToCStr()); 161 | event->SetBool("hint_allow_nodraw_target", m_bAllowNoDrawTarget); 162 | event->SetBool("hint_nooffscreen", m_bNoOffscreen); 163 | event->SetBool("hint_forcecaption", m_bForceCaption); 164 | event->SetBool("hint_local_player_only", bFilterByActivator); 165 | 166 | gameeventmanager->FireEvent(event); 167 | } 168 | } 169 | 170 | //----------------------------------------------------------------------------- 171 | //----------------------------------------------------------------------------- 172 | void CEnvInstructorHint::InputEndHint(inputdata_t &inputdata) 173 | { 174 | IGameEvent *event = 175 | gameeventmanager->CreateEvent("instructor_server_hint_stop", false); 176 | if (event) 177 | { 178 | event->SetString("hint_name", GetEntityName().ToCStr()); 179 | 180 | gameeventmanager->FireEvent(event); 181 | } 182 | } 183 | 184 | //----------------------------------------------------------------------------- 185 | // Purpose: A generic target entity that gets replicated to the client for instructor hint targetting 186 | //----------------------------------------------------------------------------- 187 | class CInfoInstructorHintTarget : public CPointEntity 188 | { 189 | public: 190 | DECLARE_CLASS(CInfoInstructorHintTarget, CPointEntity); 191 | 192 | virtual int UpdateTransmitState(void) // set transmit filter to transmit always 193 | { 194 | return SetTransmitState(FL_EDICT_ALWAYS); 195 | } 196 | 197 | DECLARE_DATADESC(); 198 | }; 199 | 200 | LINK_ENTITY_TO_CLASS(info_target_instructor_hint, CInfoInstructorHintTarget); 201 | 202 | BEGIN_DATADESC(CInfoInstructorHintTarget) 203 | 204 | END_DATADESC() 205 | -------------------------------------------------------------------------------- /src/public/tier1/utlsymbol.h: -------------------------------------------------------------------------------- 1 | //========= Copyright Valve Corporation, All rights reserved. ============// 2 | // 3 | // Purpose: Defines a symbol table 4 | // 5 | // $Header: $ 6 | // $NoKeywords: $ 7 | //===========================================================================// 8 | 9 | #ifndef UTLSYMBOL_H 10 | #define UTLSYMBOL_H 11 | 12 | #ifdef _WIN32 13 | #pragma once 14 | #endif 15 | 16 | #include "tier0/threadtools.h" 17 | #include "tier1/utlrbtree.h" 18 | #include "tier1/utlvector.h" 19 | #include "tier1/utlbuffer.h" 20 | #include "tier1/utllinkedlist.h" 21 | #include "tier1/stringpool.h" 22 | 23 | //----------------------------------------------------------------------------- 24 | // forward declarations 25 | //----------------------------------------------------------------------------- 26 | class CUtlSymbolTable; 27 | class CUtlSymbolTableMT; 28 | 29 | //----------------------------------------------------------------------------- 30 | // This is a symbol, which is a easier way of dealing with strings. 31 | //----------------------------------------------------------------------------- 32 | typedef unsigned short UtlSymId_t; 33 | 34 | #define UTL_INVAL_SYMBOL ((UtlSymId_t)~0) 35 | 36 | class CUtlSymbol 37 | { 38 | public: 39 | // constructor, destructor 40 | CUtlSymbol() : m_Id(UTL_INVAL_SYMBOL) 41 | { 42 | } 43 | CUtlSymbol(UtlSymId_t id) : m_Id(id) 44 | { 45 | } 46 | CUtlSymbol(const char *pStr); 47 | CUtlSymbol(CUtlSymbol const &sym) : m_Id(sym.m_Id) 48 | { 49 | } 50 | 51 | // operator= 52 | CUtlSymbol &operator=(CUtlSymbol const &src) 53 | { 54 | m_Id = src.m_Id; 55 | return *this; 56 | } 57 | 58 | // operator== 59 | bool operator==(CUtlSymbol const &src) const 60 | { 61 | return m_Id == src.m_Id; 62 | } 63 | bool operator==(const char *pStr) const; 64 | 65 | // Is valid? 66 | bool IsValid() const 67 | { 68 | return m_Id != UTL_INVAL_SYMBOL; 69 | } 70 | 71 | // Gets at the symbol 72 | operator UtlSymId_t const() const 73 | { 74 | return m_Id; 75 | } 76 | 77 | // Gets the string associated with the symbol 78 | const char *String() const; 79 | 80 | // Modules can choose to disable the static symbol table so to prevent accidental use of them. 81 | static void DisableStaticSymbolTable(); 82 | 83 | protected: 84 | UtlSymId_t m_Id; 85 | 86 | // Initializes the symbol table 87 | static void Initialize(); 88 | 89 | // returns the current symbol table 90 | static CUtlSymbolTableMT *CurrTable(); 91 | 92 | // The standard global symbol table 93 | static CUtlSymbolTableMT *s_pSymbolTable; 94 | 95 | static bool s_bAllowStaticSymbolTable; 96 | 97 | friend class CCleanupUtlSymbolTable; 98 | }; 99 | 100 | //----------------------------------------------------------------------------- 101 | // CUtlSymbolTable: 102 | // description: 103 | // This class defines a symbol table, which allows us to perform mappings 104 | // of strings to symbols and back. The symbol class itself contains 105 | // a static version of this class for creating global strings, but this 106 | // class can also be instanced to create local symbol tables. 107 | // 108 | // This class stores the strings in a series of string pools. The first 109 | // two bytes of each string are decorated with a hash to speed up 110 | // comparisons. 111 | //----------------------------------------------------------------------------- 112 | 113 | class CUtlSymbolTable 114 | { 115 | public: 116 | // constructor, destructor 117 | CUtlSymbolTable(int growSize = 0, int initSize = 16, bool caseInsensitive = false); 118 | ~CUtlSymbolTable(); 119 | 120 | // Finds and/or creates a symbol based on the string 121 | CUtlSymbol AddString(const char *pString); 122 | 123 | // Finds the symbol for pString 124 | CUtlSymbol Find(const char *pString) const; 125 | 126 | // Look up the string associated with a particular symbol 127 | const char *String(CUtlSymbol id) const; 128 | 129 | // Remove all symbols in the table. 130 | void RemoveAll(); 131 | 132 | int GetNumStrings(void) const 133 | { 134 | return m_Lookup.Count(); 135 | } 136 | 137 | // We store one of these at the beginning of every string to speed 138 | // up comparisons. 139 | typedef unsigned short hashDecoration_t; 140 | 141 | protected: 142 | class CStringPoolIndex 143 | { 144 | public: 145 | inline CStringPoolIndex() 146 | { 147 | } 148 | 149 | inline CStringPoolIndex(unsigned short iPool, unsigned short iOffset) : m_iPool(iPool), m_iOffset(iOffset) 150 | { 151 | } 152 | 153 | inline bool operator==(const CStringPoolIndex &other) const 154 | { 155 | return m_iPool == other.m_iPool && m_iOffset == other.m_iOffset; 156 | } 157 | 158 | unsigned short m_iPool; // Index into m_StringPools. 159 | unsigned short m_iOffset; // Index into the string pool. 160 | }; 161 | 162 | class CLess 163 | { 164 | public: 165 | CLess(int ignored = 0) 166 | { 167 | } // permits default initialization to NULL in CUtlRBTree 168 | bool operator!() const 169 | { 170 | return false; 171 | } 172 | bool operator()(const CStringPoolIndex &left, const CStringPoolIndex &right) const; 173 | }; 174 | 175 | // Stores the symbol lookup 176 | class CTree : public CUtlRBTree 177 | { 178 | public: 179 | CTree(int growSize, int initSize) : CUtlRBTree(growSize, initSize) 180 | { 181 | } 182 | friend class CUtlSymbolTable::CLess; // Needed to allow CLess to calculate pointer to symbol table 183 | }; 184 | 185 | struct StringPool_t 186 | { 187 | int m_TotalLen; // How large is 188 | int m_SpaceUsed; 189 | char m_Data[1]; 190 | }; 191 | 192 | CTree m_Lookup; 193 | 194 | bool m_bInsensitive; 195 | mutable unsigned short m_nUserSearchStringHash; 196 | mutable const char *m_pUserSearchString; 197 | 198 | // stores the string data 199 | CUtlVector m_StringPools; 200 | 201 | private: 202 | int FindPoolWithSpace(int len) const; 203 | const char *StringFromIndex(const CStringPoolIndex &index) const; 204 | const char *DecoratedStringFromIndex(const CStringPoolIndex &index) const; 205 | 206 | friend class CLess; 207 | friend class CSymbolHash; 208 | }; 209 | 210 | class CUtlSymbolTableMT : public CUtlSymbolTable 211 | { 212 | public: 213 | CUtlSymbolTableMT(int growSize = 0, int initSize = 32, bool caseInsensitive = false) 214 | : CUtlSymbolTable(growSize, initSize, caseInsensitive) 215 | { 216 | } 217 | 218 | CUtlSymbol AddString(const char *pString) 219 | { 220 | m_lock.LockForWrite(); 221 | CUtlSymbol result = CUtlSymbolTable::AddString(pString); 222 | m_lock.UnlockWrite(); 223 | return result; 224 | } 225 | 226 | CUtlSymbol Find(const char *pString) const 227 | { 228 | m_lock.LockForWrite(); 229 | CUtlSymbol result = CUtlSymbolTable::Find(pString); 230 | m_lock.UnlockWrite(); 231 | return result; 232 | } 233 | 234 | const char *String(CUtlSymbol id) const 235 | { 236 | m_lock.LockForRead(); 237 | const char *pszResult = CUtlSymbolTable::String(id); 238 | m_lock.UnlockRead(); 239 | return pszResult; 240 | } 241 | 242 | private: 243 | mutable CThreadSpinRWLock m_lock; 244 | }; 245 | 246 | //----------------------------------------------------------------------------- 247 | // CUtlFilenameSymbolTable: 248 | // description: 249 | // This class defines a symbol table of individual filenames, stored more 250 | // efficiently than a standard symbol table. Internally filenames are broken 251 | // up into file and path entries, and a file handle class allows convenient 252 | // access to these. 253 | //----------------------------------------------------------------------------- 254 | 255 | // The handle is a CUtlSymbol for the dirname and the same for the filename, the accessor 256 | // copies them into a static char buffer for return. 257 | typedef void *FileNameHandle_t; 258 | 259 | // Symbol table for more efficiently storing filenames by breaking paths and filenames apart. 260 | // Refactored from BaseFileSystem.h 261 | class CUtlFilenameSymbolTable 262 | { 263 | // Internal representation of a FileHandle_t 264 | // If we get more than 64K filenames, we'll have to revisit... 265 | // Right now CUtlSymbol is a short, so this packs into an int/void * pointer size... 266 | struct FileNameHandleInternal_t 267 | { 268 | FileNameHandleInternal_t() 269 | { 270 | path = 0; 271 | file = 0; 272 | } 273 | 274 | // Part before the final '/' character 275 | unsigned short path; 276 | // Part after the final '/', including extension 277 | unsigned short file; 278 | }; 279 | 280 | public: 281 | FileNameHandle_t FindOrAddFileName(const char *pFileName); 282 | FileNameHandle_t FindFileName(const char *pFileName); 283 | int PathIndex(const FileNameHandle_t &handle) 284 | { 285 | return ((const FileNameHandleInternal_t *)&handle)->path; 286 | } 287 | bool String(const FileNameHandle_t &handle, char *buf, int buflen); 288 | void RemoveAll(); 289 | void SpewStrings(); 290 | bool SaveToBuffer(CUtlBuffer &buffer); 291 | bool RestoreFromBuffer(CUtlBuffer &buffer); 292 | 293 | private: 294 | CCountedStringPool m_StringPool; 295 | mutable CThreadSpinRWLock m_lock; 296 | }; 297 | 298 | // This creates a simple class that includes the underlying CUtlSymbol 299 | // as a private member and then instances a private symbol table to 300 | // manage those symbols. Avoids the possibility of the code polluting the 301 | // 'global'/default symbol table, while letting the code look like 302 | // it's just using = and .String() to look at CUtlSymbol type objects 303 | // 304 | // NOTE: You can't pass these objects between .dlls in an interface (also true of CUtlSymbol of course) 305 | // 306 | #define DECLARE_PRIVATE_SYMBOLTYPE(typename) \ 307 | class typename \ 308 | { \ 309 | public: \ 310 | typename(); \ 311 | typename(const char *pStr); \ 312 | typename &operator=(typename const &src); \ 313 | bool operator==(typename const &src) const; \ 314 | const char *String() const; \ 315 | \ 316 | private: \ 317 | CUtlSymbol m_SymbolId; \ 318 | }; 319 | 320 | // Put this in the .cpp file that uses the above typename 321 | #define IMPLEMENT_PRIVATE_SYMBOLTYPE(typename) \ 322 | static CUtlSymbolTable g_##typename##SymbolTable; \ 323 | typename ::typename() \ 324 | { \ 325 | m_SymbolId = UTL_INVAL_SYMBOL; \ 326 | } \ 327 | typename ::typename(const char *pStr) \ 328 | { \ 329 | m_SymbolId = g_##typename##SymbolTable.AddString(pStr); \ 330 | } \ 331 | typename &typename ::operator=(typename const &src) \ 332 | { \ 333 | m_SymbolId = src.m_SymbolId; \ 334 | return *this; \ 335 | } \ 336 | bool typename ::operator==(typename const &src) const \ 337 | { \ 338 | return (m_SymbolId == src.m_SymbolId); \ 339 | } \ 340 | const char *typename ::String() const \ 341 | { \ 342 | return g_##typename##SymbolTable.String(m_SymbolId); \ 343 | } 344 | 345 | #endif // UTLSYMBOL_H --------------------------------------------------------------------------------