Welcome, Guest! Login | Register

Making a Flashbang [Print this Article]
Posted by: PowerSoul
Date posted: Oct 01 2004
User Rating: N/A
Number of views: 7272
Number of comments: 1
Description: Tutorial on making a flashbang grenade, complete with CS-style screen fading & concussion effect.
You must complete omega's orthotriangles tutorial before following this article.

I've seen horrible implementations of flashbangs in numerous smaller mods, and when I had to write one for my own mod, I wanted to do it right.
This is my way of coding a flashbang, enjoy.

First, on the client dll, we're going to modify the TFC's concussion effect so it automatically slows down & goes off, without needing to send a message from the server every second.
We will need to change gHud's m_iConcussion from private member to a public member, so we can modify it later.
Open hud.h, and move int m_iConcussionEffect; from CHud's privates to publics (line 558 -> 561).
Next, open tri.cpp, and add the following to HUD_DrawOrthoTriangles:
 CODE (C++) 
  static float nextUpdate = gHUD.m_flTime + 0.2;
  if (gHUD.m_iConcussionEffect > 0) {
    if (gHUD.m_flTime > nextUpdate) {
      gHUD.m_iConcussionEffect -= 1;
      if (gHUD.m_iConcussionEffect < 0) {
        gHUD.m_iConcussionEffect = 0;
      }
      nextUpdate = gHUD.m_flTime+0.2;
    }
  }

This decreases m_iConcussionEffect (strength of the effect, 0 = off) by 1 every 0.2 seconds.
You might be asking why we're adding this here - simply because HUD_DrawOrthoTriangles gets called every frame for sure. You could add this to numerous other places, but I like it there.

That's it for client side, compile & open the server workspace.

What we're going to do first is "re-enable" the concussion message on the server side, so we can use it later.
Open player.cpp, and add this to line 186:
 CODE (C++) 
int gmsgConcussion = 0;
then go to line 233, and add this:
 CODE (C++) 
gmsgConcussion = REG_USER_MSG( "Concuss", 1 );

Now the server dll recognizes the gmsgConcussion-message, which we're going to use as an added effect to the flash.
Next we'll add two new functions to CGrenade, ShootFlashbang & Flash.
So open up weapons.h, and add the following below static CGrenade *ShootSatchelCharge:
 CODE (C++) 
static CGrenade *ShootFlashbang( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time );

...and the following below void Explode:
 CODE (C++) 
void Flash( TraceResult *pTrace );

Those prototype the added functions.
Next, open ggrenade.cpp, and scroll down around line 425, and our ShootFlashbang function there:
 CODE (C++) 
CGrenade * CGrenade::ShootFlashbang( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ) {
  CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL );
  pGrenade->Spawn();
  UTIL_SetOrigin( pGrenade->pev, vecStart );
  pGrenade->pev->velocity = vecVelocity;
  pGrenade->pev->angles = UTIL_VecToAngles(pGrenade->pev->velocity);
  pGrenade->pev->owner = ENT(pevOwner);
  // we'll use the handgrenade's bouncetouch
  pGrenade->SetTouch( BounceTouch );
  // this is when our flashbang is going to explode
  pGrenade->pev->dmgtime = gpGlobals->time + time;
  pGrenade->SetThink( TumbleThink );
  // just some cosmetic stuff here
  pGrenade->pev->avelocity.y = RANDOM_FLOAT ( -5, -20 );
  pGrenade->pev->nextthink = gpGlobals->time + 0.1;
  if (time < 0.1) {
    pGrenade->pev->nextthink = gpGlobals->time;
    pGrenade->pev->velocity = Vector( 0, 0, 0 );
  }
  // sets the model - PLEASE don't email me asking "where's w_flashbang.mdl?"
  SET_MODEL(ENT(pGrenade->pev), "models/w_flashbang.mdl");
  if ( RANDOM_LONG( 1, 2 ) == 1 ) {
    pGrenade->pev->sequence = 2;
  } else {
    pGrenade->pev->sequence = 3;
  }
  pGrenade->pev->animtime = gpGlobals->time;
  pGrenade->pev->framerate = 1.0;
  pGrenade->pev->gravity = 0.55;
  pGrenade->pev->friction = 0.6;
  // important - if this is false, the flashbang explodes like a normal grenade.
  pGrenade->m_bIsFlashbang = TRUE;
  pGrenade->pev->dmg = 0;
  return pGrenade;
}

Next go to the Detonate() function, line 217, and modify it so it looks like this:
 CODE (C++) 
void CGrenade::Detonate( void ) {
  TraceResult tr;
  Vector vecSpot = pev->origin + Vector ( 0 , 0 , 8 );
  UTIL_TraceLine ( vecSpot, vecSpot + Vector ( 0, 0, -40 ),  ignore_monsters, ENT(pev), & tr);
  if ( m_bIsFlashbang == TRUE ) {
    Flash( &tr );
  } else {
    Explode( &tr, DMG_BLAST );
  }
}

This is just so it calls Flash() instead of handgrenade's Explode() if the granade is a flashbang.
"Now what the heck is this m_bIsFlashbang?", you might be asking. Indeed, we haven't yet added it.
So open up weapons.h again, and add
 CODE (C++) 
BOOL m_bIsFlashbang;

to the end of CGrenade's publics. It's a boolean we use to tell a flashbang from a normal grenade.
We're almost done - only the most critical part is missing ;)
Go to the start of ggrenade.cpp, and add these below the other includes:
 CODE (C++) 
#include "shake.h"
#include "math.h"

We need shake.h to use UTIL_ScreenFade, and math.h, because we'll be using powf() to calculate the duration of the flash, based on player's distance.
Go around line 129, and add our Flash() function there as follows:
 CODE (C++) 
void CGrenade::Flash( TraceResult *pTrace ) {
  pev->model = iStringNull;
  pev->solid = SOLID_NOT;
  pev->takedamage = DAMAGE_NO;
  if ( pTrace->flFraction != 1.0 ) {
    pev->origin = pTrace->vecEndPos + (pTrace->vecPlaneNormal * 100 * 0.1);
  }
  // flash, apparently, doesn't work underwater.
  int iContents = UTIL_PointContents ( pev->origin );
  if (iContents != CONTENTS_WATER) {
    // replace this with YOUR flash-sound. you'll also want to precache the sound in weapons.cpp.
    EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/flashbang/bang.wav", 0.9, ATTN_NORM);
    // cool decal
    UTIL_DecalTrace( pTrace, DECAL_SCORCH1 );
    CBaseEntity *pEntity = NULL;
    // we'll loop thru all entities 2000 units or less away from us
    while ((pEntity = UTIL_FindEntityInSphere( pEntity, pev->origin, 2000 )) != NULL) {
      // only affect players, duh
      if ( pEntity->IsPlayer() ) {
        // get the distance between the flash & the player
        float flDist = (pEntity->Center() - pev->origin).Length();
        // we'll only fade the player's view if he saw the flash
        if ( FVisible( pEntity ) ) {
          // you can mess with these values if you're not happy with the original durations
          float flFadeTime = 150000 / powf(flDist, 2);
          // we'll use 30 as the maximum limit - else the player's view won't fade back in hours if he stares at the grenade from short distances.
          // even 30 is kind of high, you'll probably want to lower this.
          if (flFadeTime > 30) { flFadeTime = 30; }
          else if (flFadeTime <= 2.0) { flFadeTime = 2.0; }
          UTIL_ScreenFade( pEntity, Vector(255,255,255), flFadeTime, (flFadeTime / 4), 255, FFADE_IN );
          // now the fun part - concussion!
          // they didn't have this in CS ;D - but I think it really adds to the effect.
          extern int gmsgConcussion;
          MESSAGE_BEGIN( MSG_ONE, gmsgConcussion, NULL, pEntity->pev );
          if (flFadeTime < 3) { WRITE_BYTE( 20 ); }
          else if (flFadeTime >= 3 && flFadeTime < 4) { WRITE_BYTE( 34 ); }
          else if (flFadeTime >= 4 && flFadeTime < 5.5) { WRITE_BYTE( 50 ); }
          else if (flFadeTime >= 5.5 && flFadeTime < 12) { WRITE_BYTE( 72 ); }
          else if (flFadeTime >= 12) { WRITE_BYTE( 90 ); }
          MESSAGE_END();
        }
      }
    }
    // heavy sparkage!
    int sparks = RANDOM_LONG(1,6);
    for ( int i = 0; i < sparks; i++ )
      Create( "spark_shower", pev->origin, pTrace->vecPlaneNormal, NULL );
  }
  // don't draw the model after it has exploded.
  pev->effects |= EF_NODRAW;
  // emit some smoke, & remove self.
  SetThink( Smoke );
  pev->velocity = g_vecZero;
  pev->nextthink = gpGlobals->time + 0.3;
}

One last thing - If we leave the flashbang like it is now, it won't emit smoke - this is because it's "dmg" is 0.
So, replace the CGrenade's Smoke-function with the following:
 CODE (C++) 
void CGrenade::Smoke( void ) {
  if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER) {
    UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 );
  } else {
    MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
    WRITE_BYTE( TE_SMOKE );
    WRITE_COORD( pev->origin.x );
    WRITE_COORD( pev->origin.y );
    WRITE_COORD( pev->origin.z );
    WRITE_SHORT( g_sModelIndexSmoke );
    WRITE_BYTE( 70 ); // scale * 10
    // static amount if it's a flashbang
    if (m_bIsFlashbang) {
      WRITE_BYTE( 80 );
    } else {
      WRITE_BYTE( (pev->dmg - 50) * 0.80 ); // scale * 10
    }
    WRITE_BYTE( 12  ); // framerate
    MESSAGE_END();
  }
  UTIL_Remove( this );
}

That's all - you now have a working flashbang in your mod.
The easiest way to test it off is to change CHandGrenade to use CGrenade::ShootFlashbang instead of CGrenade::ShootTimed.
Have fun ;)

Rate This Article
This article has not yet been rated.

You have to register to rate this article.
User Comments Showing comments 1-1

Posted By: kidneynabrik on Mar 29 2006 at 00:55:26
hey PowerSoul, like to mention that your code here....
 CODE  

void CGrenade::Smoke( void ) {
  if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER) {
    UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 );
  } else {
    MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
    WRITE_BYTE( TE_SMOKE );
    WRITE_COORD( pev->origin.x );
    WRITE_COORD( pev->origin.y );
    WRITE_COORD( pev->origin.z );
    WRITE_SHORT( g_sModelIndexSmoke );
    WRITE_BYTE( 70 ); // scale * 10
    // static amount if it's a flashbang
    if (m_bIsFlashbang) {
      WRITE_BYTE( 80 );
    } else {
      WRITE_BYTE( (pev->dmg - 50) * 0.80 ); // scale * 10
    }
    WRITE_BYTE( 12  ); // framerate
    MESSAGE_END();
  }
  UTIL_Remove( this );
}


needs to look like this

 CODE  

void CGrenade::Smoke( void ) {
  if (UTIL_PointContents ( pev->origin ) == CONTENTS_WATER) {
    UTIL_Bubbles( pev->origin - Vector( 64, 64, 64 ), pev->origin + Vector( 64, 64, 64 ), 100 );
  } else {
    MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
    WRITE_BYTE( TE_SMOKE );
    WRITE_COORD( pev->origin.x );
    WRITE_COORD( pev->origin.y );
    WRITE_COORD( pev->origin.z );
    WRITE_SHORT( g_sModelIndexSmoke );
   // WRITE_BYTE( 70 ); // scale * 10  // FIX, THIS IS NULL/VOID unneeded
    // static amount if it's a flashbang
    if (m_bIsFlashbang) {
      WRITE_BYTE( 80 );
    } else {
      WRITE_BYTE( (pev->dmg - 50) * 0.80 ); // scale * 10
    }
    WRITE_BYTE( 12  ); // framerate
    MESSAGE_END();
  }
  UTIL_Remove( this );
}


everything else is good....


You must register to post a comment. If you have already registered, you must login.

Latest Articles
3rd person View in Multiplayer
Half-Life 2 | Coding | Client Side Tutorials
How to enable it in HL2DM

By: cct | Nov 13 2006

Making a Camera
Half-Life 2 | Level Design
This camera is good for when you join a map, it gives you a view of the map before you join a team

By: slackiller | Mar 05 2006

Making a camera , Part 2
Half-Life 2 | Level Design
these cameras are working monitors that turn on when a button is pushed.

By: slackiller | Mar 04 2006

Storing weapons on ladder
Half-Life 2 | Coding | Snippets
like Raven Sheild or BF2

By: British_Bomber | Dec 24 2005

Implementation of a string lookup table
Half-Life 2 | Coding | Snippets
A string lookup table is a set of functions that is used to convert strings to pre-defined values

By: deathz0rz | Nov 13 2005


Latest Comments
knock knock
General | News
By: omega | Dec 22 2016
 
knock knock
General | News
By: MIFUNE | Oct 10 2015
 
New HL HUD Message System
Half-Life | Coding | Shared Tutorials
By: chbrules | Dec 31 2011
 
knock knock
General | News
By: Whistler | Nov 05 2011
 
Particle Engine tutorial part 4
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 18 2010
 
Particle Engine tutorial part 2
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Particle Engine tutorial part 3
Half-Life | Coding | Client Side Tutorials
By: darkPhoenix | Feb 11 2010
 
Game Movement Series #2: Analog Jumping and Floating
Half-Life 2 | Coding | Shared Tutorials
By: mars3554 | Oct 26 2009
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Deadpool | Aug 02 2009
 
Particle Engine tutorial part 5
Half-Life | Coding | Client Side Tutorials
By: Persuter | Aug 02 2009
 

Site Info
297 Approved Articless
8 Pending Articles
3940 Registered Members
0 People Online (15 guests)
About - Credits - Contact Us

Wavelength version: 3.0.0.9
Valid XHTML 1.0! Valid CSS!