You can use
grenade_throw forward to hook when a grenade is thrown.
This forward is based on
SetModel forward, in others words
grenade_throw is called right after a throw(ing?) when the grenade model is applied.
The problem is : the explosion comes after, so you may think that's not a good way.
Here, a preview of a basic flow (and only what we need) of a smoke grenade explosion :
Code:
You throw a grenade
┌ A new grenade entity spawns
└ The smoke grenade model is applied on the entity → grenade_throw called.
┌ After 1.5 seconds, the grenade detonates
├ createsmoke.sc event is called. (big smoke)
└ m_SGExplosionPos offset is set by the current grenade position.
└ 0.1 second later, the grenade explodes.
┌ 0.1 second later, the smoke appears
└ A second createsmoke.sc event is fired. (20 times, small smoke)
└ Grenade removed.
So, a solution would be to hook the
createsmoke.sc event (the first) in
grenade_throw and since we hook this forward, we don't need the offset anymore.
But since the player's id is not passed for this event, we need some trick.
An example :
PHP Code:
#include <amxmodx>
#include <fakemeta>
#include <csx>
new HandleFwdPlaybackEvent;
new Array:HandleGrenadePlayerIdQueue;
public plugin_init()
{
register_plugin( "", "", "" );
}
public grenade_throw( player, grenade, weaponId )
{
if( weaponId == CSW_SMOKEGRENADE )
{
if( HandleGrenadePlayerIdQueue == Invalid_Array )
{
HandleGrenadePlayerIdQueue = ArrayCreate();
}
ArrayPushCell( HandleGrenadePlayerIdQueue, player );
if( !HandleFwdPlaybackEvent )
{
HandleFwdPlaybackEvent = register_forward( FM_PlaybackEvent, "OnPlaybackEvent" );
}
}
}
public OnPlaybackEvent( const flags, const client, const eventIndex, const Float:delay, const Float:origin[3] )
{
if( HandleFwdPlaybackEvent )
{
new player = ArrayGetCell( HandleGrenadePlayerIdQueue, 0 );
ArrayDeleteItem( HandleGrenadePlayerIdQueue, 0 );
if( !ArraySize( HandleGrenadePlayerIdQueue ) )
{
ArrayDestroy( HandleGrenadePlayerIdQueue );
unregister_forward( FM_PlaybackEvent, HandleFwdPlaybackEvent );
HandleFwdPlaybackEvent = 0;
}
// Use origin variable to get the explosion origin.
//server_print( "Player %d - Explosion origin = %f %f %f", player, origin[ 0 ], origin[ 1 ], origin[ 2 ] );
}
}
Note #1 : It's an example, so it may need more check for example if player is still connected, or if you throw a grenade, the game is reset or new round and the grenade is removed right away without exploding, the Array would need to be destroy. Such situation where you need to check.
Note #2 : A more direct way would be simply to hook directly
CGrenade::SG_Detonate() as post, with orpheu and retrieving the
m_SGExplosionPos offset. If you don't care using Orpheu module, tell me.
__________________