19.01.2015, 12:17
(
Last edited by CalvinC; 29/04/2016 at 02:51 PM.
Reason: Updated - More accurate, more info
)
When i ******d this, i found no-one having a real tutorial of this, only some vague attempts that doesn't work properly, so i decided to make my first tutorial here about my own script.
Includes
You only need the basic a_samp include.
Description
This tutorial will learn you how to create an efficient system that gives custom damages to players, depending where you shoot on their body, and more factors you can choose yourself.
• This includes custom armour damage, i saw alot of tutorials that only gave custom damages to health, not armour.
• This removes the old damage, so you can make completely new damages. I saw alot of tutorials that only added more damage to the old damage.
To do this, we use either the OnPlayerTakeDamage callback or the OnPlayerGiveDamage callback.
They have some pre-made parameters i will show you:
For the sake of this tutorial we will be using OnPlayerTakeDamage.
OnPlayerTakeDamage VS OnPlayerGiveDamage
OnPlayerTakeDamage is called when a player takes damage on their screen, while OnPlayerGiveDamage is called when an attacker deals damage to another player on the attackers screen.
The upside with OnPlayerTakeDamage is that the damage always looks fair on both clients screens.
Although the aggressor may shoot the player where the callback isn't called because the bullet or punch doesn't hit the victim on their screen.
This also leads to the weird SAMP sync during melee fights where sometimes nobody takes damage when hitting eachother.
OnPlayerGiveDamage gives a much more accurate feel for the attacking player, although the bullets or punches doesn't always hit on the victim's screen the callback will still be called, as long as they hit on the aggressors screen.
This is arguable a way to fix the SAMP sync during melee fights, since the player always deals damage when punching the other player.
The other player doesn't necessarily see it on their screen though, and both players can end up continuously damaging eachother at the same time.
Part 1 - Setting Teams
First off, we need to assign the player to the same teams, which makes them unable to damage eachother, then we can use our own damages instead.
We do this with the SetPlayerTeam function when the player connects.
Part 2 - Get Players Health and Armour
Before adding weapon damages, we need to get the players health and armour, then store it in 2 different floats, floats are tagged variables you can store different information in, like health, armour, coordinates and such. If you need more info, you can read more about it on the wiki.
So we declare the variables, but we need to declare them as floats, so we put "Float:variablename".
You can name the floats whatever you want, it doesn't matter.
I called them "health" and "armour", so now our OnPlayerTakeDamage callback should look like underneath.
But we have to store the health and armour of the player in these floats, as of now we just created them.
To store the players health and armour in these floats, use GetPlayerHealth(playerid, Float:variablename) and GetPlayerArmour(playerid, Float:variablename)
Now we have the players health and armour, which we will need later.
Part 3 - Setting up the Switches
Now we need the weapon ID that the "issuer" attacked the player with.
Quite handy, it's already declared in the variable as "weaponid".
So to set up different damages for each weapon, we use a switch to detect which system to use.
I see alot of people using this method:
You can do this, but this method is very inefficient and slow.
It is both easier, more efficient, and faster to use switches, as the wiki also states, this counts for everything where you would use an "else" or "else if", if it's possible, use a switch instead.
To create a switch, we set it up like this:
NOTE: All weapon ID's can be found here.
So now we'll work with the Desert Eagle weapon. And i already showed you how to set up a switch to detect it. (And other weapons.)
If you want more weapons, just put more "Case id:", and replace "id" with the weaponid ofcourse.
But now we need to check if the player has armour, or if he doesn't, and then deal damage to his armour, or health.
We use a switch again, to check if his armour is 0, then we deal damage to his health. And we use "default" which replaces the "else", so if his armour isn't 0, it will activate the "default" code.
We create the switch inside the case 24: (Desert Eagle weapon), like this:
Those are the basic switches done, in part 4 i explain how to give damage according to which bodypart was hit.
Part 4 - Applying the Custom Damages & Detecting Bodyparts
Now we need to get the bodyparts, and deal damage accordingly to which bodypart was hit.
So therefore we need to define the bodyparts ourselves, by putting this at the top of our script.
There's no body part 0, 1 or 2 as of now.
So the case 0 is called when the player doesn't have armour, therefore we deal damage to the players health, according to which bodypart was hit.
So we create a switch, that switches through the value of "bodypart", which is created in the callback, and we defined.
These values obviously aren't realistic, but i can use them to describe, so this will check if the case is etc. 4, (BODY_PART_GROIN) and SetPlayerHealth to his current health, minussed with 20.
It will do accordingly with the other cases, such as 9, (BODY_PART_HEAD) it will set his health to his current health, minussed with 50.
Ofc. you can change the damages it will minus the health with.
And then you do the same under "default", just change SetPlayerHealth to SetPlayerArmour, and health - (value) to armour - (value).
And you're done!
By now you should hopefully have a fully working custom damage system for your servers, if you have any questions, feel free to ask about it below.
Quote:
Table of Contents Includes Description OnPlayerTakeDamage VS OnPlayerGiveDamage Part 1 - Setting Teams Part 2 - Get Players Health and Armour Part 3 - Setting up the Switches Part 4 - Applying the Custom Damages & Detecting Bodyparts |
You only need the basic a_samp include.
Description
This tutorial will learn you how to create an efficient system that gives custom damages to players, depending where you shoot on their body, and more factors you can choose yourself.
• This includes custom armour damage, i saw alot of tutorials that only gave custom damages to health, not armour.
• This removes the old damage, so you can make completely new damages. I saw alot of tutorials that only added more damage to the old damage.
To do this, we use either the OnPlayerTakeDamage callback or the OnPlayerGiveDamage callback.
They have some pre-made parameters i will show you:
Code:
public OnPlayerTakeDamage(playerid, issuerid, Float: amount, weaponid, bodypart) // playerid = The player that got damaged. // issuerid = The player or thing that gave the damage. // Float: amount = The amount of damage given. // weaponid = The weapon ID that dealt the damage, may also be other reasons which can be seen on the wiki. // bodypart = The bodypart that was hit. public OnPlayerGiveDamage(playerid, damagedid, Float: amount, weaponid, bodypart) // playerid = The person that gave the damage. // damagedid = The player that got damaged. // Float: amount = The amount of damage given. // weaponid = The weapon ID that dealt the damage. // bodypart = The bodypart that was hit.
OnPlayerTakeDamage VS OnPlayerGiveDamage
OnPlayerTakeDamage is called when a player takes damage on their screen, while OnPlayerGiveDamage is called when an attacker deals damage to another player on the attackers screen.
The upside with OnPlayerTakeDamage is that the damage always looks fair on both clients screens.
Although the aggressor may shoot the player where the callback isn't called because the bullet or punch doesn't hit the victim on their screen.
This also leads to the weird SAMP sync during melee fights where sometimes nobody takes damage when hitting eachother.
OnPlayerGiveDamage gives a much more accurate feel for the attacking player, although the bullets or punches doesn't always hit on the victim's screen the callback will still be called, as long as they hit on the aggressors screen.
This is arguable a way to fix the SAMP sync during melee fights, since the player always deals damage when punching the other player.
The other player doesn't necessarily see it on their screen though, and both players can end up continuously damaging eachother at the same time.
Part 1 - Setting Teams
First off, we need to assign the player to the same teams, which makes them unable to damage eachother, then we can use our own damages instead.
We do this with the SetPlayerTeam function when the player connects.
Code:
public OnPlayerConnect(playerid) { SetPlayerTeam(playerid, 0); return 1; }
Before adding weapon damages, we need to get the players health and armour, then store it in 2 different floats, floats are tagged variables you can store different information in, like health, armour, coordinates and such. If you need more info, you can read more about it on the wiki.
So we declare the variables, but we need to declare them as floats, so we put "Float:variablename".
You can name the floats whatever you want, it doesn't matter.
I called them "health" and "armour", so now our OnPlayerTakeDamage callback should look like underneath.
Code:
public OnPlayerTakeDamage(playerid, issuerid, Float:amount, weaponid, bodypart) { new Float: health, Float: armour ; // Declares the variables, and defines them as floats. return 1; }
To store the players health and armour in these floats, use GetPlayerHealth(playerid, Float:variablename) and GetPlayerArmour(playerid, Float:variablename)
Code:
public OnPlayerTakeDamage(playerid, issuerid, Float:amount, weaponid, bodypart) { new Float: health, Float:armour ; // Declares the variables, and defines them as floats. GetPlayerHealth(playerid, health); // Gets the health of the player that took damage, and stores it in the float "health". GetPlayerArmour(playerid, armour); // Gets the armour of the player that took damage, and stores it in the float "armour". return 1; }
Part 3 - Setting up the Switches
Now we need the weapon ID that the "issuer" attacked the player with.
Quite handy, it's already declared in the variable as "weaponid".
So to set up different damages for each weapon, we use a switch to detect which system to use.
I see alot of people using this method:
Code:
if(weaponid == 24) // If the weapon is an Desert Eagle (id 24) { // Codes } else if(weaponid == 31) // If the weapon is an M4 (id 31) { // Codes } else if(weaponid == 34) // If the weapon is an Sniper (id 34) { // Codes }
It is both easier, more efficient, and faster to use switches, as the wiki also states, this counts for everything where you would use an "else" or "else if", if it's possible, use a switch instead.
To create a switch, we set it up like this:
Code:
public OnPlayerTakeDamage(playerid, issuerid, Float: amount, weaponid, bodypart) { new Float: health, Float:armour ; // Declares the variables, and defines them as floats. GetPlayerHealth(playerid, health); // Gets the health of the player that took damage, and stores it in the float "health". GetPlayerArmour(playerid, armour); // Gets the armour of the player that took damage, and stores it in the float "armour". switch(weaponid) // Starts the switch, and switches through the variable "weaponid". (declared in callback) { case 24: // If the variable is set to 24 (Desert Eagle weaponid), it activates the codes below. { // Codes } case 31: // If the variable is set to 31 (M4 weaponid), it activates the codes below. { // Codes } case 34: // If the variable is set to 34 (Sniper weaponid), it activates the codes below. { // Codes } } return 1; }
So now we'll work with the Desert Eagle weapon. And i already showed you how to set up a switch to detect it. (And other weapons.)
If you want more weapons, just put more "Case id:", and replace "id" with the weaponid ofcourse.
But now we need to check if the player has armour, or if he doesn't, and then deal damage to his armour, or health.
We use a switch again, to check if his armour is 0, then we deal damage to his health. And we use "default" which replaces the "else", so if his armour isn't 0, it will activate the "default" code.
We create the switch inside the case 24: (Desert Eagle weapon), like this:
Code:
case 24: // Desert Eagle weapon ID { switch(armour) // Creates a switch that switches through the armour float, and checks the value. { case 0: // If the value is 0, the codes underneath will activate. { // Codes } default: // Otherwise the codes underneath will activate. { // Codes } } }
Part 4 - Applying the Custom Damages & Detecting Bodyparts
Now we need to get the bodyparts, and deal damage accordingly to which bodypart was hit.
Quote:
Originally Posted by SA-MP Wiki
Important Note These IDs are not 100% confirmed, and are not defined in any SA-MP includes - they must be defined by the scripter. It is unknown if IDs 0, 1 and 2 have any use. |
Code:
#define BODY_PART_TORSO 3 #define BODY_PART_GROIN 4 #define BODY_PART_LEFT_ARM 5 #define BODY_PART_RIGHT_ARM 6 #define BODY_PART_LEFT_LEG 7 #define BODY_PART_RIGHT_LEG 8 #define BODY_PART_HEAD 9
So the case 0 is called when the player doesn't have armour, therefore we deal damage to the players health, according to which bodypart was hit.
So we create a switch, that switches through the value of "bodypart", which is created in the callback, and we defined.
Code:
switch(bodypart) // Under case 0. { case 3: SetPlayerHealth(playerid, health - 30); // Torso. case 4: SetPlayerHealth(playerid, health - 20); // Groin. case 5: SetPlayerHealth(playerid, health - 5); // Left Arm. case 6: SetPlayerHealth(playerid, health - 10); // Right Arm. case 7: SetPlayerHealth(playerid, health - 7); // Left Leg. case 8: SetPlayerHealth(playerid, health - 12); // Right Leg. case 9: SetPlayerHealth(playerid, health - 50); // Head. }
It will do accordingly with the other cases, such as 9, (BODY_PART_HEAD) it will set his health to his current health, minussed with 50.
Ofc. you can change the damages it will minus the health with.
And then you do the same under "default", just change SetPlayerHealth to SetPlayerArmour, and health - (value) to armour - (value).
And you're done!
By now you should hopefully have a fully working custom damage system for your servers, if you have any questions, feel free to ask about it below.