[Include] GetPlayerAimedBodyPart - Detect Headshots, Armshots, Legshots !
#1

How it works

Using GetPlayerCameraFrontVector, GetPlayerCameraPos, but not any loops, this simple function detects where the shooter is aiming, and it returns a value according to where the shooter is aiming.
Works for every weapon : you can use this with guns, but also with close range weapons - see the video with the katana for example. It even detect the headshots when the target is in a vehicle, and headshots/armshots for crouched players !

Ideal for DM and zombie servers of course, but also nice for RP servers to get more realistic shootings !

Function

pawn Код:
stock GetPlayerAimedBodyPart(playerid, targetid, Float:range,weapon); //Returns the bodypart of targetid which playerid is aiming. Use it with OnPlayerTakeDamage ; I only tested it with it.
Callbacks

pawn Код:
public OnPlayerHeadshot(playerid,targetid,weaponid);//Do whatever you want when a player is hit in the head, the arm, the leg...
public OnPlayerLegshot(playerid,targetid,weaponid);
public OnPlayerArmshot(playerid,targetid,weaponid);
Put them wherever you want in your script.

In Game function

Код:
/widescreen - since 2.0, activates or deactivates the Widescreen mode for the player.
I made this function so the player manages manually the Widescreen ON/OFF mode. Indeed, as I try to explain below, although in the 1.0 and 1.01 versions being in Widescreen ON mode made it really easier to make headshots, this is not anymore a problem since 2.0, so the script doesn't have to check itself if the player uses Widescreen or not. It is now the player's problem since it doesn't give him advantages to use it or not. Don't hesitate to ask questions about this

v2.0 update (06/01/2013)
  • finally got this working as a real include
  • greatly improved the accuracy thanks to Nero_3D GetPlayerCameraWeaponVector include that let me take the correct offset with Widescreen ON
  • /widescreen command to let the player take the Widescreen ON/OFF mode. Being in Widescreen ON mode is no longer a problem since it doesn't make it easier to do headshots. Indeed, the script now checks if the player aims a point, no more just the coord on Z axis. Please note it is still working better with Widescreen OFF mode.
Pastebin (v2.0)
v1.01 update (03/01/2013)
  • made it easier to shoot the arm, which was almost impossible in the 1.0
  • kind of found a solution about the widescreen on/off problem (thanks to Nanory on Samp Forums for reporting) : the script checks if the player has an "overcorrection" with the GetPlayerCameraFrontVector Z-coord (which was the case when the player used Widescreen). If so, it will put the player in a "Widescreen" mode.
    Also (since all the values were got experimentally), it will make the inverse check with angle correction (still about the GetPlayerCameraFrontVector inaccuracy with other weapons than sniper rifle) to check if the player lacks of correction. So basically, if the player is not in Widescreen but the script detected so (because of any bug or a wrong calculation), the script will automatically put the player back in non-Widescreen mode.
    Added some calculation to do that, and a PVar "Widescreen".
  • Also took TheArcher's (thanks by the way) piece of advice about the callbacks.
Pastebin (v1.01 - Fix)
Pastebin (v1.0)
Example

Here is how I used the callbacks in the video (see code below) :
  • If hit in the head, if the player doesn't have a helmet the player dies or loses a lot of health according to the shooter weapon.
  • If hit in the leg, player will randomly fall or not.
  • If hit in the arm, the player might lose his weapon.


pawn Код:
public OnPlayerHeadshot(playerid,targetid,weaponid)
{
    new Float:Arm,Float:heal;

    GetPlayerArmour(targetid,Arm);
    GetPlayerHealth(targetid,heal);
   
    switch(weaponid){
                                case 33,34,30,31,25..27,24:{
                                    if(Casque[playerid]>1&&Arm>0){
                                        Casque[playerid]--;
                                        SetPlayerArmour(targetid,Arm-25);
                                    }
                                    else SetPlayerHealth(targetid,0);
                                }
                                case 22,23,28,29,32:{
                                    if((Arm>0&&Casque[targetid]>0)||GetPlayerSkin(targetid)==285){
                                        Casque[targetid]--;
                                        SetPlayerArmour(targetid,Arm-15);
                                    }
                                    else SetPlayerHealth(targetid,floatround(heal-30,floatround_round));
                                }
                                case 8:SetPlayerHealth(targetid,0);
                                case 4..6,1:SetPlayerHealth(targetid,floatround(heal-30,floatround_round));
                                default:SetPlayerHealth(targetid,floatround(heal-5,floatround_round));
    }
    GameTextForPlayer(playerid,"HEADSHOT !",1000,6);
    GameTextForPlayer(targetid,"OUCH ! HEADSHOT !",1000,6);
    return 1;
}

public OnPlayerLegshot(playerid,targetid,weaponid)
{
    switch(weaponid){
                                case 33,34,30,31,25..27,24:{
                                    if(random(3)==1) OnePlayAnim(targetid,"ped","FLOOR_hit",4,0,1,1,0,0);
                                }
                                case 22,23,28,29,32:{
                                    if(random(5)==1) OnePlayAnim(targetid,"ped","FLOOR_hit",4,0,1,1,0,0);
                                }
                                case 8:{
                                    if(random(2)==1) OnePlayAnim(targetid,"ped","FLOOR_hit",4,0,1,1,0,0);
                                }
                                case 4..6,1:
                                {
                                    if(random(3)==1) OnePlayAnim(targetid,"ped","FLOOR_hit",4,0,1,1,0,0);
                                }
                                default:{
                                    if(random(3)==1) OnePlayAnim(targetid,"ped","FLOOR_hit",4,0,1,1,0,0);
                                }
    }
    GameTextForPlayer(playerid,"LEGSHOT !",1000,6);
    GameTextForPlayer(targetid,"OUCH ! LEGSHOT !",1000,6);
    return 1;
}

public OnPlayerArmshot(playerid,targetid,weaponid)
{
    new wep=GetPlayerWeapon(targetid);
    if(wep!=0){
        switch(weaponid){
                                    case 33,34,30,31,25..27,24:{
                                        if(random(2)==1) DropWep(targetid,wep);
                                    }
                                    case 22,23,28,29,32:{
                                        if(random(3)==1) DropWep(targetid,wep);
                                    }
                                    case 8:{
                                        if(random(2)==1) DropWep(targetid,wep);
                                    }
                                    case 4..6,1:
                                    {
                                        if(random(2)==1) DropWep(targetid,wep);
                                    }
                                    default:{
                                        if(random(2)==1) DropWep(targetid,wep);
                                    }
        }
        GameTextForPlayer(playerid,"ARMSHOT !",1000,6);
        GameTextForPlayer(targetid,"OUCH ! ARMSHOT !",1000,6);
    }
    return 1;
}
Video

[ame="http://www.youtube.com/watch?v=2Y4ngd_wpzY"]Video[/ame]
Notice it works pretty well (this video was made with 1.0 version)

Installation

Just put this on top of your script :

pawn Код:
#include <GPABP>
Then, just put the callbacks seen above wherever you want in your script.

Q & A
  • What if the target is in movement? (His arms would swing and his legs would move)
    What if the target is falling/jumping?
    Does it detect those things?

    Basically the script calculates where the player is aiming and, if the target (whose Pos is X Y Z for example) is hit and if the shooter aims below Z-0.3, the player is aiming the legs. Then if the target moves, the script doesn't care if the legs move, it just determines if the player is aiming below Z-0.3.
    It is almost the same with the arms, except it depends on the X and Y coordinates (and the facing angle then) - that actually makes the armshot the toughest to detect.
    About the falling/jumping stuff, it should work just as fine as any other movement (player running...).
  • What happens when the victim is lying on the floor? for example, if he has just got out of a moving vehicle, you know that he rolls on the floor a bit, then he lies for a moment and finally gets up. Same when the victim has just been hit by a vehicle.
    If the player is lying on the floor you would have to aim down, so I guess the script would detect a legshot. However this is not so frequent, so it wouldn't be really bothering.
Credits
  • wups for GetDistanceFromPointToLine
  • Double-O-Seven for CrossProduct system
  • Nero3D for GetPlayerCameraWeaponVector
Thanks also to TheArcher, wups, Nanory for their help and contribution.


Don't hesitate to ask questions or suggest improvements. Feel free to share/use/modify but please don't remove credits if you share it.
Reply
#2

Pretty nice script ^_^. I have one suggestion.

Instead of modifying the include for

pawn Код:
public OnPlayerHeadshot(playerid,targetid,weaponid);
public OnPlayerLegshot(playerid,targetid,weaponid);
public OnPlayerArmshot(playerid,targetid,weaponid);
Just edit this part:

pawn Код:
case 1:OnPlayerHeadshot(issuerid,playerid,weaponid);
case 2:OnPlayerLegshot(issuerid,playerid,weaponid);
case 3:OnPlayerArmshot(issuerid,playerid,weaponid);
to

pawn Код:
case 1:CallLocalFunction("OnPlayerHeadshot", "ddd", issuerid,playerid,weaponid);
case 2:CallLocalFunction("OnPlayerLegshot", "ddd", issuerid,playerid,weaponid);
case 3:CallLocalFunction("OnPlayerArmshot", "ddd", issuerid,playerid,weaponid);
So, the callback is called only if your FS/GM has the "public".
Reply
#3

Hmm. I still will forever doubt such a feature will be accurate. But well done anyway. There was a GetPlayerWeaponVector function made, I forgot the author however maybe consider using that if it would work.
Reply
#4

Great script ! thx
Reply
#5

Now test it on a server with 100+ players
Reply
#6

Quote:
Originally Posted by Lorenc_
Посмотреть сообщение
I still will forever doubt such a feature will be accurate.
Me too. When a player with 300 ping will run and I hit his head with sniper (lag shooting), the camera's position will be kinda different compared to a player who doesn't move.
Reply
#7

First, thanks for your comments and feedback.

@ TheArcher : Thanks for the suggestion. It is the first time I release an "include" so I didn't really know how I should post it. I will consider what you said about the callbacks.

@ Lorenc & Dwane : Of course there are some imperfections, but as you can see in the video, the result is pretty good, as every distance and with every weapon. I ******d the "GetPlayerWeaponVector" stuff but couldn't find anything interesting.
However in this script, I considered the fact that, when you aim with a weapon, the GetPlayerCameraFrontVector (on the Z axis) won't be really accurate, except with the sniper rifle. Indeed, when you're aiming, the player CameraFrontVector doesn't look exactly where you aim, the crosshair, but below it. At first I didn't consider this, then the results were awful and you could make headshots from very short distances only. That's why I used some trigo with angles I determined for each kind of weapon, making some tests, to get the most accurate result I could.
About the lag, since it uses the player pos, it will sure be tough to hit a player with lag, but it always is ^^ Although (if I can I will make some tests with other people), if you aim in front of the player while he moves, theoretically you could make headshots and stuff... To be tested.

@ Aldo : Unlike the last script I saw about this "headshot" problem, this script doesn't use any loop. It is only basic calculation from distances and player vectors. I can't test it on a 100+ server for now, but it would be interesting indeed if someone could tell us what it does... Though I don't think this eats much Ram.
Reply
#8

What if the target is in movement? (His arms would swing and his legs would move)
What if the target is falling/jumping?

Does it detect those things?

BTW nice work
Reply
#9

I have a doubt. How you declared, "Casque"? xD is it a normal variable?
Excellent contribution, I will add in Zombie Walk. thank you very much
Reply
#10

Thanks for the feedback

I tested the script with 3 mates yesterday and they all thought it worked fine, even with a little lag (I was running the server with a Wifi connexion). Only the armshot is kind of difficult to get.

Quote:
Originally Posted by Maxips2
Посмотреть сообщение
What if the target is in movement? (His arms would swing and his legs would move)
What if the target is falling/jumping?

Does it detect those things?
Basically the script calculates where the player is aiming and, if the target (whose Pos is X Y Z for example) is hit and if the shooter aims below Z-0.3, the player is aiming the legs. Then if the target moves, the script doesn't care if the legs move, it just determines if the player is aiming below Z-0.3.

It is almost the same with the arms, except it depends on the X and Y coordinates (and the facing angle then) - that actually makes the armshot the toughest to detect.

About the falling/jumping stuff, it should work just as fine as any other movement (player running...).

Quote:
Originally Posted by RubenZone
Посмотреть сообщение
I have a doubt. How you declared, "Casque"? xD is it a normal variable?
Lol "casque" means "helmet" in French, it is just a variable in my test script
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)