/*----------------------------------------------------------------------------*- =========================== foreach efficient looping =========================== Description: Provides functionality to loop efficiently through all connected players. Removes reliance on both modification of MAX_PLAYERS for more efficient processing on small servers (although still recommended) and IsPlayerConnected. Legal: Copyright (C) 2007 Alex "Y_Less" Cole This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Version: 0.1.3 Changelog: 21/08/09: Updated to include random functions. Made entirely stand alone. Ported to 0.3 (separate version). Added automatic callback hook code. Removed debug information from stand alone version. 06/01/08: Added debug information. 09/10/07: Moved to system. 16/09/07: Added list sorting. Made this part of Y SeRver Includes, not Y Sever Includes. Made list sorting optional. Fixed version number. 08/09/07: First version. Functions: Public: OnPlayerDisconnect - Called when a player leaves to remove them. OnPlayerConnect - Called when a player connects to add them. Core: - Stock: Itter_ShowArray - Displays the contents of the array. Itter_AddInternal - Add a value to an itterator. Itter_RemoveInternal - Remove a value from an itterator. Itter_RandomInternal - Get a random item from an itterator. Static: - Inline: Itter_Create - Create a new itterator value set. Itter_Add - Wraps Itter_AddInternal. Itter_Remove - Wraps Itter_RemoveInternal. Itter_Random - Wraps Itter_RandomInternal. Itter_Count - Gets the number of items in an itterator. API: - Callbacks: - Hooks: Itter_OnPlayerConnect - Hook for the OnPlayerConnect callback. Itter_OnPlayerDisconnect - Hook for the OnPlayerDisconnect callback. Definitions: - Enums: - Macros: foreach - Command to loop through all connected players efficiently. foreachex - Like foreach but without a new variable. Tags: - Variables: Global: - Static: - Commands: - Compile options: YSI_ITTER_NO_SORT - Doesn't sort itterators, so using them comes out random. Operators: - Iterators: Player - List of all players connected. Bot - List of all bots (npcs) connected. NPC - Alias of Bot. Character - All players and bots. -*----------------------------------------------------------------------------*/ #if defined _foreach_included #endinput #endif #define _foreach_included #if !defined _samp_included #include #endif #if defined IsPlayerNPC #define _FOREACH_BOT #endif /*----------------------------------------------------------------------------*- Function: Itter_Create Params: name - Itterator identifier. size - Number of values. Return: - Notes: Creates a new itterator start/array pair. -*----------------------------------------------------------------------------*/ #define Iter_Create Itter_Create #define Itter_Create(%1,%2) \ new \ YSI_g%1S = -1, \ YSI_g%1C = 0, \ YSI_g%1A[%2] = {-1, ...} /*----------------------------------------------------------------------------*- Function: Itter_Add Params: itter - Name of the itterator to add the data to. value - Value to add to the itterator. Return: - Notes: Wrapper for Itter_AddInternal -*----------------------------------------------------------------------------*/ #define Iter_Add Itter_Add #define Itter_Add(%1,%2) \ Itter_AddInternal(YSI_g%1S, YSI_g%1C, YSI_g%1A, %2) /*----------------------------------------------------------------------------*- Function: Itter_Remove Params: itter - Name of the itterator to remove data from. value - Data to remove. Return: - Notes: Wrapper for Itter_RemoveInternal -*----------------------------------------------------------------------------*/ #define Iter_Remove Itter_Remove #define Itter_Remove(%1,%2) \ Itter_RemoveInternal(YSI_g%1S, YSI_g%1C, YSI_g%1A, %2) /*----------------------------------------------------------------------------*- Function: Itter_Random Params: itter - Name of the itterator to get a random slot from4. Return: - Notes: Wrapper for Itter_RandomInternal -*----------------------------------------------------------------------------*/ #define Iter_Random Itter_Random #define Itter_Random(%1) \ Itter_RandomInternal(YSI_g%1S, YSI_g%1C, YSI_g%1A) /*----------------------------------------------------------------------------*- Function: Itter_Random Params: itter - Name of the itterator to get a random slot from4. Return: - Notes: Wrapper for Itter_RandomInternal -*----------------------------------------------------------------------------*/ #define Iter_Random Itter_Random #define Itter_Random(%1) \ Itter_RandomInternal(YSI_g%1S, YSI_g%1C, YSI_g%1A) /*----------------------------------------------------------------------------*- Function: Itter_Count Params: itter - Name of the itterator to get a random slot from4. Return: - Notes: Returns the number of items in this itterator -*----------------------------------------------------------------------------*/ #define Iter_Count Itter_Count #define Itter_Count(%1) \ YSI_g%1C /*----------------------------------------------------------------------------*- Create the internal itterators. -*----------------------------------------------------------------------------*/ Itter_Create(Player, MAX_PLAYERS); #if defined _FOREACH_BOT Itter_Create(Bot, MAX_PLAYERS); Itter_Create(Character, MAX_PLAYERS); #define YSI_gNPCS YSI_gBotS #define YSI_gNPCC YSI_gBotC #define YSI_gNPCA YSI_gBotA #endif /*----------------------------------------------------------------------------*- Function: foreach Params: data - Data to itterate through. as - Variable to set value to. Return: - Notes: Not exactly the same as PHP foreach, just itterates through a list and returns the value of the current slot but uses that slot as the next index too. Variables must be in the form YSI_gS for the start index and YSI_gA for the data array where is what's entered in data. -*----------------------------------------------------------------------------*/ #define foreach(%1,%2) \ for (new %2 = YSI_g%1S; %2 != -1; %2 = YSI_g%1A[%2]) /*----------------------------------------------------------------------------*- Function: foreachex Params: data - Data to itterate through. as - Variable to set value to. Return: - Notes: Similar to foreach but doesn't declare a new variable for the itterator. -*----------------------------------------------------------------------------*/ #define foreachex(%1,%2) \ for (%2 = YSI_g%1S; %2 != -1; %2 = YSI_g%1A[%2]) /*----------------------------------------------------------------------------*- Function: Itter_OnPlayerConnect Params: playerid - Player who joined. Return: - Notes: Adds a player to the loop data. Now sorts the list too. Note that I found the most bizzare bug ever (I *think* it may be a compiler but, but it requires further investigation), basically it seems that multiple variables were being treated as the same variable (namely YSI_gBotS and YSI_gCharacterS were the same and YSI_gBotC and YSI_gCharacterC were the same). Adding print statements which reference these variables seem to fix the problem, and I've tried to make sure that the values will never actually get printed. -*----------------------------------------------------------------------------*/ public OnPlayerConnect(playerid) { #if defined _FOREACH_BOT if (IsPlayerNPC(playerid)) { if (!Itter_Add(Bot, playerid)) { printf("", YSI_gBotS); } } else { if (!Itter_Add(Player, playerid)) { printf("", YSI_gPlayerS); } } if (!Itter_Add(Character, playerid)) { printf("", YSI_gCharacterS); } #else if (!Itter_Add(Player, playerid)) { printf("", YSI_gPlayerS); } #endif CallLocalFunction("Itter_OnPlayerConnect", "i", playerid); return 1; } #define OnPlayerConnect Itter_OnPlayerConnect forward Itter_OnPlayerConnect(playerid); /*----------------------------------------------------------------------------*- Function: Itter_OnPlayerDisconnect Params: playerid - Player who left. Return: - Notes: Removes a player from the loop data. -*----------------------------------------------------------------------------*/ public OnPlayerDisconnect(playerid, reason) { #if defined _FOREACH_BOT if (IsPlayerNPC(playerid)) { Itter_Remove(Bot, playerid); } else { Itter_Remove(Player, playerid); } Itter_Remove(Character, playerid); #else Itter_Remove(Player, playerid); #endif CallLocalFunction("Itter_OnPlayerDisconnect", "ii", playerid, reason); return 1; } #define OnPlayerDisconnect Itter_OnPlayerDisconnect forward Itter_OnPlayerDisconnect(playerid, reason); /*----------------------------------------------------------------------------*- Function: Itter_ShowArray Params: start - Itterator start point. members[] - Itterator contents. size - Number of itterator values Return: - Notes: Pure debug function. Has regular prints not debug prints as it's only called when debug is on. -*----------------------------------------------------------------------------*/ stock Itter_ShowArray(start, members[], size) { static sString[61]; new i, j = 10; printf("Start: %d", start); while (i < size) { sString[0] = '\0'; while (i < j && i < size) { format(sString, sizeof (sString), "%s, %d", sString, members[i]); i++; } printf("Array (%d): %s", j, sString); j += 10; } } /*----------------------------------------------------------------------------*- Function: Itter_RandomInternal Params: start - Array start index. count - Number of items in the itterator. array[] - Itterator data. Return: - Notes: Returns a random value from an iterator. -*----------------------------------------------------------------------------*/ stock Itter_RandomInternal(start, count, array[]) { if (count == 0) { return -1; } new rnd = random(count), cur = start; while (cur != -1) { if (rnd--) { cur = array[cur]; } else { return cur; } } return -1; } /*----------------------------------------------------------------------------*- Function: Itter_AddInternal Params: &start - Array start index. &count - Number of items in the itterator. array[] - Itterator data. value - Item to add. Return: - Notes: Adds a value to a given itterator set. -*----------------------------------------------------------------------------*/ stock Itter_AddInternal(&start, &count, array[], value) { if (array[value] != -1) { return 0; } ++count; #if defined YSI_ITTER_NO_SORT array[value] = start; start = value; #else if (start == -1) { start = value; } else if (start > value) { array[value] = start; start = value; } else { new cur = start, last; do { last = cur; cur = array[cur]; if (cur > value) { array[value] = cur; array[last] = value; return 1; } } while (cur != -1); array[last] = value; } #endif return 1; } /*----------------------------------------------------------------------------*- Function: Itter_AddInternal Params: &start - Array start index. &count - Number of items in the itterator. array[] - Itterator data. value - Item to remove. Return: - Notes: Removes a value from an itterator. -*----------------------------------------------------------------------------*/ stock Itter_RemoveInternal(&start, &count, array[], value) { if (start == -1) { return 0; } if (start == value) { start = array[value]; } else { new cur = start; while (array[cur] != value) { cur = array[cur]; if (cur == -1) { return 0; } } array[cur] = array[value]; } array[value] = -1; --count; return 1; }