17.01.2014, 15:43
(
Последний раз редактировалось Lordzy; 25.04.2015 в 07:36.
)
Creating custom destroyable objects or objects which can get damaged
0.3z
0.3z
Introduction
Hello everyone,
SA-MP 0.3z R version have been released recently. It provides some cool features like better sync and detects if a player shoots another player, vehicle or even an object. Well as it provides object, it's simply easy to create a system like damaging objects. 0.3z provides the best feature in object destruction because it easily detects the sizes. Most of them detects a range when the player shoots at a position, but on 0.3z, it does the coverage of the object completely and is much efficient!
NOTE: I know that SA-MP 0.3z is still a RC version, however this tutorial is also a concept in regarding damaging objects. I will be updating this tutorial in case if any changes are being occurred on RC updates or R release. SA-MP 0.3z R1 has been released!
NOTE 2: The current tutorial will be explaining in regarding damaging or destroying objects which are either created by "CreateObject" or "CreatePlayerObject" only. About streamer, it will be updated later. I need to test streamer related objects before explaining it here so as to avoid explaining shits.
Streamer has been updated to 0.3z version! - So, streamer tutorial is also found at last.
Requirements
• SA-MP 0.3z server files <Includes, executable files and stuff>
• Streamer 0.3z version (In case if you want this to get performed on streamer's dynamic objects)
Concept
The concept in this tutorial is like shooting down the objects and it gets damaged. Destroying objects directly would not be fair enough because it would be like no good logic and also performance related issues would occur. If you want the object ids to get called while shooting them, it must not be a GTA SA default created object. You must implement it via SA-MP functions.
Tutorial
Let's start the tutorial. First of all, open pawno.exe and include a_samp. It's not actually needed in explaining how to include as this one is relating only to destroy or damage custom objects.
pawn Код:
#include <a_samp>
• Creating an HP variable for every objects.
Just like we declare HP for players, we're also declaring our own server-sided HP for objects.
pawn Код:
new ObjectHP[MAX_OBJECTS];
//We've declared a variable called 'ObjectHP' for 1000 objects. (MAX_OBJECTS = 1000)
pawn Код:
#define FILTERSCRIPT
#include <a_samp>
Creating objects is pretty simple, you can use the function called CreateObject. Or, more easier by using SA-MP map editor or any other map editors. I suggest SA-MP map editor as it's more convenient and faster. Here, I'm considering that I've created 5 objects on Los Santos Airport.
NOTE: Always prefer using objects which don't get destroyed by default. There's many objects which gets destroyed as it's set default. Either get them to be destroyed when player shoots them at first itself.
Before implementing those CreateObject codes under OnFilterScriptInit, it's necessary to reset every object's HP. And then, after creating, set them back. On the quicker way, I'm letting every "CreateObject" objects to face damages when a player shoots it.
pawn Код:
#define FILTERSCRIPT
#include <a_samp>
new ObjectHP[MAX_OBJECTS];
public OnFilterScriptInit()
{
//Let's loop through MAX_OBJECTS and reset their HP.
for(new i; i< MAX_OBJECTS; i++) ObjectHP[i] = 0;
/*What the above code does is, it loops till 1000 as MAX_OBJECT's value is 1000.
Basically it does:
ObjectHP[0] = 0;
ObjectHP[1] = 0;
ObjectHP[2] = 0;
...
ObjectHP[999] = 0; */
CreateObject(18848, 1450.59, -2446.57, 12.50, 0.00, 0.00, 0.00);
CreateObject(18848, 1442.11, -2444.87, 12.55, 0.00, 0.00, 0.00);
CreateObject(18848, 1461.18, -2446.89, 12.54, 0.00, 0.00, 0.00);
CreateObject(18848, 1457.31, -2430.67, 12.54, 0.00, 0.00, 0.00);
CreateObject(18848, 1449.48, -2430.51, 12.54, 0.00, 0.00, 0.00);
//I've created 5 objects which are S-A-M missile launchers (Unbreakable)
//Now, let me set their HP.
for(new i; i< MAX_OBJECTS; i++) { //Looping once again
if(!IsValidObject(i)) continue; /*If it's not a valid object, it skips that loop and jumps to next.
! being used before this function means if it returns a false statement.
*/
ObjectHP[i] = 100; //I'm setting every valid object's HP to 100 as this is a quicker way.
}
return 1;
}
So, we've done with creating objects and setting their HP rates.
• Damaging the objects
Since 0.3z, shooting an object always calls "OnPlayerWeaponShot". And since 0.3z R2, it supports an easier method in player-objects also getting called under the same callback. On this quick method, I'm just explaining about normal global objects.
OnPlayerWeaponShot gets called accordingly :
pawn Код:
public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
return 1;
weaponid - The weapon's ID in which player used for shooting.
hittype - The type of hit occurred.
There's 4 types of hit.
pawn Код:
#define BULLET_HIT_TYPE_NONE 0
#define BULLET_HIT_TYPE_PLAYER 1
#define BULLET_HIT_TYPE_VEHICLE 2
#define BULLET_HIT_TYPE_OBJECT 3
#define BULLET_HIT_TYPE_PLAYER_OBJECT 4
BULLET_HIT_TYPE_NONE gets called on this callback if player shoots nothing.
BULLET_HIT_TYPE_PLAYER gets called on this callback in case if player shoots another player.
BULLET_HIT_TYPE_VEHICLE gets called in case if player shoots a vehicle.
BULLET_HIT_TYPE_OBJECT gets called in case if player shoots an object and finally
BULLET_HIT_TYPE_PLAYER_OBJECT gets called in case if player shoots a player-object.
hitid
hitid is the ID in relating to the hittype. In case if hittype goes TYPE_PLAYER, it returns the player ID as hitid. Or if it's a vehicle, it returns the vehicle's ID as hitid. Same facts on object and player-objects; it will return the object ID or player object ID in case if the hittype is either TYPE_OBJECT or TYPE_PLAYER_OBJECT.
fX, fY, fZ
These are the offsets within the object ID, vehicle ID or the player's skin. Which means the position where the bullet gets hit. Not actually the POS, but the offset position of an object, player-object, vehicle or a player's skin.
We're gonna use this callback to reduce the HP of object and destroy it.
pawn Код:
public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
//We must know if the bullet hit type is related to object, so use an if statement and verify if it's hitting an object.
if(hittype == BULLET_HIT_TYPE_OBJECT) { //In case if player hits an object
if(IsValidObject(hitid)) { /*The callback may get called only if hitting valid objects, but still to verify much,
we can know if it's a valid object or not using 'IsValidObject'. Here, in case if it's a valid object, then:
We're gonna reduce it's HP. Reducing a custom value wouldn't seem to be good, so let's randomize the value.
Reducing also depends on the firerates, so if player got good firerates, reducing would go fastly.
*/
ObjectHP[hitid] -= random(10) + 1;
/*
Here, we're reducing the ObjectHP of the object ID which is called on this callback. It reduces from a
minimum of 1. random(max) means it will return any numbers starting from random to the max specified value.
I've added additional +1 to it because in case if 0 is the result, it sums up and doesn't result in 0.
Now, in case if object's HP goes at 0 or lower than that, we must destroy it. */
if(ObjectHP[hitid] <= 0) { //If objectHP of that object is either 0 or lower,:
DestroyObject(hitid);
}
}
}
return 1;
}
pawn Код:
public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
//We must know if the bullet hit type is related to object, so use an if statement and verify if it's hitting an object.
if(hittype == BULLET_HIT_TYPE_OBJECT) { //In case if player hits an object
if(IsValidObject(hitid)) { /*The callback may get called only if hitting valid objects, but still to verify much,
we can know if it's a valid object or not using 'IsValidObject'. Here, in case if it's a valid object, then:
We're gonna reduce it's HP. Reducing a custom value wouldn't seem to be good, so let's randomize the value.
Reducing also depends on the firerates, so if player got good firerates, reducing would go fastly.
*/
ObjectHP[hitid] -= random(10) + 1;
/*
Here, we're reducing the ObjectHP of the object ID which is called on this callback. It reduces from a
minimum of 1. random(max) means it will return any numbers starting from random to the max specified value.
I've added additional +1 to it because in case if 0 is the result, it sums up and doesn't result in 0.
Now, in case if object's HP goes at 0 or lower than that, we must destroy it. */
if(ObjectHP[hitid] >= 0) { //If object's HP is either 0 or 1.
new str[128]; //We will need to declare a string to display the message.
//I'll be using GameTextForPlayer because if we're using SendClientMessage, it could always spam.
format(str, sizeof(str), "~G~OBJECT DAMAGED!~N~~Y~OBJECT ID ~W~: ~R~ %d~N~~Y~HP LEFT ~W~: ~R~ %d", hitid, ObjectHP[hitid]);
//I've formatted the string which includes the information of object id and it's HP left.
GameTextForPlayer(playerid, str, 1800, 3);
//I'm displaying the info to player. I'm using style '3' because it's the better one in case if this callback is being called at many times.
}
if(ObjectHP[hitid] <= 0) { //If objectHP of that object is either 0 or lower,:
DestroyObject(hitid);
}
}
}
return 1;
}
pawn Код:
#define FILTERSCRIPT
#include <a_samp>
new ObjectHP[MAX_OBJECTS];
public OnFilterScriptInit()
{
//Let's loop through MAX_OBJECTS and reset their HP.
for(new i; i< MAX_OBJECTS; i++) ObjectHP[i] = 0;
/*What the above code does is, it loops till 1000 as MAX_OBJECT's value is 1000.
Basically it does:
ObjectHP[0] = 0;
ObjectHP[1] = 0;
ObjectHP[2] = 0;
...
ObjectHP[999] = 0; */
CreateObject(18848, 1450.59, -2446.57, 12.50, 0.00, 0.00, 0.00);
CreateObject(18848, 1442.11, -2444.87, 12.55, 0.00, 0.00, 0.00);
CreateObject(18848, 1461.18, -2446.89, 12.54, 0.00, 0.00, 0.00);
CreateObject(18848, 1457.31, -2430.67, 12.54, 0.00, 0.00, 0.00);
CreateObject(18848, 1449.48, -2430.51, 12.54, 0.00, 0.00, 0.00);
//I've created 5 objects which are S-A-M missile launchers (Unbreakable)
//Now, let me set their HP.
for(new i; i< MAX_OBJECTS; i++) { //Looping once again
if(!IsValidObject(i)) continue; /*If it's not a valid object, it skips that loop and jumps to next.
! being used before this function means if it returns a false statement.
*/
ObjectHP[i] = 100; //I'm setting every valid object's HP to 100 as this is a quicker way.
}
return 1;
}
public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
//We must know if the bullet hit type is related to object, so use an if statement and verify if it's hitting an object.
if(hittype == BULLET_HIT_TYPE_OBJECT) { //In case if player hits an object
if(IsValidObject(hitid)) { /*The callback may get called only if hitting valid objects, but still to verify much,
we can know if it's a valid object or not using 'IsValidObject'. Here, in case if it's a valid object, then:
We're gonna reduce it's HP. Reducing a custom value wouldn't seem to be good, so let's randomize the value.
Reducing also depends on the firerates, so if player got good firerates, reducing would go fastly.
*/
ObjectHP[hitid] -= random(10) + 1;
/*
Here, we're reducing the ObjectHP of the object ID which is called on this callback. It reduces from a
minimum of 1. random(max) means it will return any numbers starting from random to the max specified value.
I've added additional +1 to it because in case if 0 is the result, it sums up and doesn't result in 0.
Now, in case if object's HP goes at 0 or lower than that, we must destroy it. */
if(ObjectHP[hitid] >= 0) { //If object's HP is either 0 or 1.
new str[128]; //We will need to declare a string to display the message.
//I'll be using GameTextForPlayer because if we're using SendClientMessage, it could always spam.
format(str, sizeof(str), "~G~OBJECT DAMAGED!~N~~Y~OBJECT ID ~W~: ~R~ %d~N~~Y~HP LEFT ~W~: ~R~ %d", hitid, ObjectHP[hitid]);
//I've formatted the string which includes the information of object id and it's HP left.
GameTextForPlayer(playerid, str, 1800, 3);
//I'm displaying the info to player. I'm using style '3' because it's the better one in case if this callback is being called at many times.
}
if(ObjectHP[hitid] <= 0) { //If objectHP of that object is either 0 or lower,:
DestroyObject(hitid);
}
}
}
return 1;
}
• Grouped method
In grouped method, let's group objects which needs to get damaged. So it will get damaged only if they're assigned to receive damages. Just like mentioned on the Quicker method, you must first include and declare the ObjectHP variable.
pawn Код:
#define FILTERSCRIPT
//This example is also a FS related example.
#include <a_samp>
new ObjectHP[MAX_OBJECTS];
pawn Код:
new bool:ObjectDamage[MAX_OBJECTS]; //Let's create this as a boolean as there's only two statements to be declared.
//I'll be using it in a way as if the variable is true, it means the object is assigned to face damage, else not.
pawn Код:
#define FILTERSCRIPT
#include <a_samp>
new ObjectHP[MAX_OBJECTS],
bool:ObjectDamage[MAX_OBJECTS];
public OnFilterScriptInit()
{
//Let's loop through MAX_OBJECTS and reset their HP.
for(new i; i< MAX_OBJECTS; i++) {
ObjectHP[i] = 0;
/*What the above code does is, it loops till 1000 as MAX_OBJECT's value is 1000.
Basically it does:
ObjectHP[0] = 0;
ObjectHP[1] = 0;
ObjectHP[2] = 0;
...
ObjectHP[999] = 0; */
//On the grouped method, I'm also resetting the assigned objects.
ObjectDamage[i] = false;
/* This performs in a loop in such a way that :
ObjectDamage[0] = false;
ObjectDamage[1] = false;
ObjectDamage[2] = false;
...
ObjectDamage[3] = false; */
}
/*
Now, these are the objects which requires to be assigned to face damage.
I'll retrieve the object IDs and assign those IDs to face damage.
I'm declaring an array to retrieve the object IDs.*/
new Object_ID[5]; //There's 5 objects, so size of 5.
Object_ID[0] = CreateObject(18848, 1450.59, -2446.57, 12.50, 0.00, 0.00, 0.00);
Object_ID[1] = CreateObject(18848, 1442.11, -2444.87, 12.55, 0.00, 0.00, 0.00);
Object_ID[2] = CreateObject(18848, 1461.18, -2446.89, 12.54, 0.00, 0.00, 0.00);
Object_ID[3] = CreateObject(18848, 1457.31, -2430.67, 12.54, 0.00, 0.00, 0.00);
Object_ID[4] = CreateObject(18848, 1449.48, -2430.51, 12.54, 0.00, 0.00, 0.00);
//I've created 5 objects which are S-A-M missile launchers (Unbreakable) and also grouped.
//Now, let me set their HP and assign them.
//This time, we'll set the HP only to the assigned ones.
//First of all, let me assign the ones.
for(new i; i< 5; i++) {
ObjectDamage[Object_ID[i]] = true; //The ObjectDamage boolean sets true to the object ids which have been retrieved.
/*Under loop, it does more faster and does in a way like this :
ObjectDamage[Object_ID[0]] = true;
ObjectDamage[Object_ID[1]] = true;
...
ObjectDamage[Object_ID[4]] = true; */
}
//Now just like I did before on the earlier method, I'm setting object's HP.
//But this time,I'm setting the HP of valid and assigned objects only.
for(new i; i< MAX_OBJECTS; i++) {
if(!IsValidObject(i)) continue; //Skips if it's not a valid object.
if(ObjectDamage[i] == false) continue; //If they're not assigned or not set to true, it will skip.
ObjectHP[i] = 100; //You can also change the HP rate according to the model ID of objects.
}
return 1;
}
pawn Код:
public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
//We must know if the bullet hit type is related to object, so use an if statement and verify if it's hitting an object.
if(hittype == BULLET_HIT_TYPE_OBJECT) { //In case if player hits an object
if(IsValidObject(hitid)) { /*The callback may get called only if hitting valid objects, but still to verify much,
we can know if it's a valid object or not using 'IsValidObject'. Here, in case if it's a valid object, then:
We're gonna reduce it's HP. Reducing a custom value wouldn't seem to be good, so let's randomize the value.
Reducing also depends on the firerates, so if player got good firerates, reducing would go fastly.
*/
//This time, we're also looking if the object ID is assigned to true, else it won't get damaged!
if(ObjectDamage[hitid] == true) { //In case if it's assigned or true, it will damage.
ObjectHP[hitid] -= random(10) + 1;
/*
Here, we're reducing the ObjectHP of the object ID which is called on this callback. It reduces from a
minimum of 1. random(max) means it will return any numbers starting from random to the max specified value.
I've added additional +1 to it because in case if 0 is the result, it sums up and doesn't result in 0.
Now, in case if object's HP goes at 0 or lower than that, we must destroy it. */
if(ObjectHP[hitid] >= 0) { //If object's HP is either 0 or 1.
new str[128]; //We will need to declare a string to display the message.
//I'll be using GameTextForPlayer because if we're using SendClientMessage, it could always spam.
format(str, sizeof(str), "~G~OBJECT DAMAGED!~N~~Y~OBJECT ID ~W~: ~R~ %d~N~~Y~HP LEFT ~W~: ~R~ %d", hitid, ObjectHP[hitid]);
//I've formatted the string which includes the information of object id and it's HP left.
GameTextForPlayer(playerid, str, 1800, 3);
//I'm displaying the info to player. I'm using style '3' because it's the better one in case if this callback is being called at many times.
}
if(ObjectHP[hitid] <= 0) { //If objectHP of that object is either 0 or lower,:
DestroyObject(hitid);
}
}
}
}
return 1;
}
pawn Код:
#define FILTERSCRIPT
#include <a_samp>
new ObjectHP[MAX_OBJECTS],
bool:ObjectDamage[MAX_OBJECTS];
public OnFilterScriptInit()
{
//Let's loop through MAX_OBJECTS and reset their HP.
for(new i; i< MAX_OBJECTS; i++) {
ObjectHP[i] = 0;
/*What the above code does is, it loops till 1000 as MAX_OBJECT's value is 1000.
Basically it does:
ObjectHP[0] = 0;
ObjectHP[1] = 0;
ObjectHP[2] = 0;
...
ObjectHP[999] = 0; */
//On the grouped method, I'm also resetting the assigned objects.
ObjectDamage[i] = false;
/* This performs in a loop in such a way that :
ObjectDamage[0] = false;
ObjectDamage[1] = false;
ObjectDamage[2] = false;
...
ObjectDamage[3] = false; */
}
/*
Now, these are the objects which requires to be assigned to face damage.
I'll retrieve the object IDs and assign those IDs to face damage.
I'm declaring an array to retrieve the object IDs.*/
new Object_ID[5]; //There's 5 objects, so size of 5.
Object_ID[0] = CreateObject(18848, 1450.59, -2446.57, 12.50, 0.00, 0.00, 0.00);
Object_ID[1] = CreateObject(18848, 1442.11, -2444.87, 12.55, 0.00, 0.00, 0.00);
Object_ID[2] = CreateObject(18848, 1461.18, -2446.89, 12.54, 0.00, 0.00, 0.00);
Object_ID[3] = CreateObject(18848, 1457.31, -2430.67, 12.54, 0.00, 0.00, 0.00);
Object_ID[4] = CreateObject(18848, 1449.48, -2430.51, 12.54, 0.00, 0.00, 0.00);
CreateObject(18848, 1486.46, -2439.21, 12.50, 0.00, 0.00, 0.00); //A normal object which isn't assigned to face damage.
//I've created 5 objects which are S-A-M missile launchers (Unbreakable) and also grouped.
//Now, let me set their HP and assign them.
//This time, we'll set the HP only to the assigned ones.
//First of all, let me assign the ones.
for(new i; i< 5; i++) {
ObjectDamage[Object_ID[i]] = true; //The ObjectDamage boolean sets true to the object ids which have been retrieved.
/*Under loop, it does more faster and does in a way like this :
ObjectDamage[Object_ID[0]] = true;
ObjectDamage[Object_ID[1]] = true;
...
ObjectDamage[Object_ID[4]] = true; */
}
//Now just like I did before on the earlier method, I'm setting object's HP.
//But this time,I'm setting the HP of valid and assigned objects only.
for(new i; i< MAX_OBJECTS; i++) {
if(!IsValidObject(i)) continue; //Skips if it's not a valid object.
if(ObjectDamage[i] == false) continue; //If they're not assigned or not set to true, it will skip.
ObjectHP[i] = 100; //You can also change the HP rate according to the model ID of objects.
}
return 1;
}
public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
//We must know if the bullet hit type is related to object, so use an if statement and verify if it's hitting an object.
if(hittype == BULLET_HIT_TYPE_OBJECT) { //In case if player hits an object
if(IsValidObject(hitid)) { /*The callback may get called only if hitting valid objects, but still to verify much,
we can know if it's a valid object or not using 'IsValidObject'. Here, in case if it's a valid object, then:
We're gonna reduce it's HP. Reducing a custom value wouldn't seem to be good, so let's randomize the value.
Reducing also depends on the firerates, so if player got good firerates, reducing would go fastly.
*/
//This time, we're also looking if the object ID is assigned to true, else it won't get damaged!
if(ObjectDamage[hitid] == true) { //In case if it's assigned or true, it will damage.
ObjectHP[hitid] -= random(10) + 1;
/*
Here, we're reducing the ObjectHP of the object ID which is called on this callback. It reduces from a
minimum of 1. random(max) means it will return any numbers starting from random to the max specified value.
I've added additional +1 to it because in case if 0 is the result, it sums up and doesn't result in 0.
Now, in case if object's HP goes at 0 or lower than that, we must destroy it. */
if(ObjectHP[hitid] >= 0) { //If object's HP is either 0 or 1.
new str[128]; //We will need to declare a string to display the message.
//I'll be using GameTextForPlayer because if we're using SendClientMessage, it could always spam.
format(str, sizeof(str), "~G~OBJECT DAMAGED!~N~~Y~OBJECT ID ~W~: ~R~ %d~N~~Y~HP LEFT ~W~: ~R~ %d", hitid, ObjectHP[hitid]);
//I've formatted the string which includes the information of object id and it's HP left.
GameTextForPlayer(playerid, str, 1800, 3);
//I'm displaying the info to player. I'm using style '3' because it's the better one in case if this callback is being called at many times.
}
if(ObjectHP[hitid] <= 0) { //If objectHP of that object is either 0 or lower,:
DestroyObject(hitid);
}
}
}
}
return 1;
}
public OnPlayerCommandText(playerid, cmdtext[])
{
if(!strcmp(cmdtext, "/ls")) return SetPlayerPos(playerid,1450.59, -2446.57, 12.50+5.0);
return 0;
}
• Per-Player Objects
NOTE: You should've read the above parts to know more about player object related damaging more. Because I've explained more on those parts only!
Per-Player Objects are the ones which are visible only to the player in which it's specified. We're using the function CreatePlayerObject to create a player object. On the WIKI page it's being created under OnPlayerConnect but I suggest to use OnPlayerSpawn to create player objects and OnPlayerConnect isn't that efficient for player objects getting created.
On this, create the variables like mentioned above, either grouped or non-grouped ones. Here, I'm doing grouped ones.
pawn Код:
#define FILTERSCRIPT
#include <a_samp>
new PlayerObjectHP[MAX_PLAYERS][MAX_OBJECTS];
//It's a player object, so it needs an extra slot for storing player ID too. And hence, it's a 2D array.
new bool:PlayerObjectDamage[MAX_PLAYERS][MAX_OBJECTS];
//Just like I declared PlayerObjectHP, I'm declaring the group assigning variable too.
pawn Код:
#define FILTERSCRIPT
#include <a_samp>
new PlayerObjectHP[MAX_PLAYERS][MAX_OBJECTS];
//It's a player object, so it needs an extra slot for storing player ID too. And hence, it's a 2D array.
new bool:PlayerObjectDamage[MAX_PLAYERS][MAX_OBJECTS];
//Just like I declared PlayerObjectHP, I'm declaring the group assigning variable too.
new p_OBJECTS[MAX_PLAYERS][5]; //Another 2D array to retrieve player's OBJECT ID. This is also used to destroy the object in case if it's alive when player disconnects.
new p_NODAMAGE[MAX_PLAYERS]; //This variable is to store the object which don't face damages. Why I'm declaring this is because I need to destroy this when player leaves.
public OnPlayerSpawn(playerid)
{
p_OBJECTS[playerid][0] = CreatePlayerObject(playerid, 18848, 1450.59, -2446.57, 12.50, 0.00, 0.00, 0.00);
p_OBJECTS[playerid][1] = CreatePlayerObject(playerid, 18848, 1442.11, -2444.87, 12.55, 0.00, 0.00, 0.00);
p_OBJECTS[playerid][2] = CreatePlayerObject(playerid, 18848, 1461.18, -2446.89, 12.54, 0.00, 0.00, 0.00);
p_OBJECTS[playerid][3] = CreatePlayerObject(playerid, 18848, 1457.31, -2430.67, 12.54, 0.00, 0.00, 0.00);
p_OBJECTS[playerid][4] = CreatePlayerObject(playerid, 18848, 1449.48, -2430.51, 12.54, 0.00, 0.00, 0.00);
p_NODAMAGE[playerid] = CreatePlayerObject(playerid, 18848, 1486.46, -2439.21, 12.50, 0.00, 0.00, 0.00);
//Now I've retrieved these created object's ID on these variables.
//The ones stored on p_OBJECTS are to be assigned to get damaged and the p_NODAMAGE won't get any damages.
//Just like I've done to global ones, here also I'm doing a loop and assigning these player objects to face damage.
for(new i; i< 5; i++) {
PlayerObjectDamage[playerid][p_OBJECTS[playerid][i]] = true; //It sets the assigned player object IDs to true so that it'll receive damages.
}
//Another loop in setting the player object's HP.
for(new i; i< MAX_OBJECTS; i++) {
if(!IsValidPlayerObject(playerid, i)) continue;
/* IsValidPlayerObject checks if it's a valid player-object for the specified player ID. I'm skipping the -
loop value in case if it's returning false.
*/
PlayerObjectHP[playerid][i] = 100; //Sets the player-object's HP to 100.
}
return 1;
}
pawn Код:
public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
if(hittype == BULLET_HIT_TYPE_PLAYER_OBJECT) { //In case if player is shooting at a player object.
if(IsValidPlayerObject(playerid, hitid)) { //If the called player-object is valid for the player, then:
if(PlayerObjectDamage[playerid][hitid] == true) { //If the player's object ID is assigned to take damage, then:
//Now just like I've done to global objects, I'm once again reducing these object's HP randomly.
PlayerObjectHP[playerid][hitid] -= random(10) + 1;
if(PlayerObjectHP[playerid][hitid] >= 0) { //If the Player's Object's HP is either 0 or more;
new str[128]; //This concept isn't actually needed, however it's to show info of the damage.
//And yes, we're declaring a string variable to format it with the specifiers.
format(str, sizeof(str), "~G~DAMAGE DONE!~N~~Y~PLAYER OBJECT ID ~W~: ~R~ %d~N~~Y~HP LEFT ~W~: ~R~ %d", hitid, PlayerObjectHP[playerid][hitid]);
GameTextForPlayer(playerid, str, 1800, 3);
}
if(PlayerObjectHP[playerid][hitid] <= 0) { //If the HP goes to 0 or goes lesser than 0;
DestroyPlayerObject(playerid, hitid); //We're destroying the PLAYER's OBJECT then, not a global one.
}
}
}
}
return 1;
}
We aren't yet done with player objects. These have to be destroyed under OnPlayerDisconnect if player hasn't destroyed them yet!
pawn Код:
public OnPlayerDisconnect(playerid, reason)
{
//We'll loop through every objects at first.
for(new i; i< MAX_OBJECTS; i++) {
//Then, we'll see if it's a player object or not.
if(!IsValidPlayerObject(playerid, i)) continue; //If it's not a valid player object, it will skip that loop value.
DestroyPlayerObject(playerid, i); //In case if there's any player objects, it will be destroying them.
}
return 1;
}
pawn Код:
#define FILTERSCRIPT
#include <a_samp>
new PlayerObjectHP[MAX_PLAYERS][MAX_OBJECTS];
//It's a player object, so it needs an extra slot for storing player ID too. And hence, it's a 2D array.
new bool:PlayerObjectDamage[MAX_PLAYERS][MAX_OBJECTS];
//Just like I declared PlayerObjectHP, I'm declaring the group assigning variable too.
new p_OBJECTS[MAX_PLAYERS][5]; //Another 2D array to retrieve player's OBJECT ID. This is also used to destroy the object in case if it's alive when player disconnects.
new p_NODAMAGE[MAX_PLAYERS]; //This variable is to store the object which don't face damages. Why I'm declaring this is because I need to destroy this when player leaves.
public OnPlayerSpawn(playerid)
{
p_OBJECTS[playerid][0] = CreatePlayerObject(playerid, 18848, 1450.59, -2446.57, 12.50, 0.00, 0.00, 0.00);
p_OBJECTS[playerid][1] = CreatePlayerObject(playerid, 18848, 1442.11, -2444.87, 12.55, 0.00, 0.00, 0.00);
p_OBJECTS[playerid][2] = CreatePlayerObject(playerid, 18848, 1461.18, -2446.89, 12.54, 0.00, 0.00, 0.00);
p_OBJECTS[playerid][3] = CreatePlayerObject(playerid, 18848, 1457.31, -2430.67, 12.54, 0.00, 0.00, 0.00);
p_OBJECTS[playerid][4] = CreatePlayerObject(playerid, 18848, 1449.48, -2430.51, 12.54, 0.00, 0.00, 0.00);
p_NODAMAGE[playerid] = CreatePlayerObject(playerid, 18848, 1486.46, -2439.21, 12.50, 0.00, 0.00, 0.00);
//Now I've retrieved these created object's ID on these variables.
//The ones stored on p_OBJECTS are to be assigned to get damaged and the p_NODAMAGE won't get any damages.
//Just like I've done to global ones, here also I'm doing a loop and assigning these player objects to face damage.
for(new i; i< 5; i++) {
PlayerObjectDamage[playerid][p_OBJECTS[playerid][i]] = true; //It sets the assigned player object IDs to true so that it'll receive damages.
}
//Another loop in setting the player object's HP.
for(new i; i< MAX_OBJECTS; i++) {
if(!IsValidPlayerObject(playerid, i)) continue;
/* IsValidPlayerObject checks if it's a valid player-object for the specified player ID. I'm skipping the -
loop value in case if it's returning false.
*/
PlayerObjectHP[playerid][i] = 100; //Sets the player-object's HP to 100.
}
return 1;
}
public OnPlayerWeaponShot(playerid, weaponid, hittype, hitid, Float:fX, Float:fY, Float:fZ)
{
if(hittype == BULLET_HIT_TYPE_PLAYER_OBJECT) { //In case if player is shooting at a player object.
if(IsValidPlayerObject(playerid, hitid)) { //If the called player-object is valid for the player, then:
if(PlayerObjectDamage[playerid][hitid] == true) { //If the player's object ID is assigned to take damage, then:
//Now just like I've done to global objects, I'm once again reducing these object's HP randomly.
PlayerObjectHP[playerid][hitid] -= random(10) + 1;
if(PlayerObjectHP[playerid][hitid] >= 0) { //If the Player's Object's HP is either 0 or more;
new str[128]; //This concept isn't actually needed, however it's to show info of the damage.
//And yes, we're declaring a string variable to format it with the specifiers.
format(str, sizeof(str), "~G~DAMAGE DONE!~N~~Y~PLAYER OBJECT ID ~W~: ~R~ %d~N~~Y~HP LEFT ~W~: ~R~ %d", hitid, PlayerObjectHP[playerid][hitid]);
GameTextForPlayer(playerid, str, 1800, 3);
}
if(PlayerObjectHP[playerid][hitid] <= 0) { //If the HP goes to 0 or goes lesser than 0;
DestroyPlayerObject(playerid, hitid); //We're destroying the PLAYER's OBJECT then, not a global one.
}
}
}
}
return 1;
}
public OnPlayerDisconnect(playerid, reason)
{
//We'll loop through every objects at first.
for(new i; i< MAX_OBJECTS; i++) {
//Then, we'll see if it's a player object or not.
if(!IsValidPlayerObject(playerid, i)) continue; //If it's not a valid player object, it will skip that loop value.
DestroyPlayerObject(playerid, i); //In case if there's any player objects, it will be destroying them.
}
return 1;
}
This is pretty easy, you could just change "CreateObject" or "CreatePlayerObject" to "CreateDynamicObject". And the "OnPlayerWeaponShot" can be changed to "OnPlayerShootDynamicObject". But here's the tutorial for it:
pawn Код:
public OnPlayerShootDynamicObject(playerid, weaponid, objectid, Float:x, Float:y, Float:z)
{
//objectid returns the object which has received shot!
if(IsValidDynamicObject(objectid)) { //Dynamic objects can be known by "IsValidDynamicObject", per-player objects too include these.
if(PlayerObjectDamage[playerid][objectid] == true) { //If the player's object ID is assigned to take damage, then:
//Now just like I've done to global objects, I'm once again reducing these object's HP randomly.
PlayerObjectHP[playerid][objectid] -= random(10) + 1;
if(PlayerObjectHP[playerid][objectid] >= 0) { //If the Player's Object's HP is either 0 or more;
new str[128]; //This concept isn't actually needed, however it's to show info of the damage.
//And yes, we're declaring a string variable to format it with the specifiers.
format(str, sizeof(str), "~G~DAMAGE DONE!~N~~Y~PLAYER OBJECT ID ~W~: ~R~ %d~N~~Y~HP LEFT ~W~: ~R~ %d", hitid, PlayerObjectHP[playerid][hitid]);
GameTextForPlayer(playerid, str, 1800, 3);
}
if(PlayerObjectHP[playerid][objectid] <= 0) { //If the HP goes to 0 or goes lesser than 0;
DestroyDynamicObject(objectid); //We're destroying the PLAYER's OBJECT then, not a global one.
}
}
}
}
return 1;
}
Example Script
Here's an example filterscript of destroying object. It's not a release, I've just used it today to test how things work. Feel free to edit it though.
http://pastebin.com/UE7zBUKZ - Thanks to Deadspirit for the Pirate island map.
◘ Video of the above filterscript.
[ame]http://www.youtube.com/watch?v=Vu1hL24dFWc[/ame]
Additional Notes
• OnPlayerWeaponShot may not get called if you're using weapons which doesn't have the normal cross hair aiming.
• In case if you're using a breakable object, I suggest you to use the "OnPlayerWeaponShot" callback and either destroy it when any player shoots at it. If you want to add it again, better delay that and add or else player could just spam shooting them out and the performance would get bad.
• OnPlayerWeaponShot won't get called on objects which are just textures but not solid!
• Use of iterators to hold the objects could improve the performance.