13.06.2014, 06:14
CREATING AN EFFECTIVE STRANGER SYSTEM
Section 1.0 - Introduction
It (a Stranger System) nowadays seems to be a must-have feature with servers. But most of them are poorly executed and just show a stranger, not a stranger ID to report and everything else, which gets very confusing for administrators, players, etcetera (or even worse, and just hides their name and that's about it)! So, it is important that you have a stranger system that has both dazzle and functionality. I will cover it all in this tutorial! There are multiple things you should consider:
- How important is dazzle to me? (How will I spice it up a bit? I.E: Creating a transparent -but darker- textdraw over the entire screen when a player puts on sunglasses)
- How important is functionality to me? (How much work should admins have to go through to find who a stranger is?)
- What will the system's purpose be? (Will it be used for ultra-secret factions or such, or for anybody?)
Section 1.1 - What We Will Use
We will be using multiple things today, such as:
- Standard Variables
- Loops
- 3DTextLabels
- ProxDetector
- Scripting Basics
pawn Code:
stock randomEx(min, max)
{
//Credits to y_less
new rand = random(max-min)+min;
return rand;
}
pawn Code:
forward ProxDetectorS(Float:radi, playerid, targetid);
stock ProxDetector(Float:radi, playerid, string[], col1, col2, col3, col4, col5)
{
if(IsPlayerConnected(playerid))
{
new Float:posx, Float:posy, Float:posz;
new Float:oldposx, Float:oldposy, Float:oldposz;
new Float:tempposx, Float:tempposy, Float:tempposz;
new invehicle[MAX_PLAYERS];
new virtualworld = GetPlayerVirtualWorld(playerid);
new interior = GetPlayerInterior(playerid);
new vehicleid = GetPlayerVehicleID(playerid);
new ivehicleid;
if(vehicleid)
{
GetVehiclePos(vehicleid,oldposx,oldposy,oldposz);
}
else
{
GetPlayerPos(playerid, oldposx, oldposy, oldposz);
vehicleid = GetPlayerVehicleID(playerid);
}
while (strfind(string, PlayerName(playerid), false) != -1 && PlayerInfo[playerid][pMask])
{
new pos = strfind(string, PlayerName(playerid), false);
strdel(string, pos, pos + strlen(PlayerName(playerid)));
new string2[26];
format(string2, sizeof(string2), "Stranger %d", StrangerID[playerid]);
strins(string, string2, pos, 512);
}
for(new i = 0; i < MAX_PLAYERS; i++)
{
if(IsPlayerConnected(i))
{
if(!BigEar[i])
{
if(GetPlayerVirtualWorld(i) == virtualworld)
{
if((GetPlayerInterior(i) == interior))
{
if(vehicleid)
{
if(IsPlayerInVehicle(i,vehicleid)) invehicle[i] = 1;
}
if(!invehicle[i])
{
if(IsPlayerInAnyVehicle(i))
{
ivehicleid = GetPlayerVehicleID(i);
GetVehiclePos(ivehicleid,posx,posy,posz);
}
else
{
GetPlayerPos(i,posx,posy,posz);
}
tempposx = (oldposx -posx);
tempposy = (oldposy -posy);
tempposz = (oldposz -posz);
if (((tempposx < radi/16) && (tempposx > -radi/16)) && ((tempposy < radi/16) && (tempposy > -radi/16)) && ((tempposz < radi/16) && (tempposz > -radi/16))) SendClientMessage(i, col1, string);
else if (((tempposx < radi/8) && (tempposx > -radi/8)) && ((tempposy < radi/8) && (tempposy > -radi/8)) && ((tempposz < radi/8) && (tempposz > -radi/8))) SendClientMessage(i, col2, string);
else if (((tempposx < radi/4) && (tempposx > -radi/4)) && ((tempposy < radi/4) && (tempposy > -radi/4)) && ((tempposz < radi/4) && (tempposz > -radi/4))) SendClientMessage(i, col3, string);
else if (((tempposx < radi/2) && (tempposx > -radi/2)) && ((tempposy < radi/2) && (tempposy > -radi/2)) && ((tempposz < radi/2) && (tempposz > -radi/2))) SendClientMessage(i, col4, string);
else if (((tempposx < radi) && (tempposx > -radi)) && ((tempposy < radi) && (tempposy > -radi)) && ((tempposz < radi) && (tempposz > -radi))) SendClientMessage(i, col5, string);
}
else SendClientMessage(i, col1, string);
}
}
}
else SendClientMessage(i, col1, string);
}
}
}
return 1;
}
pawn Code:
#define DIALOG_MASK 1
#define PURPLE 0xC2A2DAAA
new StrangerID[MAX_PLAYERS]; //Gets/Sets the player's stranger ID when the mask.
new Text3D:StrangerTag[MAX_PLAYERS]; //This will be the 3DTextLabel that shows their stranger ID
new Text3D:StrangerHealth[MAX_PLAYERS]; //This will show the stranger's health & armor (if they have armor)
Section 2.1 - Creating the Command
pawn Code:
CMD:mask(playerid, params[])
{
if(StrangerID[playerid]) == 0) //Checking to see if the player is already masked...
{
ShowPlayerDialog(playerid, DIALOG_MASK, DIALOG_STYLE_LIST, "Which mask?", "Sunglasses\nHandkerchief\nMask (default)", "Select", "Cancel"); //Asking them what style of mask they would like to wear...
}
else if(StrangerID[playerid] > 0) //But if the player is already masked...
{
SendClientMessage(playerid, -1, "ERROR: You already have a mask on. Use /unmask to take it off!"); //Send this message...
}
return 1;
}
Section 2.2 - Masking Up
pawn Code:
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
switch(dialogid)
{
case DIALOG_MASK: //If the mask dialog is chosen...
{
if(!response) return 0; //If the cancel button is hit then do nothing.
new choice[64], string[128], bool:found = false; //The bool here is important as it states whether the system has found an available stranger ID for the player.
for(new i = 0; i < MAX_PLAYERS; i++) //Looping through all the players.
{
new randz = randomEx(1000, 5000);
if (StrangerID[i] == randz) //The Stranger ID is currently in use by another player, so we will continue the server for an ID...
{
while (!found) //When the system has still yet to find an available stranger ID...
{
randz = randomEx(1000, 5000); //Call another random to try to find an available Stranger ID
if (StrangerID[i] == randz) //If the attempted new Stranger ID is already taken...
{
found = false; //Let the search continue...
continue; //Continue the search...
}
else //If the attempted new Stranger ID is available...
{
found = true; //The search is over, we have found our Stranger ID!
break; //Get out of this section and continue on in the script.
}
}
}
StrangerID[playerid] = randz; //Set the stranger ID to the found random integer
ShowPlayerNameTagForPlayer(i, playerid, 0); //Hide the player's name tag for all players.
}
switch(listitem) //Switching between the three mask options (no difference between them other than the tag, which is intended for roleplay purposes.
{
case 0: //If they chose sunglasses...
{
format(string, sizeof(string), "* Stranger %d has put on a pair of sunglasses", StrangerID[playerid]); //Just formatting their RP message for ProxDetector.
format(choice, sizeof(choice), "Stranger %d (sunglasses)", StrangerID[playerid]); //Setting their Stranger Tag
}
case 1: //If they chose a handkerchief...
{
format(string, sizeof(string), "* Stranger %d has put on a handkerchief", StrangerID[playerid]); //Just formatting their RP message for ProxDetector.
format(choice, sizeof(choice), "Stranger %d (handkerchief)", StrangerID[playerid]);//Setting their Stranger Tag
}
case 2: //If they chose a regular mask...
{
format(string, sizeof(string), "* Stranger %d has put on a mask", StrangerID[playerid]); //Just formatting their RP message for ProxDetector.
format(choice, sizeof(choice), "Stranger %d (mask)", StrangerID[playerid]);//Setting their Stranger Tag
}
}
StrangerTag[playerid] = Create3DTextLabel(choice, 0xFFFFFFFF, 0, 0, 0, 15.0, 0, 1); //Let's define the player's StrangerTag and set it to their formatted tag from above.
Attach3DTextLabelToPlayer(StrangerTag[playerid], playerid, 0.0, 0.0, 0.3); //Attach their 3DTextLabel from the line above.
new Float:arm, Float:hps, healthstring[64]; //Float variables to detect a player's health and the string to format the information to.
GetPlayerHealth(playerid, hps); //Get the player's health and set it to Float:hps.
GetPlayerArmour(playerid, arm); //Get the player's armor and set it to Float:arm.
new hpe = floatround(hps); //Create a new variable (integer) and round the float to a whole number to display the health.
new arme = floatround(arm); //Create a new variable (integer) and round the float to a whole number to display the armor.
if(arm != 0) //If the player's armor is greater than zero...
{
format(healthstring, sizeof(healthstring), "HP: %d | Armour: %d", hpe, arme); //Format their health string to include both Health and Armor information.
}
else //If the player has no armor.
{
format(healthstring, sizeof(healthstring), "Health: %d", hpe); //Format their health string to only include their health.
}
StrangerHealth[playerid] = Create3DTextLabel(healthstring, 0xFFFFFFFF, 0, 0, 0, 15.0, 0, 1); //Create their 3DTextLabel for their health information and set it to the healthstring formatted in the if statement above.
Attach3DTextLabelToPlayer(StrangerHealth[playerid], playerid, 0.0, 0.0, 0.225); //Attach their health information.
ProxDetector(15.0, playerid, string, PURPLE, PURPLE, PURPLE, PURPLE, PURPLE); //Send the RP message that the person has put on a mask
}
return 1;
}
return 0;
}
Section 2.3 - Removing The Mask
pawn Code:
stock RemoveMask(playerid)
{
if(StrangerID[playerid] == 0) return 0; //If the player doesn't have a mask to remove in the first place...
StrangerID[playerid] = 0; //Setting the stranger ID to zero, as the player no longer needs a Stranger ID.
Delete3DTextLabel(StrangerTag[playerid]); //Deleting the StrangerTag, as they are no longer a stranger.
Delete3DTextLabel(StrangerHealth[playerid]); //Deleting the StrangerHealth, as they are no longer a stranger.
for(new i=0;i<MAX_PLAYERS;i++) //Looping through all the players...
{
ShowPlayerNameTagForPlayer(i, playerid, 1); //Show the player's name again to other players.
}
return 1;
}
pawn Code:
public OnPlayerDeath(playerid, killerid, reason) //We are using this here because SA:MP (by default) show's player nametags again to everyone when the player dies. You can make a workaround for this; however for the sake of time I will not go into that (merely hide the player's name again and you should be good.)
{
if(StrangerID[playerid] != 0) RemoveMask(playerid); //Call the RemoveMask function for the player when they die if the player is masked.
return 1;
}
public OnPlayerDisconnect(playerid, reason) //We are removing it here in order to clean up the 3DTextLabels and permit the StrangerID to be available for new people who /mask.
{
if(StrangerID[playerid] != 0) RemoveMask(playerid); //Call the RemoveMask function for the player when they disconnect if the player is masked so it cleans the old 3DTextLabels and can open up a StrangerID for the random search.
return 1;
}
CMD:unmask(playerid, params[]) //And finally, the command to unmask..
{
if(StrangerID[playerid] == 0) return SendClientMessage(playerid, -1, "You are not wearing a mask, use /mask to put one on!");
RemoveMask(playerid);
new string[128], Name[64];
GetPlayerName(playerid, Name, MAX_PLAYER_NAME);
format(string, sizeof(string), "* %s removes the clothing from their face, revealing their identity. *", Name); //formatting a RP message to show people nearly as the person removes their mask.
ProxDetector(15.0, playerid, string, PURPLE, PURPLE, PURPLE, PURPLE, PURPLE); //Send the RP message that the person has removed their mask.
return 1;
}
Section 2.4 - Updating the Health String
pawn Code:
public OnGameModeInit()
{
SetTimer("StrangerHealthUpdate", 1000, true); //You can put everything that is called in this timer in any other 1-second timer to conserve on computer RAM and CPU, I just made a separate one because we only use one timer throughout the script.
return 1;
}
forward StrangerHealthUpdate();
public StrangerHealthUpdate()
{
for(new i=0;i<MAX_PLAYERS;i++) //Looping through all the players...
{
if(StrangerID[i] != 0) //If the player's Stranger ID does not equal zero...
{
new Float:hps, Float:arm, healthstring[64]; //All the stuff from when we got the health before.
GetPlayerHealth(playerid, hps); //Get their health in Float:hps
GetPlayerArmour(playerid, arm); //Get their armor in Float:arm
new armour = floatround(arm); //Round their armor to an integer
new hltz = floatround(hps); //Round their health to an integer
if(arm != 0) //If they have greater than zero armor...
{
format(healthstring, sizeof(healthstring), "HP: %d | Armour: %d", hltz, armour); //Format it as such...
}
else //If they have zero armor...
{
format(healthstring, sizeof(healthstring), "Health: %d", hltz); //Format it without armor
}
Update3DTextLabelText(StrangerHealth[playerid], 0xFFFFFFFF, healthstring); //And now we update the string.
}
}
return 1;
}
Section 3.0 - The Rest is up to You
Well, I covered the basic information that you need to know to creating an effective stranger system. Now what you should be able to easily do is create a /reportstranger command that get's the player's name and sends it as a regular report to administrators. And also a simple /viewstrangers command. You should easily be able to make it to where you detect if someone is wearing a mask and to create chat messages with their stranger ID rather than their name or just "stranger". Some suggestions that I will give you to make your stranger system more intricate are:
- Create items to attach to the player's face based on what kind of mask they put on
- Create TextDraw effects for things like the sunglasses to actually resemble the effects of sunglasses
- Create more possibilities for masks
I have covered just about everything to show you how I make my stranger systems and to interpret how to make your own or build off of this one. I hope that I have taught you a thing or two within this tutorial; if I taught one person something, then the two hours I wrote writing this was well worth it! This is my first tutorial, so if I made any mistakes within my code please inform me and if I left out some explaining inform me as well. Good luck!