Making a concussion grenade: Difference between revisions
(fixup) |
|||
Line 1: | Line 1: | ||
[[Category:Programming]] | [[Category:Programming]] | ||
==Info | ==Info== | ||
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. | 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. | ||
==Purpose | ==Purpose== | ||
To Create a grenade that will blind someone. | To Create a grenade that will blind someone. | ||
==Route | ==Route== | ||
Research UTIL_ functions and BaseGrenade | Research UTIL_ functions and BaseGrenade | ||
==Solution | ==Solution== | ||
One simple function does it all folks. | One simple function does it all folks. | ||
<pre>void CGrenadeConc::Detonate( void ) | <pre>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(); | |||
}</pre> | }</pre> | ||
Line 52: | Line 52: | ||
<pre>GetAbsOrigin()+Vector(0,10,0)</pre> | <pre>GetAbsOrigin()+Vector(0,10,0)</pre> | ||
</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. | <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. | ||
<pre>MASK_SOLID | <pre>MASK_SOLID replaced with MASK_PLAYERSOLID</pre> | ||
</div> | |||
==Update 1== | ==Update 1== | ||
The question was posed... " | 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 | |||
#Find the distance the player is from the grenade | #Find the distance the player is from the grenade | ||
# | #Consider.. | ||
#*the 100% flash distance | #*..the 100% flash distance | ||
#*the 0% distance | #*..the 0% distance | ||
# | #Calculate and set alpha | ||
So let's do it really quick | |||
1 | ===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 | |||
<pre>CBasePlayer *pPlayer = ToBasePlayer(list[i]); | <pre>CBasePlayer *pPlayer = ToBasePlayer(list[i]); | ||
Line 84: | Line 82: | ||
color32 white = { 255,255,255,255 };</pre> | color32 white = { 255,255,255,255 };</pre> | ||
A simple line will take care of finding the distance... | |||
float distance = (pPlayer->GetAbsOrigin() - GetAbsOrigin()+Vector(0,10,0)).Length() | |||
===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... | |||
if (distance >= 200) | |||
ratio = 1-(distance-200)/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) }; | |||
color32 white = { 255,255,255,(255* | |||
==Update 2== | ==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. | |||
<pre>void CGrenadeConc::Detonate( void ) | <pre>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 distance = (pPlayer->GetAbsOrigin() - GetAbsOrigin()+Vector(0,10,0)).Length() | |||
float ratio = 1.0; | |||
if (distance >= 200) | |||
ratio = 1-(distance-200)/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(); | |||
}</pre> | }</pre> | ||
Line 182: | Line 160: | ||
<pre>if(tr.fraction == 1.0f) | <pre>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 ); | |||
}</pre> | }</pre> | ||
The above shows how to skip the screenfade if the player can't actually see the grenade. |
Revision as of 20:02, 27 March 2007
Info
This Tutorial was originally from gneu.org and moved here to combine all the tutorials into one location.
Purpose
To Create a grenade that will blind someone.
Route
Research UTIL_ functions and BaseGrenade
Solution
One simple function does it all folks.
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 distance = (pPlayer->GetAbsOrigin() - GetAbsOrigin()+Vector(0,10,0)).Length()
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...
if (distance >= 200)
ratio = 1-(distance-200)/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 distance = (pPlayer->GetAbsOrigin() - GetAbsOrigin()+Vector(0,10,0)).Length() float ratio = 1.0; if (distance >= 200) ratio = 1-(distance-200)/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.