SA-MP Forums

Go Back   SA-MP Forums > SA-MP Scripting and Plugins > Scripting Help

Reply
 
Thread Tools Display Modes
Old 07/01/2020, 11:28 PM   #1
FunnyBear
Gangsta
 
Join Date: Mar 2013
Posts: 512
Reputation: 15
Default Looping through enum

Hi,

This stock is supposed to return the number of vehicles a player owns. Loops through the vehicle enums and counts how many times the vehicle's owner matches their name. However, it's not working and always returns 2000 even though they have 0.

Code:
stock countplayerVeh(playerid)
{
	new count = 0;
    for(new i = 0; i != sizeof(Vehicles); ++i)
	{
	    if(!strcmp(GetName(playerid), Vehicles[i][veh_owner], true))
	    {
			count++;
		}
	}
	return count;
}
If anyone could help me, I'd be greatly appreciated.
FunnyBear is offline   Reply With Quote
Old 08/01/2020, 03:51 AM   #2
grymtn
Huge Clucker
 
Join Date: Jun 2013
Posts: 266
Reputation: 26
Default Re: Looping through enum

can you try replacing your strcmp with this?
Code:
if(strcmp(GetName(playerid), Vehicles[i][veh_owner])==0)
if your GetName function removes underscore letter("_") it might be why it has no matches too, the reason it returns 2000 is your size of "Vehicles" is 2000 and you are telling it to count up if name doesn't match.
__________________
grymtn is offline   Reply With Quote
Old 08/01/2020, 07:03 AM   #3
Calisthenics
Gangsta
 
Join Date: May 2018
Posts: 948
Reputation: 167
Default Re: Looping through enum

`strcmp` function returns 0 (that the two string match) even if one of them is empty. This is the reason `count` is 2000.

The solution is to skip the empty strings, if you do not have any include with isnull defined, define it yourself:
pawn Code:
#if !defined isnull
    #define isnull(%0) ((%0[(%0[0])=='\1'])=='\0')
#endif
pawn Code:
if (!isnull(Vehicles[i][veh_owner]) && !strcmp(GetName(playerid), Vehicles[i][veh_owner], true))

Quote:
Originally Posted by grymtn View Post
can you try replacing your strcmp with this?
Code:
if(strcmp(GetName(playerid), Vehicles[i][veh_owner])==0)
value == 0 is the same as !value
__________________
Calisthenics is offline   Reply With Quote
Old 08/01/2020, 10:20 AM   #4
FunnyBear
Gangsta
 
Join Date: Mar 2013
Posts: 512
Reputation: 15
Default Re: Looping through enum

Quote:
Originally Posted by Calisthenics View Post
`strcmp` function returns 0 (that the two string match) even if one of them is empty. This is the reason `count` is 2000.

The solution is to skip the empty strings, if you do not have any include with isnull defined, define it yourself:
pawn Code:
#if !defined isnull
    #define isnull(%0) ((%0[(%0[0])=='\1'])=='\0')
#endif
pawn Code:
if (!isnull(Vehicles[i][veh_owner]) && !strcmp(GetName(playerid), Vehicles[i][veh_owner], true))



value == 0 is the same as !value
Doesn't quite seem to work either. Returns 1 even though I actually have 17 vehicles.

Quote:
Originally Posted by grymtn View Post
if your GetName function removes underscore letter("_") it might be why it has no matches too, the reason it returns 2000 is your size of "Vehicles" is 2000 and you are telling it to count up if name doesn't match.
It's not for a roleplay server and I don't use underscores in my name.
FunnyBear is offline   Reply With Quote
Old 08/01/2020, 12:08 PM   #5
Calisthenics
Gangsta
 
Join Date: May 2018
Posts: 948
Reputation: 167
Default Re: Looping through enum

Quote:
Originally Posted by FunnyBear View Post
Doesn't quite seem to work either. Returns 1 even though I actually have 17 vehicles.
Unless you set a default value as owner name for non-existed vehicles, it should have worked. Make sure the loading part is correct and debug it. Clear server_log.txt and run:
pawn Code:
printf("veh_owner: \"%s\", \
        GetName: \"%s\", \
        isnull: %d, \
        match: %d"
,
        Vehicles[i][veh_owner],
        GetName(playerid),
        isnull(Vehicles[i][veh_owner]),
        (!isnull(Vehicles[i][veh_owner]) && !strcmp(GetName(playerid), Vehicles[i][veh_owner], true)));

if (!isnull(Vehicles[i][veh_owner]) && !strcmp(GetName(playerid), Vehicles[i][veh_owner], true))
{
    count++;
}
__________________
Calisthenics is offline   Reply With Quote
Old 08/01/2020, 04:52 PM   #6
FunnyBear
Gangsta
 
Join Date: Mar 2013
Posts: 512
Reputation: 15
Default Re: Looping through enum

Quote:
Originally Posted by Calisthenics View Post
Unless you set a default value as owner name for non-existed vehicles, it should have worked. Make sure the loading part is correct and debug it. Clear server_log.txt and run:
pawn Code:
printf("veh_owner: \"%s\", \
        GetName: \"%s\", \
        isnull: %d, \
        match: %d"
,
        Vehicles[i][veh_owner],
        GetName(playerid),
        isnull(Vehicles[i][veh_owner]),
        (!isnull(Vehicles[i][veh_owner]) && !strcmp(GetName(playerid), Vehicles[i][veh_owner], true)));

if (!isnull(Vehicles[i][veh_owner]) && !strcmp(GetName(playerid), Vehicles[i][veh_owner], true))
{
    count++;
}
This is how I'm loading my vehicles:

Code:
forward OnPlayerLoadVehicles(playerid);
public OnPlayerLoadVehicles(playerid)
{
	new rows=cache_num_rows(), count = 0, id;
	if(rows > 0)
	{
	    for(new z = 0; z < rows; z++)
     	{
		    for(new i = 0; i < MAX_SPAWNED_VEHICLES; i++)
			{
				cache_get_value_name_int(z, "id", Vehicles[i][veh_id]);
				cache_get_value_name_int(z, "model", Vehicles[i][veh_model]);
				cache_get_value_name(z, "owner", Vehicles[i][veh_owner], .max_len = MAX_PLAYER_NAME);
				cache_get_value_name_int(z, "purchase_date", Vehicles[i][veh_purchase_date]);
				cache_get_value_name_int(z, "color1", Vehicles[i][veh_color1]);
				cache_get_value_name_int(z, "color2", Vehicles[i][veh_color2]);
				cache_get_value_name(z, "plate", Vehicles[i][veh_plate], .max_len = MAX_PLAYER_NAME);
				count++;
				Iter_Add(OwnedVehicle, i);
				break;
			}
		}
	}
	printf("Loaded %d vehicles from %s", count, Name[playerid]);
	return 1;
}
Also, this is how I create newly purchased vehicles:

Code:
forward OnSavedVehicleCreated(model, playerid);
public OnSavedVehicleCreated(model, playerid)
{
    new Float:x, Float:y, Float:z;
    GetPlayerPos(playerid, x, y, z);
    
	for(new i = 0; i < MAX_SPAWNED_VEHICLES; i++)
	{
		Vehicles[i][veh_id] = cache_insert_id();
		format(Vehicles[i][veh_owner], MAX_PLAYER_NAME, "%s", Name[playerid]);
		Vehicles[i][veh_model] = model;
		Vehicles[i][veh_color1]	= 1;
		Vehicles[i][veh_color2]	= 1;
		format(Vehicles[i][veh_plate], 16, DEFAULT_NUMBER_PLATE);
		
		PersonalVehicles[i] = AddStaticVehicle(Vehicles[i][veh_model], aDealerships[dealershipChoice[playerid]][dealership_spawn_x], aDealerships[dealershipChoice[playerid]][dealership_spawn_y], aDealerships[dealershipChoice[playerid]][dealership_spawn_z], aDealerships[dealershipChoice[playerid]][dealership_spawn_f], Vehicles[i][veh_color1], Vehicles[i][veh_color2]);
        SetVehicleNumberPlate(PersonalVehicles[i], Name[playerid]);
		dealershipChoice[playerid] = -1;
		break;
	}
	return 1;
}
FunnyBear is offline   Reply With Quote
Old 08/01/2020, 05:25 PM   #7
Calisthenics
Gangsta
 
Join Date: May 2018
Posts: 948
Reputation: 167
Default Re: Looping through enum

You are overwriting `Vehicles` array because no matter the `playerid`, you always set new values for index 0 to MAX_SPAWNED_VEHICLES-1. It is not per-vehicle, nor per-player vehicles anymore.

If you want to loop through the vehicles a player owns in other parts of the gamemode, the best way is multi-iterator. You can count the vehicles very easy with `Iter_Count` too.
__________________
Calisthenics is offline   Reply With Quote
Old 08/01/2020, 09:30 PM   #8
FunnyBear
Gangsta
 
Join Date: Mar 2013
Posts: 512
Reputation: 15
Default Re: Looping through enum

Quote:
Originally Posted by Calisthenics View Post
You are overwriting `Vehicles` array because no matter the `playerid`, you always set new values for index 0 to MAX_SPAWNED_VEHICLES-1. It is not per-vehicle, nor per-player vehicles anymore.

If you want to loop through the vehicles a player owns in other parts of the gamemode, the best way is multi-iterator. You can count the vehicles very easy with `Iter_Count` too.
Could you give me an example of how this would be used in the script that I used above? I've searched about iterators but not quite sure how I'd use it in this kind of vechicle system.
FunnyBear is offline   Reply With Quote
Old 09/01/2020, 07:40 AM   #9
Calisthenics
Gangsta
 
Join Date: May 2018
Posts: 948
Reputation: 167
Default Re: Looping through enum

Quote:
Originally Posted by FunnyBear View Post
Could you give me an example of how this would be used in the script that I used above? I've searched about iterators but not quite sure how I'd use it in this kind of vechicle system.
pawn Code:
// multi-iterator: a player can own many vehicles but a vehicle can be owned only by 1 player
new Iterator: OwnedVehicles<MAX_PLAYERS, MAX_VEHICLES>;

// when you create the vehicle for player
Iter_Add(OwnedVehicles<playerid>, vehicleid);

// total vehicles a player owns
new total_vehicles = Iter_Count(OwnedVehicles<playerid>);

// is this vehicle owned by this player check
if (Iter_Contains(OwnedVehicles<playerid>, vehicleid))
{
    // this vehicle is owned by this player
}
else
{
    // this vehicle is not owned by this player
}

// looping through all vehicles owned by a certain player
foreach(new i : OwnedVehicles<playerid>) {}

Reference: https://forum.sa-mp.com/showthread.php?t=571159

But you need to change the way you store in `Vehicles` array. Load the vehicle data (id, model, purchase date , color and plate) for the player and assign them to local variables. Then create the vehicle and grab the `vehicleid` to use it as an index and assign the true values:
pawn Code:
new vehicleid,
    v_id, model_id, purchase_date, color1, color2, plate[MAX_PLAYER_NAME];

for(new z = 0; z < rows; z++)
{
    cache_get_value_name_int(z, "id", v_id);
    cache_get_value_name_int(z, "model", model_id);
    cache_get_value_name_int(z, "purchase_date", purchase_date);
    cache_get_value_name_int(z, "color1", color1);
    cache_get_value_name_int(z, "color2", color2);
    cache_get_value_name(z, "plate", plate, .max_len = MAX_PLAYER_NAME);

    vehicleid = CreateVehicle(...);

    if (vehicleid != INVALID_VEHICLE_ID) // valid vehicle
    {
        Vehicles[vehicleid][veh_id] = id;
        Vehicles[vehicleid][veh_model] = model_id
        Vehicles[vehicleid][veh_purchase_date] = purchase_date;
        Vehicles[vehicleid][veh_color1] = color1;
        Vehicles[vehicleid][veh_color2] = color2;
        strcpy(Vehicles[vehicleid][veh_plate], plate, MAX_PLAYER_NAME);

        Iter_Add(OwnedVehicles<playerid>, vehicleid);
    }
}
`strcpy` can be found in YSI library. Do not forget to reset the variables when you destroy the vehicle (on player disconnect for example, depending on your system) and remove vehicle from the iterator for the player.
__________________
Calisthenics is offline   Reply With Quote
Old 10/01/2020, 10:39 PM   #10
FunnyBear
Gangsta
 
Join Date: Mar 2013
Posts: 512
Reputation: 15
Default Re: Looping through enum

Quote:
Originally Posted by Calisthenics View Post
pawn Code:
// multi-iterator: a player can own many vehicles but a vehicle can be owned only by 1 player
new Iterator: OwnedVehicles<MAX_PLAYERS, MAX_VEHICLES>;

// when you create the vehicle for player
Iter_Add(OwnedVehicles<playerid>, vehicleid);

// total vehicles a player owns
new total_vehicles = Iter_Count(OwnedVehicles<playerid>);

// is this vehicle owned by this player check
if (Iter_Contains(OwnedVehicles<playerid>, vehicleid))
{
    // this vehicle is owned by this player
}
else
{
    // this vehicle is not owned by this player
}

// looping through all vehicles owned by a certain player
foreach(new i : OwnedVehicles<playerid>) {}

Reference: https://forum.sa-mp.com/showthread.php?t=571159

But you need to change the way you store in `Vehicles` array. Load the vehicle data (id, model, purchase date , color and plate) for the player and assign them to local variables. Then create the vehicle and grab the `vehicleid` to use it as an index and assign the true values:
pawn Code:
new vehicleid,
    v_id, model_id, purchase_date, color1, color2, plate[MAX_PLAYER_NAME];

for(new z = 0; z < rows; z++)
{
    cache_get_value_name_int(z, "id", v_id);
    cache_get_value_name_int(z, "model", model_id);
    cache_get_value_name_int(z, "purchase_date", purchase_date);
    cache_get_value_name_int(z, "color1", color1);
    cache_get_value_name_int(z, "color2", color2);
    cache_get_value_name(z, "plate", plate, .max_len = MAX_PLAYER_NAME);

    vehicleid = CreateVehicle(...);

    if (vehicleid != INVALID_VEHICLE_ID) // valid vehicle
    {
        Vehicles[vehicleid][veh_id] = id;
        Vehicles[vehicleid][veh_model] = model_id
        Vehicles[vehicleid][veh_purchase_date] = purchase_date;
        Vehicles[vehicleid][veh_color1] = color1;
        Vehicles[vehicleid][veh_color2] = color2;
        strcpy(Vehicles[vehicleid][veh_plate], plate, MAX_PLAYER_NAME);

        Iter_Add(OwnedVehicles<playerid>, vehicleid);
    }
}
`strcpy` can be found in YSI library. Do not forget to reset the variables when you destroy the vehicle (on player disconnect for example, depending on your system) and remove vehicle from the iterator for the player.
Interesting, thanks for the help. However, I've got a question. When loading player vehicles (OnPlayerLoadVehicles), I do not intend to create the vehicle straight away, so how would I use Iter_Add without having a vehicleid to refer to?

What I am trying to do is load a player's vehicle information when they connect so they can spawn a vehicle that they already own at a dealership. Would I have to create two seperate iterators: one for player owned vehicles and one for player spawned vehicles?

Quick Update: Would this be right?

I changed the current OwnedVehicles to SpawnedVehicles and made another seperate iterator.

Code:
Iterator: OwnedVehicles<MAX_PLAYERS>;
Upon loading all vehicles, I saved the model id to OwnedVehicles using

Code:
Iter_Add(OwnedVehicles, modelid);
When a player wants to spawn a vehicle, I loop through all OwnedVehicles to return the modelid's saved and display it in a dialog. The player would then choose what vehicle they would like to spawn.

When the player spawns the vehicle, that is when I will add it to SpawnedVehicles using

Code:
Iter_Add(SpawnedVehicles<playerid>, vehicleid);

Last edited by FunnyBear; 10/01/2020 at 11:20 PM.
FunnyBear is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Looping through an enum zsoolt997 Scripting Help 4 17/01/2018 08:42 AM
Looping through enum with switch MotherDucker Scripting Help 8 12/09/2017 02:11 PM
Storing in a ENUM interfears with another enum justjamie Scripting Help 9 14/08/2016 08:20 AM
Pawn: enum type in enum sagosagi1 Scripting Help 6 19/05/2014 09:34 AM
Multiple instances of an enum inside an enum Enforcer501 Scripting Help 4 18/06/2013 03:31 PM


All times are GMT. The time now is 01:02 AM.


Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.