1. Mods don't all follow the same standards.
2. Mini-mods can fuck with buttons.
3. Melee and explosive devices don't use trace line
4. There are tons of trace lines sent out each second
However, by briefly looking in the HLSDK, we can see that these three Trace_*'s are used:
trace_line - guns
trace_hull - melee
trace_sphere - explosives
However, all three types of weapons use trace_line. So, we will start with trace_line.
Hooking trace_line with FM is a simple task; unfortunately, trace_line doesn't say what entity fired the trace_line, for speed.
To get a place to start, we'll consider this:
1. The starting point for firing a weapon is the player who fired.
2. The end point for firing a weapon is where it hits.
So, in theory, if we loop through the clients, comparing their origins and points of convergence for sight to the trace_line, we should come up with who fired!
Lets make some code!
Code: Select all
public check_trace( Float:start[3], Float:end[3], monsters, skip_ent, TraceResult:ptr)
{
new Players[32]
new playerCount, i, player
get_players(Players, playerCount, "a")
new Float:origin[3];
for (i=0; i<playerCount; i++)
{
player = Players[i];
entity_get_vector(player,EV_VEC_origin,origin)
if(is_my_traceline(start,origin) == 1) server_print("%i fired a shot!",player)
}
}Unfortunately, we hit a problem: The z origin is always different. Why? Because the gun is the one shooting, not the player. In order to keep with mod independence, we simply ignore the z origin. In addition, we need this:
Code: Select all
#define XS_FLEQ_TOLERANCE 5.0
#define XS_FLEQ(%1,%2) (((%1) <= ((%2) + XS_FLEQ_TOLERANCE)) && ((%1) >= ((%2) - XS_FLEQ_TOLERANCE)))
public is_my_traceline(Float:one[3],Float:two[3])
{
if( XS_FLEQ(one[0],two[0]) && XS_FLEQ(one[1],two[1]) /*&& (one[2] == two[2])*/ ) return 1;
return 0;
}As you might see, this is a little ineffecient. We could be losing a lot of speed, but at least it works, and always works. However, we can make it better.
The gun must not shoot the player aiming it. That would be bad; you'd kill yourself. So, lets assume that skip_ent will be the id of the shooter:
Code: Select all
public check_trace( Float:start[3], Float:end[3], monsters, skip_ent, TraceResult:ptr)
{
if(skip_ent > 0 && skip_ent <= get_maxplayers() ) server_print("%i fired a shot!",skip_ent)
}Since sending out a forward to other plugins is MUCH more expensive, speed wise, then doing a few math checks, we cna increase the speed of this function by adding back in some origin checking:
Code: Select all
public check_trace( Float:start[3], Float:end[3], monsters, skip_ent, TraceResult:ptr)
{
if(skip_ent > 0 && skip_ent <= get_maxplayers() )
{
new Float:origin[3]
entity_get_vector(skip_ent,EV_VEC_origin,origin)
if(is_my_traceline(start,origin) == 1) server_print("%i fired a shot!",skip_ent)
}
}Putting in the appropriate formatting, and add a few more bells and whistles, we have our plugin, which is uploaded below.
Feel free to use this as much as you like.
