Making a concussion grenade
January 2024
You can help by adding links to this article from other relevant articles.
January 2024
For help, see the VDC Editing Help and Wikipedia cleanup process. Also, remember to check for any notes left by the tagger at this article's talk page.
Creating a grenade that will blind someone.
void CGrenadeConc::Detonate( void )
{
// An array for all the player pointers to chill
CBaseEntity *list[1024];
// grab all of them within 400 units
int count = UTIL_EntitiesInSphere(list,1024,GetAbsOrigin()+Vector(0,10,0),400,MASK_PLAYERSOLID);
// for each of them
for ( int i = 0; i < count; i++ )
{
// make sure its a player
if (list[i]->IsPlayer())
{
// trace line to make
trace_t tr;
UTIL_TraceLine(list[i]->GetAbsOrigin(),GetAbsOrigin()+Vector(0,10,0),MASK_PLAYERSOLID, NULL, COLLISION_GROUP_NONE, &tr );
CBasePlayer *pPlayer = ToBasePlayer(list[i]);
color32 white = { 255,255,255,255 };
if(tr.fraction == 1.0f) {UTIL_ScreenFade(pPlayer,white,CONC_FALLOFF_TIME,CONC_FADEHOLD, FFADE_IN);}
}
}
BaseClass::Detonate();
}
Drop that in your grenade .cpp and add this to the class definition
virtual void Detonate( void );
and these defines into up top
#define CONC_FALLOFF_TIME 20.0f
#define CONC_FADEHOLD 3.0f
GetAbsOrigin()+Vector(0,10,0)
MASK_SOLID replaced with MASK_PLAYERSOLID
Update 1
The question was posed... "How do you get the flash to deminish with distance?" The answer is simple in theory...
- Find the distance the player is from the grenade
- Consider..
- ..the 100% flash distance
- ..the 0% distance
- Calculate and set alpha
So let's do it really quick
Step 1
We are going to tweak CGrenadeConc::Detonate( void ) a bit.
Basically, since we are changing the alpha of the fade, all calculations will be added at the marked location
CBasePlayer *pPlayer = ToBasePlayer(list[i]);
// here is where our code will be going
color32 white = { 255,255,255,255 };
A simple line will take care of finding the distance...
float distancesq = (pPlayer->GetAbsOrigin() - GetAbsOrigin()+Vector(0,10,0)).LengthSqr()
Step 2
Part A
Considering the 100% flash distance is the next step. At what distance do we still want the character to be flashed? For this tutorial, the chosen distance is 200 inches. The sphere above makes that work out pretty well because 200 inches is about half the sphere's range.
Part B
Consider the 0% distance. If 200 inches is 100%, a good 0% distance may be 400 inches.
Step 3
For simplicitys sake, and code shortening, we start percent with 100%:
float ratio = 1.0;
Since we decided that 200 inches would be a good distance for 100%, let's make sure the distance is above or at that. We have a simple calculation to know what percentage of the flash to show. The distance is left squared to possibly avoid an unneeded square root...
if (distancesq >= 40000)
ratio = (200-(vec_t)FastSqrt(distancesq))/200.0;
Distance is taken between the point of explosion and the character's location.
We want a proportion of this flash, so we will use a ratio of a 100% opaque flash.
color32 white = { 255,255,255,(255*ratio) };
Update 2
It might also be better to have the flash hold change as well via the ratio. Here is the finished detonate function for comparison.
void CGrenadeConc::Detonate( void )
{
// An array for all the player pointers to chill
CBaseEntity *list[1024];
// grab all of them within 350 units
int count = UTIL_EntitiesInSphere(list,1024,GetAbsOrigin()+Vector(0,10,0),350,MASK_PLAYERSOLID);
// for each of them
for ( int i = 0; i < count; i++ )
{
// make sure its a player
if (list[i]->IsPlayer())
{
// trace line to make
trace_t tr;
UTIL_TraceLine(list[i]->GetAbsOrigin(),GetAbsOrigin()+Vector(0,10,0),MASK_PLAYERSOLID, NULL, COLLISION_GROUP_NONE, &tr );
CBasePlayer *pPlayer = ToBasePlayer(list[i]);
float distancesq = (pPlayer->GetAbsOrigin() - GetAbsOrigin()+Vector(0,10,0)).LengthSqr()
float ratio = 1.0;
if (distancesq >= 40000)
ratio = (200-(vec_t)FastSqrt(distancesq))/200.0;
color32 white = { 255,255,255,(255*ratio) };
int fadehold = random->RandomInt( 0, 4 );
if(tr.fraction == 1.0f)
{
UTIL_ScreenFade(pPlayer, white, CONC_FALLOFF_TIME+(.5f*fadehold*ratio), fadehold*ratio, FFADE_IN);
int effect = 0 ? random->RandomInt( 35, 37 ) : random->RandomInt( 32, 34 );
CSingleUserRecipientFilter user( pPlayer );
enginesound->SetPlayerDSP( user, effect, false );
}
}
}
BaseClass::Detonate();
}
Update 3
if(tr.fraction == 1.0f)
{
if ( pPlayer->FInViewCone( this ) )
UTIL_ScreenFade(pPlayer, white, CONC_FALLOFF_TIME+(.5f*fadehold*ratio), fadehold*ratio, FFADE_IN);
int effect = 0 ? random->RandomInt( 35, 37 ) : random->RandomInt( 32, 34 );
CSingleUserRecipientFilter user( pPlayer );
enginesound->SetPlayerDSP( user, effect, false );
}
The above shows how to skip the screenfade if the player can't actually see the grenade.