Detect Passenger & Unknown command
#1

Hi.
Before you read text below i'd like to ask you NOT to post working code without explanation. Better give me Wiki/Tutorial/Other link so i could learn something. Thanks.

First things first.
I'm trying to implement vehicle teleportation with all passengers.
I do have some thoughts how i can do it. I can GetPlayerState of every online player then check if its equals "passenger" and then check if vehicle id equals id that being teleported and finally PutPlayerInVehicle. But im affraid it could cause lags and make everything unstable (cause of getting state of EVERY player). So, is there any other way to do it? Maybe even simplier?

And now weird thing.
Here's my code:
pawn Код:
if (strcmp("/tower", cmdtext, true, 10) == 0)
    {
        if(IsPlayerInAnyVehicle(playerid))
        {
            new vehicleid = GetPlayerVehicleID(playerid);
            new pState = GetPlayerState(playerid);
            if(pState == PLAYER_STATE_DRIVER)
            {
                SetVehiclePos(vehicleid, 1544.2318, -1354.3735, 329.4725);
                SetVehicleZAngle(vehicleid, 100);
                PutPlayerInVehicle(playerid, vehicleid, 0);
            }

        }
        else
        {
            SetPlayerPos(playerid, 1541.3450,-1366.5369,329.7969);
            SetPlayerFacingAngle(playerid, 360);
            return 1;
        }
    }
It works perfectly, but every time i try to teleport while in vehicle server says "unknown command" and still teleports me correctly. Whats wrong? D:

Beforehand, thanks
Reply
#2

i don't see how this will teleport all the passengers ?

for the "UNKOWN" msg u need to "return" something at the end before the last closing bracket of the "if" stamnet for the command
Reply
#3

You're going to need a loop anyway. I think it's the easiest to use IsPlayerInVehicle (not AnyVehicle).
Reply
#4

Quote:
Originally Posted by park4bmx
Посмотреть сообщение
i don't see how this will teleport all the passengers ?

for the "UNKNOWN" msg u need to "return" something at the end before the last closing bracket of the "if" statement for the command
You're right, it will teleport only one passenger. As Vince said i'll require loops.
Second issue fixed by the way, thanks

Quote:
Originally Posted by Vince
Посмотреть сообщение
You're going to need a loop anyway. I think it's the easiest to use IsPlayerInVehicle (not AnyVehicle).
If i'm going to use my first logic then IsPlayerInVehicle will also check driver and put him as a passenger.
I believe arrays can help me. I can store "player id" in array every time player state changes to "passenger" and then just check in loop that array. That may cause passenger to switch seats with each other but its okay.

This will take some time to learn arrays and write fully working code. If someone interested i can post it here as soon as i finish it.

Thanks for help guys
Reply
#5

I'm glad you asked for further explanation than most new users don't. So I will run you through your code line by line. So 'cmdtext' is the text that you enter in the input box followed by a '/'. So basically by adding a '/' as the first character in your input box, opened by 'T', '`' or 'F6' by default, you are typing a command which is then passed through OnPlayerCommandText.

For example, if I type '/mycommand' in-game, it will run it through OnPlayerCommandText like this:
Код:
OnPlayerCommandText(playerid, "/mycommand");
Where 'playerid' is the number or ID that your client is currently playing with, which is the ID used to separate each player from each other, to make them all unique. Read more here: https://sampwiki.blast.hk/wiki/OnPlayerCommandText

Now to the more important part... what your command is actually doing currently.
pawn Код:
if(strcmp("/tower", cmdtext, true, 10) == 0)
What this translate to is something like:
if the comparison of the two strings, "/tower" and cmdtext (cmdtext being what you entered in the input box), and having the two being case insensitive with a string length of 10, move forward to the next code.
strcmp = Compare two strings, if they match each other (case sensitivity is determined by the 'true' or 'false' in the third parameter), then the function will return 0.
"/tower" = The command that the player must enter in order for this code to be executed, this is the first string that is going to be compared.
cmdtext = The text that you actually entered in the input box, this is the second string to be compared. If string1 == string2, it will return 0. Basically, if the text your enter is the same as "/tower", the code below will be executed.
true = This can be set to either true or false, this is used to say whether the strings need to be case sensitive or not. This parameter is called 'ignorecase', so if a player enters "/TOWER" or "/Tower", and you have ignorecase set to false, it will not be the same as "/tower". So for command, it is recommended that you ignore the case sensitivity, so players can still execute as long as they type "/tower" in any form of capital or non-capital letters.
10 = This is the string length of the command, in your command, this is actually wrong. This is used to say how long the strings should be when at their maximum length. Now "/tower" is not 10 characters long, you can either change the 10 to a 6, or remove it altogether so it can be automatically determined by the compiler.
== 0 = If the function 'strcmp' returns 0, which is the given outcome if the strings match each other, then continue with the code. Read more here: https://sampwiki.blast.hk/wiki/strcmp

pawn Код:
if(IsPlayerInAnyVehicle(playerid))
This one is pretty self-explanatory. If the player is in any type of vehicle, continue with the code. Read more here: https://sampwiki.blast.hk/wiki/IsPlayerInAnyVehicle

pawn Код:
new vehicleid = GetPlayerVehicleID(playerid);
This will assign the outcome of 'GetPlayerVehicleID(playerid)' to the variable 'vehicleid'. So instead of typing GetPlayerVehicleID(playerid) all the time, we can just save it to a variable, and use that variable in future sections of the code. Read more here: https://sampwiki.blast.hk/wiki/GetPlayerVehicleID

pawn Код:
new pState = GetPlayerState(playerid);
This is the same as the above, but instead, this will save the outcome or returned value of 'GetPlayerState(playerid)'.

pawn Код:
if(pState == PLAYER_STATE_DRIVER)
This is basically saying that if the player's state is the state of a driver, meaning the player is driving a vehicle and not just a passenger, then follow through with the code. Because we replaced 'GetPlayerState(playerid)' with 'pState', this code is basically saying: if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER). Read more here: https://sampwiki.blast.hk/wiki/GetPlayerState

pawn Код:
SetVehiclePos(vehicleid, 1544.2318, -1354.3735, 329.4725);
This will Set the position (or teleport in this instance) the vehicle to the given x, y and z coordinates. The San Andreas map is a 3D cube if you will, which has an x, y and z plane. X being the coordinates along the X plane (East to West), Y being the coordinates along the Y plane (North to South), and Z being the coordinates along the Z plane, also known as the 'height or altitude' coordinate. Read more here: https://sampwiki.blast.hk/wiki/SetVehiclePos

pawn Код:
SetVehicleZAngle(vehicleid, 100);
This will set the angle that your vehicle faces to '100'. As in a normal circle, there is 360 degrees, this will set your facing angle too 100 degrees. Read more here (Non SA-MP related website): http://en.wikipedia.org/wiki/Degree_%28angle%29 and read more here: https://sampwiki.blast.hk/wiki/SetVehicleZAngle

pawn Код:
PutPlayerInVehicle(playerid, vehicleid, 0);
This code will put your player back into the vehicle after it has teleported, as the driver. It works as PutPlayerInVehicle(PlayerToTeleport, VehicleToTeleportInto, Seat), where seat is determined by the number 0 and upwards for passengers. 0 = driver, 1 = passenger seat 1, 2 = Passenger seat 2, 3 = Passenger seat 3 for vehicles with up to 4 seats. It continues with the more seats that their are. Read more here: https://sampwiki.blast.hk/wiki/PutPlayerInVehicle and here: https://sampwiki.blast.hk/wiki/GetPlayerVehicleSeat

pawn Код:
else
This is used to execute code if the respective 'if' statement is not true. Let's say A = 2. If I do:
pawn Код:
if(A == 3)
The 'if' statement will not execute, because A is equal to 2, not 3. So I add an 'else' statement underneath it, but note, this will execute for any value other than 3.
pawn Код:
if(A == 3) //A is equal to 3
{
    //Do stuff
}
else //A is not 3, but another value.
{
    //Do other stuff
}
Read more here: https://sampwiki.blast.hk/wiki/Keywords:Statements#else

pawn Код:
SetPlayerPos(playerid, 1541.3450,-1366.5369,329.7969);
This will set the player's position, as opposed to the vehicle's position, if the player is not a driver in a vehicle. It will teleport the player directly to the X, Y and Z coordinates that you have given. Read more here: https://sampwiki.blast.hk/wiki/SetPlayerPos

pawn Код:
SetPlayerFacingAngle(playerid, 360);
Much like the usage of SetVehicleZAngle, this will set the player's facing angle (the angle in which the player is facing) to 360 degrees. Read more here: https://sampwiki.blast.hk/wiki/SetPlayerFacingAngle

pawn Код:
return 1;
This is the value to return for OnPlayerCommandText, or the command itself "/tower". For OnPlayerCommandText, a returned value of '1' tells the script that the command was successful, and the command exists. A returned value of '0' for OnPlayerCommandText tells the script that the command was either not successfully processed, or the command does not exist at all. (This is part of the reason for the error you are getting.) Read more here: https://sampwiki.blast.hk/wiki/OnPlayerCommandText and read this: https://sampwiki.blast.hk/wiki/Keywords:Statements#return

After we run through your code, it will work normally, but will give you this error because you are only returning '1' when the player is not a driver in a vehicle. As you may notice, the return 1 is under the 'else' statement, but not under the 'if(pState == PLAYER_STATE_DRIVER)'. Meaning the command will return 'SERVER: Unknown Command' if the player is a driver in a vehicle. A way to fix this is to return 1 at the end of the command, outside of any if statements, so it will return 1 no matter what. The correct code (in your terms) would be the following:
pawn Код:
if(strcmp("/tower", cmdtext, true) == 0)
    {
        if(IsPlayerInAnyVehicle(playerid))
        {
            new vehicleid = GetPlayerVehicleID(playerid);
            new pState = GetPlayerState(playerid);
            if(pState == PLAYER_STATE_DRIVER)
            {
                SetVehiclePos(vehicleid, 1544.2318, -1354.3735, 329.4725);
                SetVehicleZAngle(vehicleid, 100);
                PutPlayerInVehicle(playerid, vehicleid, 0);
            }
        }
        else
        {
            SetPlayerPos(playerid, 1541.3450,-1366.5369,329.7969);
            SetPlayerFacingAngle(playerid, 360);
        }
    return 1;
    }
If we neaten this up, the correct code would be:
pawn Код:
if(strcmp(cmdtext, "/tower", true) == 0)
{
    if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER) //If their state is 'PLAYER_STATE_DRIVER', we can determine that they are already in a vehicle, and IsPlayerInAnyVehicle does not need to be used.
    {
        new vehicleid = GetPlayerVehicleID(playerid); //Get the player's vehicle ID
        SetVehiclePos(vehicleid, 1544.2318, -1354.3735, 329.4725); //Teleport the player's vehicle to the given coordinates
        SetVehicleZAngle(vehicleid, 100); //Set the vehicle's angle to 100
        PutPlayerInVehicle(playerid, vehicleid, 0); //Put the player in the vehicle again, in seat 0, which is the driver's seat.
    }
    else //If the player using "/tower" is not a driver in a vehicle.
    {
        SetPlayerPos(playerid, 1541.3450,-1366.5369,329.7969); //Teleport the player himself, to the given coordinates.
        SetPlayerFacingAngle(playerid, 360); //Set the player to face at an angle of 360 degrees.
    }
    return 1; //Tell the callback 'OnPlayerCommandText' to return 1 to the server, meaning this command has been executed and exists. Meaning no 'SERVER: Unknown Command' will be sent to the player.
}
The above will work, but will not teleport passengers as well. Such scripting just requires a bit of logical thinking, so you have to think of the best logical method that would work. You are thinking of going through all vehicles to see if that vehicle is the one being teleported, then going through all players to see if they are in that vehicle being teleported, which is a double loop, which really, you don't want to be using in SA-MP.
So if we re-think this, what do we get?
- Passengers must be inside the same vehicle as the driver, how do we get the vehicle id of the driver? In this line: 'new vehicleid = GetPlayerVehicleID(playerid);'
- We need to go through all players, to see if they are in this vehicle... to start a loop, we use 'for(new i = 0; i < MAX_PLAYERS; i++)'. Loops are explained here: https://sampwiki.blast.hk/wiki/Loops
- We don't want the driver of the vehicle to be included in the loop, because he has already been teleported, so we use 'if(i == playerid) continue;', meaning if the player we're looking at has the same id as the player using "/tower", skip him. More explained on 'continue' here: https://sampwiki.blast.hk/wiki/Keywords:Statements#continue
- Once we start looking through all players, we need to check if they are in the vehicle 'vehicleid', so we use 'if(GetPlayerVehicleID(i) == vehicleid)', which means if the id of the given player's vehicle, matches the id of the driver's vehicle, then they must be in the same vehicle. There cannot be 2 drivers of a vehicle, so obviously this player is a passenger in the same vehicle.
- We now know the player is a passenger in the same vehicle, so we have to teleport him into THE SAME SEAT he was in, in the vehicle originally. So we save the id of his seat with 'new seat = GetPlayerVehicleSeat(i);'
- As we need to get their vehicle seat, we have to get their seat BEFORE we actually teleport the vehicle, so this loop will have to be before we teleport the vehicle (SetVehiclePos).
- After we teleport the vehicle, we teleport the passengers back into the vehicle, which means we may need another loop after we teleport the vehicle.
- Then teleport them into the vehicle using 'PutPlayerInVehicle', but with the seat they were originally used, which we saved in the variable 'seat'. 'PutPlayerInVehicle(i, vehicleid, seat);'

So let's construct this command:
pawn Код:
if(strcmp(cmdtext, "/tower", true) == 0)
{
    if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER)
    {
        new vehicleid = GetPlayerVehicleID(playerid);
        new bool:teleportplayer[MAX_PLAYERS] = false; //Used to determine whether we need to teleport the player or not. (Bool means you are using true or false instead of integers. Could not find the page for booleans, but I know there is one)
        new seat[MAX_PLAYERS]; //Used to save the seat id to their playerid.
        new i; //Will be used in the loop, twice.
        for(i = 0; i < MAX_PLAYERS; i++)
        {
            if(!IsPlayerConnected(i)) continue; //If the playerid 'i' is not connected, skip it. (Meaning there is not player with this ID. Read more here: https://sampwiki.blast.hk/wiki/IsPlayerConnected)
            if(i == playerid) continue;
            if(!IsPlayerInVehicle(i, vehicleid)) continue; //Read more here: https://sampwiki.blast.hk/wiki/IsPlayerInVehicle
            seat[i] = GetPlayerVehicleSeat(i);
            teleportplayer[i] = true;
        }
        SetVehiclePos(vehicleid, 1544.2318, -1354.3735, 329.4725); //Teleport the player's vehicle to the given coordinates
        SetVehicleZAngle(vehicleid, 100); //Set the vehicle's angle to 100
        PutPlayerInVehicle(playerid, vehicleid, 0); //Put the player in the vehicle again, in seat 0, which is the driver's seat.
        for(i = 0; i < MAX_PLAYERS; i++)
        {
            if(!IsPlayerConnected(i)) continue;
            if(i == playerid) continue;
            if(teleportplayer[i] != true) continue;
            PutPlayerInVehicle(i, vehicleid, seat[i]);
        }
    }
    return 1;
}
I hope this kind of helps you understand, if you're unsure about anything, just ask. I just realised you already posted, so I'm not sure if I even need to post here, but here you are anyway.

EDIT: Oh, and I'm sure there's a neater way to do this command, but I'm a bit blank in the head right now, so if anyone wants to correct it, feel free to do so
Reply
#6

Wow!
BenzoAMG, you're the best! Thanks a lot. I've learned a ton of new things.
I really appreciate your help and now i can optimize all my PlayerCommands.
Reply
#7

You dont need 2 times loop for MAX_PLAYERS

pawn Код:
if(strcmp(cmdtext, "/tower", true) == 0)
{
    if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER)
    {
        new vehicleid = GetPlayerVehicleID(playerid);
        new PlayerID[50],SeatID[50],cnt,i;
        for(i = 0; i < MAX_PLAYERS; i++)
        {
            if(!IsPlayerConnected(i)) continue;
            if(i == playerid) continue;
            if(GetPlayerVehicleID(i) != vehicleid) continue;
            new VSeat = GetPlayerVehicleSeat(i);
            PlayerID[cnt] = i;
            SeatID[cnt] = (-1 < VSeat < sizeof(PlayerID)) ? VSeat : cnt+1;
            ++cnt;
        }
        SetVehiclePos(vehicleid, 1544.2318, -1354.3735, 329.4725);
        SetVehicleZAngle(vehicleid, 100.0);
        for(i = 0; i < cnt; i++)
            PutPlayerInVehicle(PlayerID[i], vehicleid, SeatID[i]);
    }
    return 1;
}
// EDIT

Wrong placed return 1; so unknown command appears

pawn Код:
if(strcmp(cmdtext, "/tower", true) == 0)
{
    if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER)
    {
        new vehicleid = GetPlayerVehicleID(playerid);
        SetVehiclePos(vehicleid, 1544.2318, -1354.3735, 329.4725);
        SetVehicleZAngle(vehicleid, 100);
    }
    else
    {
        SetPlayerPos(playerid, 1541.3450,-1366.5369,329.7969);
        SetPlayerFacingAngle(playerid, 360);
    }
    return 1;
}
Reply
#8

Thanks for clearing that up Jefff. Just one question, why is PlayerID and SeatID a size of 50? Shouldn't the max be around 8 or 9? And I knew the two loops weren't the best way to do it, but it was like 8am and I hadn't slept and I wasn't prepared to sit here and work it out. :P
Reply
#9

In Bus,at-400 and other vehicles u can have more than 8-9 passengers so I set a limit on 50 ? I think this is good limit
Reply
#10

I know the bus and coach hold around 8, and the AT-400 also holds around 8. I don't know of any that hold 50 though D:
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)