Tutorial: Harnessing ELights Last edited 7 months ago2020-03-23 06:29:13 UTC

Hello and welcome to my tutorial.

In this tutorial we will learn how to harness ELights(or Entity Lights), which are temporary entities that allow you to have per-vertex lighting on models. Half-Life by default supports vertex lighting on models, but this feature by default is not used much in the original game outside of muzzleflashes, the Nihilanth and the alien controllers's energy balls. I've created a special entity system and clientside code that manages elights in a way that allows you to place these lights into the world via env_elight entities.

Below are two examples of the env_elight entity in use:
env_elight - Exampleenv_elight - Example
env_elight - Exampleenv_elight - Example
To try out the elights in action before implementing, I've added a small mod for this purpose, in the "elights_mod.7z" package. Just unzip this into your Half-Life folder and hit New Game, and it'll load the test map with elights added.

Test mod:
Loading embedded content: Vault Item #6399
Tutorial files:
Loading embedded content: Vault Item #6400
First of all, download the "elight_src.7z" package linked in this tutorial. It will contain a null.spr file, which you will need to copy to your mod folder's sprites folder. This is an inert sprite file, which is used as a "model" by the env_elight entity, so that it is successfully sent over to clients on the entity packet list.
Then there are two new C++ files, called elight.h and elight.cpp, which you'll want to copy to your source code folder's client folder, and then add said files to your client dll project in Visual Studio. It also includes a map file called "elighttest.bsp", which is a test map for the env_elight entity. You'll want to copy that to your mod's "maps" folder.

This will mostly be a copy and paste tutorial, so it should be fairly straightforward to implement. As a first step, open up your .fgd file, and add the new fgd entry with the other env_ entity entries:
@PointClass base(Targetname) iconsprite("sprites/lightbulb.spr") size(-16 -16 -16, 16 16 16) = env_elight : "Model light"
[
  renderamt(integer) : "Radius" : 15
  rendercolor(color255) : "Render Color" : "255 255 255"
  spawnflags(flags) =
  [
    1 : "Start On" : 0
  ]
]
We'll also need to edit the delta.lst file, as we're introducing a new effects flag for the entity in const.h. The delta.lst file manages how certain entity properties are encoded and sent to the clients, and by default it is set to encode only 8 bytes for the pev->effects variable, but we need more than that. If your mod doesn't have a delta.lst file in the mod folder, just go to the "Half-Life/valve" folder and copy the delta.lst file from there to your mod folder.

Open up delta.lst in notepad and find the two entries regarding "effects".

This is the original entry:
DEFINE_DELTA( effects, DT_INTEGER, 8, 1.0 ),

And you'll want to change it to the following:
DEFINE_DELTA( effects, DT_INTEGER, 16, 1.0 ),

Once this is done, go to your source code directory, and in "src_dll/common/" find the cont.h file. Look up the following line:
#define EF_NODRAW                128    // don't draw entity
And right after it, add this new flag:
#define EF_ENVELIGHT            256 // env_elight entity
This new flag will be used to identify the env_elight entity on the client. Now go into effects.cpp, and at the very end of the file add the class definition of the env_elight entity:
//=========================================================`
// env_elight
//=========================================================
#define SF_ELIGHT_STARTON 1
class CEnvELight : public CPointEntity
{
public:
    void Spawn( void );
    void Precache( void );
    void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
};

LINK_ENTITY_TO_CLASS( env_elight, CEnvELight );

void CEnvELight:: Spawn( void )
{
    Precache();
    pev->solid = SOLID_NOT;

    SET_MODEL(ENT(pev), "sprites/null.spr");

    if(!FStringNull(pev->targetname) && !(pev->spawnflags & SF_ELIGHT_STARTON))
        pev->effects = EF_NODRAW;
    else
        pev->effects = EF_ENVELIGHT;
}

void CEnvELight:: Precache( void )
{
    PRECACHE_MODEL("sprites/null.spr");
}

void CEnvELight::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
    switch( useType )
    {
    case USE_ON:
        pev->effects = EF_ENVELIGHT;
        break;
    case USE_OFF:
        pev->effects = EF_NODRAW;
        break;
    default:
        if(pev->effects & EF_NODRAW)
            pev->effects = EF_ENVELIGHT;
        else
            pev->effects = EF_NODRAW;
        break;
    }
}
This concludes our work on the server side. Now go to your client library, and add the new .h and .cpp files from your client folder if you haven't done so already. Next, we'll be opening up entity.cpp. At the very top, add the #include for the new header:
#include "elights.h"
Now go to the "HUD_CreateEntities", and at the end of the function, add this call:
// Manage any elights
gELightManager.Think();
Once this is done, open up hud.cpp, and at the top, add:
#include "elights.h"
Now at the end of the CHud :: Init function, add this call:
gELightManager.Init();
Go to CHud :: VidInit, and at the very end, add the following call:
gELightManager.VidInit();
Now once this is done, compile your libraries, and copy the .dll files to their destinations in "modfolder/cl_dlls" and "modfolder/dlls", each respectively. Now if you haven't done so already, copy the "elighttest.bsp" file to your maps folder, and load the test map up, and observe the env_elight effect on models.

A few notes: I hope you find this new entity useful.
-Overfloater.

Comments

You must log in to post a comment. You can login or register a new account.