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:
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:
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:
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:
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:
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:
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,GetPlayerVirtualWor ld(giveplayerid));
SetPlayerInterior(playerid,GetPlayerInterior(givep layerid));
//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:
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:
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,GetPlayerVirtual World(spectedid));
SetPlayerInterior(spectatorid,GetPlayerInterior(sp ectedid));
//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!" - Y_Less

THE SCRIPT

Here the complete script(example) to get a base/test or use it in your server:
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,GetPlayerVirtualWor ld(giveplayerid));
SetPlayerInterior(playerid,GetPlayerInterior(givep layerid));
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,GetPlayerVirtual World(spectedid));
SetPlayerInterior(spectatorid,GetPlayerInterior(sp ectedid));
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;
}