[Tutorial] Update Spectating Status - The solution!
#1

INTRODUCTION
Today I present to you a very good tutorial and useful for all servers.
The system is very simple, no bugs and without the use of Timers! Enjoy!

THE SYSTEM
Are you tired of typing /spec every time the player enter/exit a vehicle, teleport, go away, etc?
Keep calm, now your problems are over!
The system will automatically detect and update all the information for the Spectator instantly.
No need Timers or anything that harms the server, are only required some standard Callbacks and 1 new to all work perfectly.
All tested and working fine!

TUTORIAL

Variables:
pawn Code:
//So, we need to create in the top of gamemode this variable
new Spectating[MAX_PLAYERS]; //Simple variable to define the spected ID for the spectator ID.

//Using this variable:

//Use Spectating[playerid] = -1; To set a none spected ID for the spectador ID.
//Use Spectating[playerid] = spectedid; To set the ID of the spected player.
Example Commands:
pawn Code:
//Now, we need to create or use an existing commands to spec a player.
/spec - To spectate another player.
/specoff - To stop spectating.
Standard Callbacks and Functions:
pawn Code:
//We gonna use this folowing callbacks and functions to make the system.
OnPlayerConnect(); - To set Spectating[playerid] = -1;(Not spectating)
OnPlayerStreamOut(); - Called when the player Streamed out for another player.
OnPlayerStateChange(); - Called when the player change your state(Die, Spawn, Enter a vehicle, Exit a vehicle, etc).
TogglePlayerSpectating(); - To Toggle on or Toggle off the spectating mode.
PlayerSpectateVehicle(); - To set spectating mode if the spectedid is in a vehicle.
PlayerSpectatePlayer(); - To set spectating mode if the spectedid is on foot.
New Callbacks and Functions:
pawn Code:
//This callback we gonna create too.
UpdateSpectatingStatus(); - Will be called when the player change the state or stream out for a player.
First step:
pawn Code:
//You make it too in OnPlayerDisconnect(playerid) and OnPlayerSpawn(playerid) or another like want.
public OnPlayerConnect(playerid)
{
   Spectating[playerid] = -1;
   //Setting this variable to -1 we toggle non-spectaing ID to the spectador ID.
   return 1;
}
Creating(if not exist) the spectating commands:
pawn Code:
//Here you can use the or make like you want.
//The tools and functions to execute the commands are old(but works too).
//This is only a example to make the Update Spectating Status work.
public OnPlayerCommandText(playerid, cmdtext[])
{
    new cmd[256],tmp[256],giveplayerid,idx;
    cmd = strtok(cmdtext, idx);
   
    if(strcmp(cmd, "/spec", true) == 0)
    {
        tmp = strtok(cmdtext, idx);//Here we gonna set the spected ID, example:  /spec 5
        giveplayerid = ReturnUser(tmp);//Getting the spected ID to the variable "giveplayerid".
        if(IsPlayerConnected(giveplayerid))
        {
            //Getting the virtual world and interior of the spected ID and setting it to the spectator ID.
            SetPlayerVirtualWorld(playerid,GetPlayerVirtualWorld(giveplayerid));
            SetPlayerInterior(playerid,GetPlayerInterior(giveplayerid));
            //Now we gonna set the spected ID(giveplayerid) to the spectator ID(playerid).
            Spectating[playerid] = giveplayerid;
            //This function will start the spectating mode for the spectator ID.
            TogglePlayerSpectating(playerid, 1);

            //Define between PlayerSpectateVehicle(); - (if spected ID is in a vehicle) or PlayerSpectatePlayer(); - (if spected ID is not in a vehicle).
            if(IsPlayerInAnyVehicle(giveplayerid)) PlayerSpectateVehicle(playerid, GetPlayerVehicleID(giveplayerid), SPECTATE_MODE_NORMAL);
            else PlayerSpectatePlayer(playerid, giveplayerid, SPECTATE_MODE_NORMAL);
        }
        else return SendClientMessage(playerid, -1, "Warning: This player is not connected!");
        return 1;
    }
    if(strcmp(cmd, "/specoff", true) == 0)
    {
        if(IsPlayerConnected(playerid))
        {
            //Here we gonna set a default virtual world and interior to the spectator ID.
            SetPlayerVirtualWorld(playerid,0);
            SetPlayerInterior(playerid,0);
            //Setting a none spected ID(important to stop the Updating system).
            Spectating[playerid] = -1;
            //Now the spectating mode is off.
            TogglePlayerSpectating(playerid, 1);
        }
        return 1;
    }
    return 0;
}
Calling the Updating system:
pawn Code:
public OnPlayerStreamOut(playerid, forplayerid)
{
     //When the spected ID(playerid) teleport, change the virtual world or interior, go away, etc...
    //"forplayerid" is the spectator ID in this case.
    if(IsPlayerConnected(forplayerid))
    {
        if(Spectating[forplayerid] == playerid)//Check if "forplayerid" is spectating the playerid.
        {
            //This new callback will check the status of the spected ID and update it to the spectator ID.
            UpdateSpectatingStatus(forplayerid, playerid);
        }
    }
    return 1;
}

public OnPlayerStateChange(playerid, newstate, oldstate)
{
    //If the spected ID(playerid) enter/exit the vehicle, spawn, etc...
    for(new i = 0; i < GetMaxPlayers(); i++)
    {
        if(IsPlayerConnected(i))
        {
            if(Spectating[i] == playerid)//Check if someone is spectating him.
            {
                //This new callback will check the status of the spected ID(playerid) and update it to the spectator ID(i).
                UpdateSpectatingStatus(i, playerid);
            }
        }
    }
    return 1;
}
Last step is the function to Update the Spectating Status:
pawn Code:
stock UpdateSpectatingStatus(spectatorid, spectedid);
{
    //If the spectator ID is really spectating the spected ID...
    if(Spectating[spectatorid] == spectedid)
    {
        //This warnings you can use or not...
        if(GetPlayerState(spectedid) == PLAYER_STATE_WASTED) return GameTextForPlayer(spectatorid, "~r~Target wasted!", 5000, 3);
        if(GetPlayerState(spectedid) == PLAYER_STATE_SPECTATING) return GameTextForPlayer(spectatorid, "~r~Target in spectating mode!", 5000, 3);
        if(!IsPlayerConnected(spectedid)) return GameTextForPlayer(spectatorid, "~r~Target disconnected!", 5000, 3);
       
        //Again setting the virtual world and interior for the spectator ID.
        SetPlayerVirtualWorld(spectatorid,GetPlayerVirtualWorld(spectedid));
        SetPlayerInterior(spectatorid,GetPlayerInterior(spectedid));
        //Put the spectator ID in the spectating mode.
        TogglePlayerSpectating(spectatorid, 1);
        if(IsPlayerInAnyVehicle(spectedid)) PlayerSpectateVehicle(spectatorid, GetPlayerVehicleID(spectedid), SPECTATE_MODE_NORMAL);
        else PlayerSpectatePlayer(spectatorid, spectedid, SPECTATE_MODE_NORMAL);
    }
    return 1;
}
WARNING
- The script is just a base, using "outdated" or "slower" functions(for some expert scripters).
- Not all scripters use the "Updated or Improved" functions.
- You can use any functions you want or based in your Game Mode.
- The script is only to show how to make a simple code but functional.
- You can edit like you want.
- First test it before talk or report any thing that you don't know.
- You may get bugs if not enable/disable the variable based in the player ID.
- If you no need this or is not useful for you, leave it.
- If you have not read or did not consider these warnings, I will ignore your critical comment!

"As time went on people developed better methods (namely dcmd/sscanf, smaller arrays etc) so the old methods should have been forgotten right? Wrong!" - ******

THE SCRIPT

Here the complete script(example) to get a base/test or use it in your server:
pawn Code:
//==============================================================================//
//                       Update Spectating Status
//                           Creator: JR_Junior
//                        Date: February, 19, 2015
//
//==============================================================================//
#include <a_samp>

new Spectating[MAX_PLAYERS];

public OnPlayerConnect(playerid)
{
   Spectating[playerid] = -1;
   return 1;
}

public OnPlayerCommandText(playerid, cmdtext[])
{
    new cmd[256],tmp[256],giveplayerid,idx;
    cmd = strtok(cmdtext, idx);

    if(strcmp(cmd, "/spec", true) == 0)
    {
        tmp = strtok(cmdtext, idx);
        giveplayerid = ReturnUser(tmp);
        if(IsPlayerConnected(giveplayerid))
        {
            SetPlayerVirtualWorld(playerid,GetPlayerVirtualWorld(giveplayerid));
            SetPlayerInterior(playerid,GetPlayerInterior(giveplayerid));
            Spectating[playerid] = giveplayerid;
            TogglePlayerSpectating(playerid, 1);
            if(IsPlayerInAnyVehicle(giveplayerid)) PlayerSpectateVehicle(playerid, GetPlayerVehicleID(giveplayerid), SPECTATE_MODE_NORMAL);
            else PlayerSpectatePlayer(playerid, giveplayerid, SPECTATE_MODE_NORMAL);
        }
        else return SendClientMessage(playerid, -1, "Warning: This player is not connected!");
        return 1;
    }
    if(strcmp(cmd, "/specoff", true) == 0)
    {
        if(IsPlayerConnected(playerid))
        {
            SetPlayerVirtualWorld(playerid,0);
            SetPlayerInterior(playerid,0);
            Spectating[playerid] = -1;
            TogglePlayerSpectating(playerid, 1);
        }
        return 1;
    }
    return 0;
}

public OnPlayerStreamOut(playerid, forplayerid)
{
    if(IsPlayerConnected(forplayerid))
    {
        if(Spectating[forplayerid] == playerid)
        {
            UpdateSpectatingStatus(forplayerid, playerid);
        }
    }
    return 1;
}

public OnPlayerStateChange(playerid, newstate, oldstate)
{
    for(new i = 0; i < GetMaxPlayers(); i++)
    {
        if(IsPlayerConnected(i))
        {
            if(Spectating[i] == playerid)
            {
                UpdateSpectatingStatus(i, playerid);
            }
        }
    }
    return 1;
}

stock UpdateSpectatingStatus(spectatorid, spectedid);
{
    if(Spectating[spectatorid] == spectedid)
    {
        if(GetPlayerState(spectedid) == PLAYER_STATE_WASTED) return GameTextForPlayer(spectatorid, "~r~Target wasted!", 5000, 3);
        if(GetPlayerState(spectedid) == PLAYER_STATE_SPECTATING) return GameTextForPlayer(spectatorid, "~r~Target in spectating mode!", 5000, 3);
        if(!IsPlayerConnected(spectedid)) return GameTextForPlayer(spectatorid, "~r~Target disconnected!", 5000, 3);
        SetPlayerVirtualWorld(spectatorid,GetPlayerVirtualWorld(spectedid));
        SetPlayerInterior(spectatorid,GetPlayerInterior(spectedid));
        TogglePlayerSpectating(spectatorid, 1);
        if(IsPlayerInAnyVehicle(spectedid)) PlayerSpectateVehicle(spectatorid, GetPlayerVehicleID(spectedid), SPECTATE_MODE_NORMAL);
        else PlayerSpectatePlayer(spectatorid, spectedid, SPECTATE_MODE_NORMAL);
    }
    return 1;
}

//If you dont have this following funtions in yours includes or game mode, you will need it to test this script.
ReturnUser(text[])
{
    new pos = 0;
    while (text[pos] < 0x21)
    {
        if (text[pos] == 0) return INVALID_PLAYER_ID;
        pos++;
    }
    new userid = INVALID_PLAYER_ID;
    if (IsNumeric(text[pos]))
    {
        userid = strval(text[pos]);
        if(userid >=0 && userid < MAX_PLAYERS)
        {
            if(!IsPlayerConnected(userid)) userid = INVALID_PLAYER_ID;
            else return userid;
        }
    }
    new len = strlen(text[pos]);
    new count = 0;
    new name[MAX_PLAYER_NAME];
    for (new i = 0; i < MAX_PLAYERS; i++)
    {
        if(IsPlayerConnected(i))
        {
            GetPlayerName(i, name, sizeof (name));
            if (strcmp(name, text[pos], true, len) == 0)
            {
                if (len == strlen(name)) return i;
                else count++,userid = i;
            }
        }
    }
    if(count != 1) userid = INVALID_PLAYER_ID;
    return userid;
}
IsNumeric(const string[])
{
    for (new i = 0, j = strlen(string); i < j; i++) if(string[i] > '9' || string[i] < '0') return 0;
    return 1;
}
strtok(string[],&idx,seperator = ' ')
{
    new ret[128], i = 0, len = strlen(string);
    while(string[idx] == seperator && idx < len) idx++;
    while(string[idx] != seperator && idx < len) ret[i] = string[idx],i++,idx++;
    while(string[idx] == seperator && idx < len) idx++;
    return ret;
}
Reply
#2

You have explained absolutely nothing and you are using outdated tools.
I didn't even bother looking at the rest of the code. This is, just like many, a copy-paste topic.
Post it as a filterscript in the right section instead of a poorly written tutorial.
Reply
#3

Quote:
Originally Posted by Bible
View Post
You have explained absolutely nothing and you are using outdated tools.
I didn't even bother looking at the rest of the code. This is, just like many, a copy-paste topic.
Post it as a filterscript in the right section instead of a poorly written tutorial.
First, thank you for your comment!
My friend is a simple script, does not need much explanation. Just will not understand who is very newbie.
Outdated tools? Just because I have not used ZCMD? Just because it's a simple script but it works?
Friend, is a tutorial / base and you use the tools you want.
You may not need it, but has many they will need! Thank you!
Reply
#4

Meh, you didn't even explain anything here, you are just throwing out code at us.
Go to the filterscripts section if you want to create and share a script, in a tutorial you should explain to people how and why they need to do things.
Also, you are using heavily outdated methods, such as strcmp in OnPlayerCommandText, and strtok.
Reply
#5

You're using outdated and slower methods. Even though the code is basic it still needs more explanation.

https://sampforum.blast.hk/showthread.php?tid=65567
Reply
#6

Quote:
Originally Posted by CalvinC
View Post
Meh, you didn't even explain anything here, you are just throwing out code at us.
Go to the filterscripts section if you want to create and share a script, in a tutorial you should explain to people how and why they need to do things.
Also, you are using heavily outdated methods, such as strcmp in OnPlayerCommandText, and strtok.
Quote:
Originally Posted by Ryan_Bowe
View Post
You're using outdated and slower methods. Even though the code is basic it still needs more explanation.

https://sampforum.blast.hk/showthread.php?tid=65567
"As time went on people developed better methods (namely dcmd/sscanf, smaller arrays etc) so the old methods should have been forgotten right? Wrong!" - ******

I will explain more... thank you all!
Reply
#7

Code:
UpdateSpectatingStatus
Not used in calling nor in timers, so why not this is stock function -_-

Code:
public OnPlayerCommandText(playerid, cmdtext[])
Why not use zcmd standards

Code:
strcmp
This is slow as he'll and thats why people recommend zcmd!

Code:
strtok
Another slow motion there, implement sscanf!
Reply
#8

Quote:
Originally Posted by Excel™
View Post
Code:
UpdateSpectatingStatus
Not used in calling nor in timers, so why not this is stock function -_-
Thanks for remember this!
Reply
#9

Quote:
Originally Posted by Excel™
View Post
Code:
UpdateSpectatingStatus
Not used in calling nor in timers, so why not this is stock function -_-

Code:
public OnPlayerCommandText(playerid, cmdtext[])
Why not use zcmd standards

Code:
strcmp
This is slow as he'll and thats why people recommend zcmd!

Code:
strtok
Another slow motion there, implement sscanf!
Excel, "stock" and a function is 2 different things.
Stock will make the compiler ignore something if it's not used in your script, thereby also hiding warnings/errors, and not including it in your .amx file.

Example of a normal function:
pawn Code:
FuncName(parameters)
Using stock:
pawn Code:
stock FuncName(parameters)
Or:
pawn Code:
new stock VariableName;
Haven't used stock for anything else, but you might be able to use it for more.

I believe that public functions can be called between filterscripts etc. by adding it like this:
pawn Code:
public FuncName(parameters)
Thereby, "public" and "stock" are 2 different add-ons.
But in that example, both "stock" and "public" is useless, unless you wanna use it between scripts.
Reply
#10

Quote:
Originally Posted by CalvinC
View Post
Excel, "stock" and a function is 2 different things.
Stock will make the compiler ignore something if it's not used in your script, thereby also hiding warnings/errors, and not including it in your .amx file.

Example of a normal function:
pawn Code:
FuncName(parameters)
Using stock:
pawn Code:
stock FuncName(parameters)
Or:
pawn Code:
new stock VariableName;
Haven't used stock for anything else, but you might be able to use it for more.

I believe that public functions can be called between filterscripts etc. by adding it like this:
pawn Code:
public FuncName(parameters)
Thereby, "public" and "stock" are 2 different add-ons, i don't think any of them are necessary for this script though.
I can't control but here it is: I never compared stock or local functions. I just for simplicity stated stock function but I apologize! Secondally, using stock Is better than a callback! Can be used in the form of an include!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)