PDA

View Full Version : [HowTo] Properly catch shot event in CS


VEN
05-06-2007, 15:23
Since CurWeapon/TraceLine methods may produce false positives i'd recommend to use the below method. Didn't added comments but variables/function names are descriptive enough. If you still don't undestand something ask me.

/* AMX Mod X
* gun_fire_playback_event_way.sma
*
* (c) Copyright 2007 by VEN
*
* This file is provided as is (no warranties)
*/

// plugin's main information
#define PLUGIN_NAME "gun_fire_playback_event_way"
#define PLUGIN_VERSION "0.1"
#define PLUGIN_AUTHOR "VEN"

#include <amxmodx>
#include <fakemeta>

#define MAX_CLIENTS 32

new g_fwid
new g_max_clients

new const g_guns_events[][] = {
"events/awp.sc",
"events/g3sg1.sc",
"events/ak47.sc",
"events/scout.sc",
"events/m249.sc",
"events/m4a1.sc",
"events/sg552.sc",
"events/aug.sc",
"events/sg550.sc",
"events/m3.sc",
"events/xm1014.sc",
"events/usp.sc",
"events/mac10.sc",
"events/ump45.sc",
"events/fiveseven.sc",
"events/p90.sc",
"events/deagle.sc",
"events/p228.sc",
"events/glock18.sc",
"events/mp5n.sc",
"events/tmp.sc",
"events/elite_left.sc",
"events/elite_right.sc",
"events/galil.sc",
"events/famas.sc"
}

new g_guns_eventids_bitsum

public plugin_precache() {
g_fwid = register_forward(FM_PrecacheEvent, "fwPrecacheEvent", 1)
}

public fwPrecacheEvent(type, const name[]) {
for (new i = 0; i < sizeof g_guns_events; ++i) {
if (equal(g_guns_events[i], name)) {
g_guns_eventids_bitsum |= (1<<get_orig_retval())
return FMRES_HANDLED
}
}

return FMRES_IGNORED
}

public plugin_init() {
register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR)

unregister_forward(FM_PrecacheEvent, g_fwid, 1)

register_forward(FM_PlaybackEvent, "fwPlaybackEvent")

g_max_clients = global_get(glb_maxClients)
}

public fwPlaybackEvent(flags, invoker, eventid) {
if (!(g_guns_eventids_bitsum & (1<<eventid)) || !(1 <= invoker <= g_max_clients))
return FMRES_IGNORED

// gun fired

return FMRES_HANDLED
}

Alka
05-06-2007, 15:38
Nice tut o0....Gj! :wink:

Arkshine
05-06-2007, 16:02
Interesting. :)

Zenith77
05-06-2007, 21:19
(1 <= invoker <= g_max_clients)


Ok, I remember talking about this a long time ago. Is this valid, are you able to do this? Because I had previously thought that it would read from left to right (like it normally does) and actually check the return from the pervious check.

VEN
05-07-2007, 03:30
Yes, it's valid.

...operators may be "chained", as in the expression "e1 <= e2 <= e3", with the semantics that the result is "1" if all individual comparisons hold and "0" otherwise.

Zenith77
05-07-2007, 16:33
Thanks for that clarification ;).

Simon Logic
06-01-2007, 10:15
what about
if(g_fwid) unregister_forward(FM_PrecacheEvent, g_fwid, 1)
?

Voi
08-18-2007, 12:34
how about processor consumption, its more resource eating than curweapon event ?

XxAvalanchexX
08-18-2007, 15:30
Are the events played back before or after the shot is actually fired?

VEN
08-19-2007, 07:28
After.

minimiller
07-31-2008, 18:28
VEN (or any1 else), i need some help...
I used this code to see when a player was shot, then i used an if statement to see if a player has <= 0 health to see if they died.
What i need now is to stop them from dieing, but i dont know how to :(
If the player who was shot did "die", i need to keep them alive and transfer them to a different team
Here is my code so far, but i'm stuck now :(


public fwPlaybackEvent(flags, invoker, eventid)
{
if(!(g_guns_eventids_bitsum & (1<<eventid)) || !(1 <= invoker <= g_max_clients))
{
return FMRES_IGNORED
}

if(get_user_health(player) <= 0)
{
// Player has died
}
return FMRES_HANDLED
}

danielkza
08-01-2008, 15:17
VEN (or any1 else), i need some help...
I used this code to see when a player was shot, then i used an if statement to see if a player has <= 0 health to see if they died.
What i need now is to stop them from dieing, but i dont know how to :(
If the player who was shot did "die", i need to keep them alive and transfer them to a different team
Here is my code so far, but i'm stuck now :(


public fwPlaybackEvent(flags, invoker, eventid)
{
if(!(g_guns_eventids_bitsum & (1<<eventid)) || !(1 <= invoker <= g_max_clients))
{
return FMRES_IGNORED
}

if(get_user_health(player) <= 0)
{
// Player has died
}
return FMRES_HANDLED
}


#include <hamsandwich>
public plugin_init()
RegisterHam(Ham_Killed,"player","fwPlayerKilled")

public fwPlayerKilled(id,killer,gib)
{
// Do your think here

// This is needed
set_pev(id,pev_health,1.0)

return HAM_SUPERCED
}

VEN
08-05-2008, 12:19
minimiller: since the above method is for post variant you can't use it for that. See the above post for a solution. FYI: should be "HAM_SUPERCEDE" instead of "HAM_SUPERCED".

danielkza
08-05-2008, 14:02
minimiller: since the above method is for post variant you can't use it for that. See the above post for a solution. FYI: should be "HAM_SUPERCEDE" instead of "HAM_SUPERCED".
You can also hook TakeDamage, and HamSandwich can alter function parameters on the fly. And I typed without paying much attention,sorry for that.

ot_207
09-19-2008, 12:23
Hi!
Sorry if what I say is a little bit offtopic.
But do the functions Ham_Weapon_PrimaryAttack/Ham_Weapon_SecondaryAttack do the same thing as this?
I've tried them in my plugin and didn't seem to work ...

This is how I used them... in case it was my error:

RegisterHam(Ham_Weapon_PrimaryAttack, "player", "fw_primary_attack")
RegisterHam(Ham_Weapon_SecondaryAttack, "player", "fw_secondary_attack")


public fw_primary_attack(id)
{
if (!is_user_alive(id))
return HAM_IGNORED
// code

return HAM_IGNORED
}

Arkshine
09-19-2008, 12:24
Theses forward work. How did you register them ? You have to register with the weapon name.

ot_207
09-19-2008, 12:25
Theses forward work. How did you register them ? You have to register with the weapon name.

I edited my post.
Edit: Can you give me an example please? So I won't make any errors.

Arkshine
09-19-2008, 12:37
RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_deagle", "fw_primary_attack") for example.

For all weapons, you can do :


#define MAX_WEAPONS 30

new s_WeaponName[ 24 ];

for ( new i_Wpn= 1; i_Wpn <= MAX_WEAPONS; i_Wpn++ )
{
get_weaponname ( i_Wpn, s_WeaponName, charsmax ( s_WeaponName ) );
if ( s_WeaponName[ 0 ] ) RegisterHam ( Ham_Weapon_PrimaryAttack, s_WeaponName, "fwd_PrimaryAttack" );
}

ot_207
09-19-2008, 12:38
RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_deagle", "fw_primary_attack") for example.

For all weapons, you can do :


#define MAX_WEAPONS 30

new s_WeaponName[ 24 ];

for ( new i_Wpn= 1; i_Wpn <= MAX_WEAPONS; i_Wpn++ )
{
get_weaponname ( i_Wpn, s_WeaponName, charsmax ( s_WeaponName ) );
if ( s_WeaponName[ 0 ] ) RegisterHam ( Ham_Weapon_PrimaryAttack, s_WeaponName, "fwd_PrimaryAttack" );
}


Thanks man!

Arkshine
09-19-2008, 12:40
Don't forget that it passes the weapon entity index, so to retrieve the player's id, you have to use pev_owner.

ot_207
09-19-2008, 12:52
Don't forget that it passes the weapon entity index, so to retrieve the player's id, you have to use pev_owner.

Already thought about that. ;) Thanks again!

LagParty
10-16-2008, 15:03
how can i know if the bullet that was shot hit an alive player or anything else? (im only using awp/scout for this)

danielkza
10-16-2008, 17:01
how can i know if the bullet that was shot hit an alive player or anything else? (im only using awp/scout for this)
Look at ham_const.inc for Ham_TraceAttack.

LagParty
12-21-2008, 00:52
Took about 2 months to guess what "this" meant, lol. I'm still a noob with hamsandwich and ham_traceattack returns 5 results with the search engine on the forum (also, the ham_const just gives basic info).

I believe that i need to give the attacked entity instead of the attacker, so i'd need to executeham on every player and compare the attacker id with the "invoker" of the gun fire event. I think there should be another (more efficient) way of doing what i want. I don't need to know the id of the player nor the aim origin or angles, just a true for you_hit_a_player and a false for you_hit_nothing. Maybe fakemeta is enough for the task?

Thanks.

ConnorMcLeod
12-21-2008, 04:13
Just register Ham_TraceAttack with entity "player", then, when the forward is called, check if idattacker is alive and then if idattacker weapon is a scout/awp.

LagParty
12-21-2008, 13:18
I was just about to ask for more help but then i said to myself "come on, think harder" So i started doing tests until i came up with a solution using the ham_traceattack and the forward for weapon fire.

I found that ham_traceattack gets called first, so i store the player id on a value and then on the other forward i check if the id is the same or not. I'll post the code for anyone that might find it helpful.

#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>

new g_fwid, g_guns_eventids_bitsum
new player_shots[33], tmpattacker

new const g_guns_events[][] = {
"events/awp.sc",
"events/scout.sc"
}
public plugin_precache() {
g_fwid = register_forward(FM_PrecacheEvent,"fwPrecacheEvent",1)
}
public fwPrecacheEvent(type, const name[]) {
for (new i = 0; i < sizeof g_guns_events; ++i) {
if (equal(g_guns_events[i], name)) {
g_guns_eventids_bitsum |= (1<<get_orig_retval())
return FMRES_HANDLED
}
}
return FMRES_IGNORED
}
public plugin_init() {
register_plugin("This is","a","Test")

unregister_forward(FM_PrecacheEvent, g_fwid, 1)
register_forward(FM_PlaybackEvent, "fwPlaybackEvent")

RegisterHam(Ham_TraceAttack,"player","fwd_Ham_TraceAttack")
register_event("DeathMsg", "player_dies","a")
}
public fwd_Ham_TraceAttack(this,idattacker,Float:dam age,Float:direction[3],traceresult,damagebits) {
if(is_user_alive(idattacker)) {
static wpn ; wpn = get_user_weapon(idattacker)
if(wpn==CSW_AWP||wpn==CSW_SCOUT) {
player_shots[idattacker] ++
tmpattacker = idattacker
//Testing pruposes
client_print(0,print_chat,"HAM: id = %d score = %d",idattacker,player_shots[idattacker])
}
}
}
public fwPlaybackEvent(flags, invoker, eventid) {
if (!(g_guns_eventids_bitsum & (1<<eventid))||!(is_user_alive(invoker))) {
return FMRES_IGNORED
}
if(invoker!=tmpattacker) {
player_shots[invoker] = 0
//Testtesttest
client_print(0,print_chat,"id = %d score %d",invoker,player_shots[invoker])
}
tmpattacker = 0
return FMRES_HANDLED
}
public player_dies() {
static player ; player = read_data(2)
if(is_user_connected(player)) {
player_shots[player] = 0
}
}
public client_disconnect(id) {
player_shots[id] = 0
}

The fun part comes next, because if the player gets a score of 2 or more points, i'll play a "impressive" quake3 sound and show the icon over the player's head. :P

Thanks conorr and danielkza (and ven of course for making the base).

Seta00
06-11-2010, 10:55
This is extremely useful. Bump for the great justice.

shuttle_wave
06-13-2010, 07:13
GJ

Doc-Holiday
08-10-2010, 01:28
Is this method still the best way?

Arkshine
08-10-2010, 05:25
All is depending your need, but it you need to catch each shot and nothing else, yes.

ConnorMcLeod
08-10-2010, 06:52
This way you catch the shot after it happens.

If you want to catch the shot before it happens you have to hook PrimaryAttack + some filters :

Pistols : clip + m_iShotsFired (63, shots count) <= 1 (+ not burst for glock)
Smgs : clip
Etc...

Doc-Holiday
08-10-2010, 14:16
yeah i use it to catch each shot to jam my weapon... and then i use some other things to block the shots...

Although i might try that updateclientinfo to block the animation right now i have it just remove the ammo and then give it back.

albert123
08-17-2010, 10:01
I don't understand about this plugin. Can someone explain me careful :( ?

Arkshine
08-17-2010, 10:06
You don't understand what exactly ?

albert123
08-18-2010, 02:34
I don't understand about description.. And its useful..because i'm beginner and trying to understand more advancer code.

ot_207
08-18-2010, 04:37
I don't understand about description.. And its useful..because i'm beginner and trying to understand more advancer code.

The code is meant for detecting when a user shoots. Try to do a client print to the invoker when he shoots and you will understand when that event takes place. And an advice. Stop reading advanced tutorials,instead try finding easier ones and after that start reading some basic plugins. After that start reading bigger tuts and even bigger/more complex plugins.
That is the way to learn. And ask questions whenever you feel uncertain about what you read/found/learned.

albert123
08-18-2010, 08:09
OK, i understand :-?

Jacob
12-30-2010, 10:00
thankS!

tei1995
03-13-2012, 21:09
Can you tell me how can i check elite shoot left or shoot right?

Doc-Holiday
03-14-2012, 00:06
Can you tell me how can i check elite shoot left or shoot right?

Well i am utterly blind and wrong lol

Arkshine
03-14-2012, 04:27
"events/elite_left.sc",
"events/elite_right.sc",

The answer is already in the first post.

tei1995
03-14-2012, 06:49
So i should create two var to get_orig_retval ?

Arkshine
03-14-2012, 06:52
Like in the example, use a sum of bits.

tei1995
03-14-2012, 19:20
Can you give me an example code?i cant imagine your idea...

ot_207
03-23-2012, 11:36
search the tutorials for bitsums and bitwise operators.

tei1995
03-31-2012, 09:48
I dont understand your idea about using bitsum.explain more for me plz?

Doc-Holiday
03-31-2012, 10:26
I dont understand your idea about using bitsum.explain more for me plz?

There is a ginormous tutorial on it.... Search don't be lazy

tei1995
04-04-2012, 07:35
I searched,read, but i until understand...

ConnorMcLeod
06-09-2012, 09:14
Code can be shortened a bit :

#include <amxmodx>
#include <fakemeta>

new g_iMaxPlayers;
#define IsPlayer(%0) ( 1 <= (%0) <= g_iMaxPlayers )

new g_iGunsEventsIdBitSum;

public plugin_init()
{
register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR);

new const szGunsEvents[][] = {
"events/awp.sc", "events/g3sg1.sc", "events/ak47.sc", "events/scout.sc", "events/m249.sc",
"events/m4a1.sc", "events/sg552.sc", "events/aug.sc", "events/sg550.sc", "events/m3.sc",
"events/xm1014.sc", "events/usp.sc", "events/mac10.sc", "events/ump45.sc", "events/fiveseven.sc",
"events/p90.sc", "events/deagle.sc", "events/p228.sc", "events/glock18.sc", "events/mp5n.sc",
"events/tmp.sc", "events/elite_left.sc", "events/elite_right.sc", "events/galil.sc", "events/famas.sc"
};
for(new i; i<sizeof(szGunsEvents); i++)
{
g_iGunsEventsIdBitSum |= 1<<engfunc(EngFunc_PrecacheEvent, 1, szGunsEvents[i]);
}

register_forward(FM_PlaybackEvent, "OnPlaybackEvent");

g_iMaxPlayers = get_maxplayers();
}

public OnPlaybackEvent(flags, id, eventid)
{
if( IsPlayer(id) && g_iGunsEventsIdBitSum & (1<<eventid) )
{
// gun fired

return FMRES_HANDLED;
}
return FMRES_IGNORED;
}

hornet
06-17-2012, 03:58
So how does this method compare as oppose to using Ham or Orpheu?

Arkshine
06-17-2012, 04:14
All is depending what you want to do. So be more precise.

The CS functions are called like that basically : "Weapon"::PrimaryAttack() -> "Weapon"Fire() -> pfnPlaybackEvent

If you want to catch each actual shots, you should use use PlaybackEvent method.

hornet
06-17-2012, 04:30
Well yes whenever I hook weapon fire its usually to get the single shot for something, or to block fire. -> Using Ham_Weapon_PrimaryAttack.

I haven't actually tried using Orpheu for this before but I've got a signature for each weapon and the virtual function PrimaryAttack.

Arkshine
06-17-2012, 04:42
PrimaryAttack() is not called on the actual shots. You could hold +attack without shooting and PrimaryAttack will be called in loop. With pfnPlaybackEvent, you can be sure called only per real shot.

Orpheu should not be used unless you want to hook the "Weapon"Fire() functions to alter params on-the-fly.

Doc-Holiday
06-17-2012, 21:44
So how does this method compare as oppose to using Ham or Orpheu?

With ham you catch primary and secondary attacks... Which is called even if the weapon isnt fired. I assume same with orphue how ever you can add checks and also hook pre..

Aooka
06-21-2012, 17:49
GJ ! :D

Just why that ? g_max_clients = global_get(glb_maxClients)

ConnorMcLeod
06-22-2012, 00:58
May be you could look where that variable is used ?

Liverwiz
06-27-2012, 13:57
I searched,read, but i until understand...

<VeCo> wrote up a great little explanation on how bitwise works. Maybe this will help you. It helped me a little. But its a very illusive subject.
http://forums.alliedmods.net/showpost.php?p=1720272&postcount=9

tei1995
06-28-2012, 11:55
solved =="

I have discoverd this one, when use playback_event in FM_PlayBackEvent forward, everyone in server wont hear the shoot sound, just only client-side can hear the shootsound.


/* Plugin generated by AMXX-Studio */

#include <amxmodx>
#include <fakemeta>

#define PLUGIN "Test"
#define VERSION "1.0"
#define AUTHOR "teobrvt1995"

new gEventWpn

public plugin_init() {
register_plugin(PLUGIN, VERSION, AUTHOR)

register_forward(FM_PlaybackEvent,"fwFM_PlaybackEvent")
}

public plugin_precache()
{
register_forward(FM_PrecacheEvent,"fwFM_PrecacheEvent_Post",1)

}

public fwFM_PrecacheEvent_Post(type,const event[])
{
if(equal(event,"events/ak47.sc"))
{
gEventWpn = get_orig_retval()

return FMRES_HANDLED
}
return FMRES_IGNORED
}

public fwFM_PlaybackEvent(flags, invoker, eventid, Float:delay, Float:origin[3], Float:angles[3], Float:fparam1, Float:fparam2, iParam1, iParam2, bParam1, bParam2)
{
if ((eventid != gEventWpn))
return FMRES_IGNORED

if (!(1 <= invoker <= 32))
return FMRES_IGNORED

fm_playback_event(flags | FEV_HOSTONLY, invoker, eventid, delay, origin, angles, fparam1, fparam2, iParam1, iParam2, bParam1, bParam2)
return FMRES_SUPERCEDE
}

NiHiLaNTh
06-28-2012, 12:55
Yes, FEV_HOSTONLY is sent only to the invoker.

tei1995
06-29-2012, 00:07
By this way, we can replace 90% weapon fire sound( play offline ) instead of using FM_UpdateClientData.

ironskillz1
06-10-2013, 15:37
This doesnt detect a usp with a silincer on.
Can this be done? to detect

ConnorMcLeod
06-10-2013, 16:35
This detects silenced weapons shots.

ironskillz1
06-10-2013, 17:16
This detects silenced weapons shots.

Nope this doesnt detect silence USP

I have tested without silencer and it worked perfect.
But With silencer it doesnt work

Arkshine
06-10-2013, 19:26
With/out silencer is unrelated. The event sent is the same. The problem is either your code or how you test.

Bugsy
12-01-2015, 19:24
By request from another forum member, I added the ability to get the CSW_ weapon index of the fired weapon. Not sure if this is the best way to capture weapon fire anymore, but thought I'd share.

#include <amxmodx>
#include <fakemeta>

new g_fwid , g_max_clients , g_guns_eventids_bitsum;

new const g_guns_events[][] =
{
"events/awp.sc", "events/g3sg1.sc", "events/ak47.sc", "events/scout.sc", "events/m249.sc",
"events/m4a1.sc", "events/sg552.sc", "events/aug.sc", "events/sg550.sc", "events/m3.sc",
"events/xm1014.sc", "events/usp.sc", "events/mac10.sc", "events/ump45.sc", "events/fiveseven.sc",
"events/p90.sc", "events/deagle.sc", "events/p228.sc", "events/glock18.sc", "events/mp5n.sc",
"events/tmp.sc", "events/elite_left.sc", "events/elite_right.sc", "events/galil.sc", "events/famas.sc"
};

new const g_guns_weaponid[] =
{
0, CSW_AWP, CSW_G3SG1, CSW_AK47, CSW_SCOUT, CSW_M249, CSW_M4A1, CSW_SG552, CSW_AUG, CSW_SG550,
CSW_M3, CSW_XM1014, CSW_USP, CSW_MAC10, CSW_UMP45, CSW_FIVESEVEN, CSW_P90, CSW_DEAGLE,
CSW_P228, 0, CSW_GLOCK18, CSW_MP5NAVY, 0, CSW_ELITE, CSW_ELITE, 0, 0, CSW_GALIL, CSW_FAMAS
};

public plugin_precache()
{
g_fwid = register_forward( FM_PrecacheEvent , "fwPrecacheEvent" , true );
}

public fwPrecacheEvent( type , const name[] )
{
for ( new i = 0 ; i < sizeof( g_guns_events ) ; ++i )
{
if ( equal( g_guns_events[ i ] , name ) )
{
g_guns_eventids_bitsum |= ( 1 << get_orig_retval() );
return FMRES_HANDLED;
}
}

return FMRES_IGNORED;
}

public plugin_init()
{
unregister_forward( FM_PrecacheEvent , g_fwid , true );
register_forward( FM_PlaybackEvent , "fwPlaybackEvent" );

g_max_clients = global_get( glb_maxClients );
}

public fwPlaybackEvent( flags , invoker , eventid )
{
if ( !( g_guns_eventids_bitsum & ( 1 << eventid ) ) || !( 1 <= invoker <= g_max_clients ) )
return FMRES_IGNORED;

//Player fired weapon. WeaponID is stored in g_guns_weaponid[ eventid ]

new szWeapon[ 20 ];
get_weaponname( g_guns_weaponid[ eventid ] , szWeapon , charsmax( szWeapon ) );
client_print( invoker , print_chat , "You fired %s" , szWeapon );

return FMRES_HANDLED;
}

waza123a
03-14-2016, 13:54
Why this code does not have grenade event ? How to add it ?

klippy
03-14-2016, 14:16
There's grenade_throw forward provided by CSX (http://amxmodx.org/api/csx/__raw).