[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


Messages In This Thread

Forum Jump:


Users browsing this thread: 4 Guest(s)