Making a concussion grenade: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
No edit summary
 
m (→‎top: clean up, added orphan, deadend tags)
 
(11 intermediate revisions by 5 users not shown)
Line 1: Line 1:
[[Category:Programing]]
{{Multiple issues|
==Info:==
{{Dead end|date=January 2024}}
This Tutorial was originally from [http://www.gneu.org/wiki/index.php?title=HL2:_Making_a_concussion_grenade gneu.org] and moved here to combine all the tutorials into one location.
{{Orphan|date=January 2024}}
{{cleanup}}
}}


==Purpose:==
Creating a grenade that will blind someone.
To Create a grenade that will blind someone.


==Route:==
<source lang=cpp>void CGrenadeConc::Detonate( void )
Research UTIL_ functions and BaseGrenade
 
==Solution:==
One simple function does it all folks.
 
<pre>void CGrenadeConc::Detonate( void )
{
{
  // An array for all the player pointers to chill
// An array for all the player pointers to chill
  CBaseEntity *list[1024];
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]);


  // grab all of them within 400 units
color32 white = { 255,255,255,255 };
  int count = UTIL_EntitiesInSphere(list,1024,GetAbsOrigin()+Vector(0,10,0),400,MASK_SOLID);
 
  // 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_SOLID, 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);}
}
}


        if(tr.fraction == 1.0f) {UTIL_ScreenFade(pPlayer,white,CONC_FALLOFF_TIME,CONC_FADEHOLD, FFADE_IN);}
BaseClass::Detonate();
      }
}</source>
  }
 
  BaseClass::Detonate();
}</pre>


Drop that in your grenade .cpp and add this to the class definition
Drop that in your grenade .cpp and add this to the class definition


<pre>virtual void      Detonate( void );</pre>
<source lang=cpp>virtual void      Detonate( void );</source>


and these defines into up top
and these defines into up top


<pre>#define CONC_FALLOFF_TIME 20.0f
<source lang=cpp>#define CONC_FALLOFF_TIME 20.0f
#define CONC_FADEHOLD 3.0f</pre>
#define CONC_FADEHOLD 3.0f</source>


There was a bug in the original code i posted here, where the grenade was actually blocking the flash. the fix is added here.
<div style="padding:.5em;background:#DF6F6F;border:2px solid red;">There was a bug in the original code I posted here, where the grenade was actually blocking the flash. the fix is added here.


<pre>GetAbsOrigin()+Vector(0,10,0)</pre>
<source lang=cpp>GetAbsOrigin()+Vector(0,10,0)</source>
</div>


<div style="padding:.5em;background:#DF6F6F;border:2px solid red;">There was a problem with the concussion effect not working when using it in the crossbow "BoltTouch" function and jumping while firing downwards. The problem was that the mask wasn't working properly. Fixed it by replacing MASK_SOLID with MASK_PLAYERSOLID. This fix has been implemented into the code on this page already.


'''THANKS TO HELK FROM HOSTILE PLANET'''
<source lang=cpp>MASK_SOLID replaced with MASK_PLAYERSOLID</source>
</div>


==Update 1==
==Update 1==


The question was posed... "how do you get the flash to deminish with distance?"
The question was posed... "How do you get the flash to deminish with distance?"
The answer is simple...
The answer is simple in theory...
in pseudo code at least...


#Find the distance the player is from the grenade...
#Find the distance the player is from the grenade
#consider...
#Consider..
#*the 100% flash distance
#*..the 100% flash distance
#*the 0% distance
#*..the 0% distance
#calculations
#Calculate and set alpha
#alpha!


so lets do it really quick
So let's do it really quick


1) in the same function as above... '''CGrenadeConc::Detonate( void )''' we are going to tweak it a bit.
===Step 1===
We are going to tweak '''CGrenadeConc::Detonate( void )''' a bit.


basically, since we are changing the color of the fade, we put all of our code in between
Basically, since we are changing the alpha of the fade, all calculations will be added at the marked location


<pre>CBasePlayer *pPlayer = ToBasePlayer(list[i]);
<source lang=cpp>CBasePlayer *pPlayer = ToBasePlayer(list[i]);
// here is where our code will be going
// here is where our code will be going
color32 white = { 255,255,255,255 };</pre>
color32 white = { 255,255,255,255 };</source>
 
so first part is the distance. a simple utility function will take care of this...
 
UTIL_DistApprox2D(pPlayer->GetAbsOrigin(), GetAbsOrigin()+Vector(0,10,0))
 
this tid bit will return a float value of the distance of the character, but its not a magnitude, its got direction as well. What this means, is that the value can be + or negative. Since we dont really need to worry about .2 of a unit, and negative values do us no good, abs() is our new best friend. It will remove the decimal portion, truncation, and return the positive version of the number, All better.


int distance = abs(UTIL_DistApprox2D(pPlayer->GetAbsOrigin(), GetAbsOrigin()+Vector(0,10,0)));
A simple line will take care of finding the distance...


okay, we have the distance.
float distancesq = (pPlayer->GetAbsOrigin() - GetAbsOrigin()+Vector(0,10,0)).LengthSqr()


2a) consider the 100% flash distance is the next question. At what distance do we still want the character to be flashed? I choose to have it at 200 units. my sphere above makes that work out pretty well. its about 1/2 the sphere, and if you think about it... 16 feet is a nice distance for this to happen...
===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.


2b) consider the 0% distance. if 16 is 100%, i think it should have 32 as 0. nothing too complex. 400 units Cool
===Part B===
Consider the 0% distance. If 200 inches is 100%, a good 0% distance may be 400 inches.


3) calculations! For simplicitys sake, and code shortening, we start percent with 100%:
===Step 3===
For simplicitys sake, and code shortening, we start percent with 100%:


  float percent = 1.0;
  float ratio = 1.0;


now we need a test. since we decided that 200 would be a good distance for 100%, lets make sure the distance is above that. and then we have a simple calculation to know what percentage of the flash to show...
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 (distance >200)
  if (distancesq >= 40000)
    percent = (distance-200)/200.0;
ratio = (200-(vec_t)FastSqrt(distancesq))/200.0;


but we have another problem. this is actually the opposite of the ratio we were looking for, and it also sends negative values to percent, like we had above... not good. so we need to invert the percent and abs it.
Distance is taken between the point of explosion and the character's location.


if (distance >200)
We want a proportion of this flash, so we will use a ratio of a 100% opaque flash.
    percent = abs (1-((distance-200)/200.0));


Next problem to avert, we have nothing but 1 and 0 as values. as i said earlier, abs truncates the decimal values. simply make the value an integer. I figure 3 decimal points is good enough... how about it.
  color32 white = { 255,255,255,(255*ratio) };
 
if (distance >200)
    percent = abs (1000*(1-((distance-200)/200.0)))/1000;
 
So lets go through this again.
 
distance is taken, from the point of explosion to the characters location.
percent is 100%
if the distance is more than 200,
percent is changed to the correct value
 
one more statement to change and we are done, folks.
 
we want the alpha to change on this color to a percentage.
 
  color32 white = { 255,255,255,(255*percent) };
 
Done.


==Update 2==
==Update 2==
On second thought, i thought it would be better to have the flashhold change as well via the percentage. here is my finished detonate function for comparison.
It might also be better to have the flash hold change as well via the ratio. Here is the finished detonate function for comparison.


<pre>void CGrenadeConc::Detonate( void )
<source lang=cpp>void CGrenadeConc::Detonate( void )
{
{
  // An array for all the player pointers to chill
// An array for all the player pointers to chill
  CBaseEntity *list[1024];
CBaseEntity *list[1024];
 
  // grab all of them within 350 units
// grab all of them within 350 units
  int count = UTIL_EntitiesInSphere(list,1024,GetAbsOrigin()+Vector(0,10,0),350,MASK_SOLID);
int count = UTIL_EntitiesInSphere(list,1024,GetAbsOrigin()+Vector(0,10,0),350,MASK_PLAYERSOLID);
 
  // for each of them
// for each of them
  for ( int i = 0; i &lt; count; i++ )
for ( int i = 0; i &lt; count; i++ )
  {
{
      // make sure its a player
// make sure its a player
      if (list[i]->IsPlayer())
if (list[i]->IsPlayer())
      {
{
        // trace line to make
// trace line to make
        trace_t  tr;   
trace_t  tr;   
        UTIL_TraceLine(list[i]->GetAbsOrigin(),GetAbsOrigin()+Vector(0,10,0),MASK_SOLID, NULL, COLLISION_GROUP_NONE, &amp;tr );
UTIL_TraceLine(list[i]->GetAbsOrigin(),GetAbsOrigin()+Vector(0,10,0),MASK_PLAYERSOLID, NULL, COLLISION_GROUP_NONE, &amp;tr );
        CBasePlayer *pPlayer = ToBasePlayer(list[i]);
CBasePlayer *pPlayer = ToBasePlayer(list[i]);
 
      int distance = abs(UTIL_DistApprox2D(pPlayer->GetAbsOrigin(), GetAbsOrigin()+Vector(0,10,0)));
float distancesq = (pPlayer->GetAbsOrigin() - GetAbsOrigin()+Vector(0,10,0)).LengthSqr()
 
      float percent = 1.0;
float ratio = 1.0;
     
      if (distance >200)
if (distancesq >= 40000)
          percent = abs (1000*(1-((distance-200)/200.0)))/1000;
ratio = (200-(vec_t)FastSqrt(distancesq))/200.0;
     
        color32 white = { 255,255,255,(255*percent) };
color32 white = { 255,255,255,(255*ratio) };
 
      int fadehold = random->RandomInt( 0, 4 );
int fadehold = random->RandomInt( 0, 4 );
 
        if(tr.fraction == 1.0f) {
if(tr.fraction == 1.0f)
        UTIL_ScreenFade(pPlayer,white,CONC_FALLOFF_TIME+(.5f*fadehold*percent),fadehold*percent, FFADE_IN);
{
         
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 );
 
int effect = 0 ? random->RandomInt( 35, 37 ) : random->RandomInt( 32, 34 );
        CSingleUserRecipientFilter user( pPlayer );
        enginesound->SetPlayerDSP( user, effect, false );
CSingleUserRecipientFilter user( pPlayer );
      }
enginesound->SetPlayerDSP( user, effect, false );
      }
}
  }
}
 
}
  BaseClass::Detonate();
}</pre>
BaseClass::Detonate();
}</source>


==Update 3==
==Update 3==
<pre>if(tr.fraction == 1.0f)
<source lang=cpp>if(tr.fraction == 1.0f)
{
{
  if ( pPlayer->FInViewCone( this ) )
if ( pPlayer->FInViewCone( this ) )
  UTIL_ScreenFade(pPlayer,white,CONC_FALLOFF_TIME+(.5f*fadehold*percent),fadehold*percent, FFADE_IN);
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 );
int effect = 0 ? random->RandomInt( 35, 37 ) : random->RandomInt( 32, 34 );
CSingleUserRecipientFilter user( pPlayer );
enginesound->SetPlayerDSP( user, effect, false );
}</source>


  CSingleUserRecipientFilter user( pPlayer );
The above shows how to skip the screenfade if the player can't actually see the grenade.
  enginesound->SetPlayerDSP( user, effect, false );
}</pre>


the above shows how to skip the screenfade if the player cant see the grenade itself.
[[Category:Weapons programming]]

Latest revision as of 22:48, 21 January 2024

Wikipedia - Letter.png
This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these template messages)
Dead End - Icon.png
This article has no Wikipedia icon links to other VDC articles. Please help improve this article by adding links Wikipedia icon that are relevant to the context within the existing text.
January 2024
Broom icon.png
This article or section needs to be cleaned up to conform to a higher standard of quality.
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
There was a bug in the original code I posted here, where the grenade was actually blocking the flash. the fix is added here.
GetAbsOrigin()+Vector(0,10,0)
There was a problem with the concussion effect not working when using it in the crossbow "BoltTouch" function and jumping while firing downwards. The problem was that the mask wasn't working properly. Fixed it by replacing MASK_SOLID with MASK_PLAYERSOLID. This fix has been implemented into the code on this page already.
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...

  1. Find the distance the player is from the grenade
  2. Consider..
    • ..the 100% flash distance
    • ..the 0% distance
  3. 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 &lt; 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, &amp;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.