An Unspeakable Modification for Half-Life

Welcome to the Mapping section!

In this section I describe how I make certain entities in the Cthulhu mod. My only request is that if you use my code, please credit me in your mod.
  1. Books
Note: I use Spirit of Half-Life, so I assume here that you do too!


In Cthulhu, there are a number of things that may be 'read', such as letters, books, etc. For this I created the item_book entity. Here I will tell you how to implement this entity in your mod.

1. Insert the following code in your mod's Hammer Editor FGD file:

@PointClass size(-16 -16 0, 16 16 36) base(Weapon, Targetx) = item_book : "Book"

model(studio) : "Model" : ""
body(Integer) : "Body" : 0
image1(string) : "Use Image1"
image2(string) : "Use Image2"
image3(string) : "Use Image3"
imageduration(string) : "Image Duration" : "5"
spawnflags(Flags) =
//* Tick this to only fire target once.
1 : "Fire Once" : 1


This should be around the same area in the file where the item_healthkit is defined.

2. Include the BOOK.CPP file into your HL.DLL C++ project.

3. In the HL.DLL file player.cpp, include the following code. I have commented the Cthulhu code and included the preceding lines, so you know where to put the code:

int gmsgTeamNames = 0;
int gmsgReadBook = 0; // Cthulhu

and in routine LinkUserMessages():

gmsgTeamNames = REG_USER_MSG( "TeamNames", -1 );
gmsgReadBook = REG_USER_MSG( "ReadBook", -1 ); // Cthulhu

4. In the HL.DLL file triggers.cpp, include the following code in the routine ChangeLevelNow(...). Again I have included the surrounding code, so you should be able to find where to put it:
CBaseEntity *pPlayer = CBaseEntity::Instance( g_engfuncs.pfnPEntityOfEntIndex( 1 ) );
if ( !InTransitionVolume( pPlayer, m_szLandmarkName ) )

ALERT( at_aiconsole, "Player isn't in the transition volume %s, aborting\n", m_szLandmarkName );


// Cthulhu: shut down any book pages

// Create an entity to fire the changetarget
if ( m_changeTarget )

5. In the HL.DLL file util.h, include the following code (immediately after the definition of UTIL_SayTextAll is a good place):

extern void UTIL_ReadBook( const char *szImage ); // Cthulhu

6. In the HL.DLL file util.cpp, include the following code (doesn't really matter where, but with the other messages like UTIL_SayTextAll):

extern int gmsgReadBook;
void UTIL_ReadBook( const char *szImage )

WRITE_STRING( szImage );


7. In the CLIENT.DLL project, include the ReadBook.CPP file.

8. In the CLIENT.DLL file HUD.H, include the following line in the class definition of CHud (next to the declaration of m_Battery is a good place):

CHudBattery m_Battery;
CHudReadBook m_ReadBook; // Cthulhu

9. In the CLIENT.DLL file HUD.H file, include the following code (at some point before the CHud class definition in Step 8 above):

#include "ImageLabel.h"
class CHudReadBook : public CHudBase
int Init( void );
int VidInit( void );
int MsgFunc_ReadBook(const char *pszName, int iSize, void *pbuf );
CImageLabel* pImage;

10. In the CLIENT.DLL file HUD.CPP, include the following code in the CHud::Init() routine:

m_ReadBook.Init(); // Cthulhu

and in the CHuD::VidInit() routine:

m_ReadBook.VidInit(); // Cthulhu

11. Rebuild both DLLs and you are now ready to start mapping with books. Some last notes on using books though:
  • when mapping using books, any model may be used for the 'book'.
  • If the 'Use Image2' field is left empty, only 1 page is displayed.
  • If the 'Use Image1' field contains 'mypage', the entity will display the file 'gfx/vgui/640_mypage.tga' if the game is running in 640x480 or higher resolution. Otherwise the display file will be 'gfx/vgui/320_mypage.tga'.
  • TGA files support transparency, so non-rectangular pages may be displayed (circles, rough edges, etc.).

Contact me: