VERC: Another Way To Make Those Cute Lil Houndeyes Not So Cute Last edited 1 year ago2022-09-29 07:54:07 UTC

Well about a week ago I got my MSVC++ and decided to finally start tweaking the HL code. I came up with a simple first project, creating the Atomic Houndeye and making its very own entry in the fgd. Here's all it takes:

The first and foremost thing to do is to find the file which contains the functions for our little friend - the houndeye - which so happens to be in houndeye.cpp.
Now, around line 19 you will find the code for all the imports. It should look like this:
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "schedule.h"
#include "animation.h"
#include "nodes.h"
#include "squadmonster.h"
#include "soundent.h"
#include "game.h"
In order to get an explosion into the otherwise feeble houndeye, we must add one additional import:
#include "explode.h"
Pretty self explanatory, right?

Next, we must find the declaration of the function SonicAttack() , it should be located around line 93 and should look like:
void SonicAttack( void );
Now, in order to alter this function in the new entity class (discussed later), you must add the virtual tag to this function so that it can be over ridden. It should now resemble this:
virtual void SonicAttack( void );
Now to making our very own houndeye. First, you should probably jump down to the bottom of the file for this part, so as to keep it separated from the rest of the code and easier to find. In order to make our new class, you must extend the old CHoundeye class and declare it to override the SonicAttack() function and link it to its own entity name. The code should look something like this:
class CAHoundeye : public CHoundeye
    public :
        virtual void SonicAttack( void );

LINK_ENTITY_TO_CLASS( monster_houndeye_atomic, CAHoundeye );
That was probably the hardest part to this. The next step is to begin the definition of your new SonicAttack() function It should look pretty much the same as this:
void CAHoundeye :: SonicAttack( void )
Then for its definition, you first must copy and paste the original SonicAttack() code for the new SonicAttack() Function. This code can be found at approximately line 560 and goes to about line 670. Don't worry about the size, there are a lot of braces and we are only concerned with a small portion of the entire block. After you paste the code in, you need to find the section in which damage is dealt to the player/entity. It should look like:
if (flAdjustedDamage > 0 )
    pEntity->TakeDamage ( pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB );
What's great about this is that you don't have to recalculate the area of effect, as the sonic attack itself has already done that for you. So all we must add is the explosion. And that goes right after the TakeDamage call, like this:
ExplosionCreate( pEntity->Center(), Vector(0,0,0), edict(), (int)(3 * flAdjustedDamage), true);
The function parameters are as follows:
( const Vector &  center, const Vector &  angles, edict_t *pOwner, int magnitude, BOOL doDamage )
All of the parameters are pretty self explanatory. Because of the nature of this function, angles is unused and has no effect on the outcome. The edict() function returns an edict_s, which carries various information pertinent to the houndeye itself. The edict_s definition can be found in engine/edict.h.

The final step before we move onto the FGD is to make our brand new monster immune to its own attack.... We don't want it to kill itself, now do we? In order for all houndeyes not to hurt each other, there is a second condition you must add to two separate, yet identical if statements. These can be found at around lines 622 and 1385. You will see the following if statement:
if ( !FClassnameIs(pEntity->pev, "monster_houndeye") )
This is how it determines whether or not the entity in question is a houndeye. Now, to include our new friend to this, we must add a new condition. The final condition should look like this:
if ( !FClassnameIs(pEntity->pev, "monster_houndeye") && !FClassnameIs(pEntity->pev, "monster_houndeye_atomic") )
There, you now have a brand new Atomic Houndeye that won't hurt itself or other houndeyes with its sonic attack. Now onto the FGD.

First,find the definition of the houndeye in the FGD. This can be done with a simple find for "houndeye". Now you copy and paste the entire code right below it. The only thing we are going to change is the very first line, and this will be done as follows:
@PointClass base(Monster) size(-16 -16 0, 16 16 36) = monster_houndeye : "Houndeye"
@PointClass base(Monster) size(-16 -16 0, 16 16 36) = monster_houndeye_atomic : "Atomic Houndeye"
And there you have it, save the changes to the FGD, load it into Hammer and you're ready to go. You may want to play around with the actual magnitude of the blast, but I found 3x its normal damage is a good number - just watch out for 'em in packs.

Things to watch out for:

Make sure you change the declaration of SonicAttack() to virtual, otherwise your new houndeye will still call the old houndeye SonicAttack.

Other Uses For this:

Because the code only needs to be added to the damage portion of an attack, this method could realistically be extended to almost any monster or entity that deals damage.
This article was originally published on Valve Editing Resource Collective (VERC).
The archived page is available here.
TWHL only publishes archived articles from defunct websites, or with permission. For more information on TWHL's archiving efforts, please visit the TWHL Archiving Project page.


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