/*----------------------------------------------------------------------------
					===========================
					 foreach efficient looping
					===========================
Description:
	Provides efficient looping through sparse data sets, such as connected
	players. Significantly improved from the original version to be a generic
	loop system, rather then purely a player loop system. When used for
	players this has constant time O(n) for number of connected players (n),
	unlike standard player loops which are O(MAX_PLAYERS), regardless of the
	actual number of connected players. Even when n is MAX_PLAYERS this is
	still faster.
Legal:
	Version: MPL 1.1

	The contents of this file are subject to the Mozilla Public License Version
	1.1 (the "License"); you may not use this file except in compliance with
	the License. You may obtain a copy of the License at
	http://www.mozilla.org/MPL/

	Software distributed under the License is distributed on an "AS IS" basis,
	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
	for the specific language governing rights and limitations under the
	License.

	The Original Code is the YSI foreach include.

	The Initial Developer of the Original Code is Alex "Y_Less" Cole.
	Portions created by the Initial Developer are Copyright (C) 2011
	the Initial Developer. All Rights Reserved.

	Contributors:
		ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice, Kar

	Thanks:
		JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
		ZeeX - Very productive conversations.
		koolk - IsPlayerinAreaEx code.
		TheAlpha - Danish translation.
		breadfish - German translation.
		Fireburn - Dutch translation.
		yom - French translation.
		50p - Polish translation.
		Zamaroht - Spanish translation.
		Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
			for me to strive to better.
		Pixels^ - Running XScripters where the idea was born.
		Matite - Pestering me to release it and using it.

	Very special thanks to:
		Thiadmer - PAWN, whose limits continue to amaze me!
		Kye/Kalcor - SA:MP.
		SA:MP Team past, present and future - SA:MP.

Version:
	19 (0.4.2)
Changelog:
	14/05/15:
		Cleaned up the entire include.
	16/07/12:
		Fixed a bug with "loadfs" blocking callbacks.
		Slightly reduced the memory consumption of constant strings.
	25/05/12:
		Added a delay timer to remove players for "Kick" crashes.
	05/01/12:
		Fixed multi-dimensional iterators.
		Fixed "FOREACH_NO_BOTS".
		Made "Iterator:" support multi-dimensional arrays.
	07/12/11:
		Underlying implementation tweak for more consistent code.
		Added Iter_Contains.
	06/12/11:
		Minor fixes.
	31/10/11:
		Changed the underlying loop code to be slightly faster.
		Added support for Iter_SafeRemove, prompting refactoring.
	17/09/11:
		Fixed arrays under the new syntax.
	28/04/11:
		Moved iterator identifiers to end of variables.
		Rewrote "foreach" to accept two syntaxes for "foreach (new i : Iter)".
	16/08/10:
		Removed all the "2" versions of the functions.
	14/08/10:
		Added Iter_Clear to reset an array.
	06/08/10:
		Added special array declaration format.
	18/12/09:
		Added Iter_Func2 functions for multi-dimensional iterators.
		Renamed foreact et al as keywords in the documentation.
		Changed licensing from GPL to MPL.
	02/09/09:
		Fixed (again) for 0.3.
		Added free slot finding.
	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:
		Iter_AddInternal - Add a value to an iterator.
		Iter_RemoveInternal - Remove a value from an iterator.
		Iter_RandomInternal - Get a random item from an iterator.
		Iter_FreeInternal - Gets the first free slot in the iterator.
		Iter_InitInternal - Initialises a multi-dimensional iterator.
		Iter_ContainsInternal - Checks if a value is in an iterator.
	Static:
		-
	Inline:
		Iter_Create - Create a new iterator value set.
		Iter_Add - Wraps Iter_AddInternal.
		Iter_SafeRemove - Wraps Iter_SafeRemoveInternal.
		Iter_Remove - Wraps Iter_RemoveInternal.
		Iter_Random - Wraps Iter_RandomInternal.
		Iter_Count - Gets the number of items in an iterator.
		Iter_Free - Wraps around Iter_FreeInternal.
		Iter_Contains - Wraps around Iter_ContainsInternal.
	API:
		-
Callbacks:
	-
Hooks:
	Iter_OnPlayerConnect - Hook for the OnPlayerConnect callback.
	Iter_OnPlayerDisconnect - Hook for the OnPlayerDisconnect callback.
	Iter_OnGameModeInit - Only exists to make the code compile correctly...
Definitions:
	-
Enums:
	-
Macros:
	-
Keywords:
	foreach - Function to loop an iterator.
Tags:
	Iterator - Declare an iterator.
Variables:
	Global:
		-
	Static:
		-
Commands:
	-
Operators:
	-
Iterators:
	Player - List of all players connected.
	Bot - List of all bots (npcs) connected.
	NPC - Alias of Bot.
	Character - All players and bots.
--------------------------------------------------------------------------------
*/

#define _FOREACH_LOCAL_VERSION 19

// Foreach is testing us.
#if defined _FOREACH_INC_TEST
	#endinput
#endif
#define _FOREACH_INC_TEST

#if !defined _samp_included
	#error "Please include a_samp or a_npc before foreach"
#endif

#if defined FOREACH_PLAYERSSTREAM_ITERATOR
	#error FOREACH_PLAYERSSTREAM_ITERATOR is deprecated, use FOREACH_I_PlayerPlayersStream
#endif

#if defined FOREACH_VEHICLESSTREAM_ITERATOR
	#error FOREACH_VEHICLESSTREAM_ITERATOR is deprecated, use FOREACH_I_PlayerVehiclesStream
#endif

#if defined FOREACH_ACTORSSTREAM_ITERATOR
	#error FOREACH_ACTORSSTREAM_ITERATOR is deprecated, use FOREACH_I_PlayerActorsStream
#endif

#if defined PlayersStream@YSII_Cg
	#error PlayersStream is deprecated, use PlayerPlayersStream
#endif

#if defined VehiclesStream@YSII_Cg
	#error VehiclesStream is deprecated, use PlayerVehiclesStream
#endif

#if defined ActorsStream@YSII_Cg
	#error ActorsStream is deprecated, use PlayerActorsStream
#endif

/*
--------------------------------------------------------------------------------
	Base defines
--------------------------------------------------------------------------------
*/

#define ITER_NONE -1

#define _Y_ITER_ARRAY: _:_Y_ITER_C0:
#define _Y_ITER_ARRAY_SIZE(%1) _:_Y_ITER_C1:_Y_ITER_C2:sizeof %1@YSII_Ag-1

#define _Y_ITER_C0:%0[%1]@YSII_%4g%3) %0@YSII_%4g[%1]%3)
#define _Y_ITER_C1:_Y_ITER_C2:%0[%1]@YSII_Ag%3) %0@YSII_Ag[]%3)
#define _Y_ITER_C2:sizeof%0(%1)@YSII_Ag-1;_:(%2=_Y_ITER_ARRAY:%3(%4)@YSII_Ag[%5])!=_Y_ITER_ARRAY_SIZE(%6);) -1;_:(%2=%3@YSII_Ag(%4,%5))!=-1;)
#define _Y_ITER_C3:%0[%1]@YSII_Cg,%2[%3]@YSII_Ag[%4]={%5} _Y_ITER_C3:%0@YSII_Cg[%1],%0@YSII_Ag[%1][%4]

forward Iter_AddInternal(&count, array[], value, size);
forward Iter_RemoveInternal(&count, array[], value, size);
forward Iter_ClearInternal(&count, array[], size);
forward Iter_OPDCInternal(playerid);

static
	bool:Iter_gIsFilterscript = false;

#if !defined FOREACH_I_Player
	#define FOREACH_I_Player 1
#endif

#if !defined FOREACH_I_Bot
	#define FOREACH_I_Bot 1
#endif

#if !defined FOREACH_I_Character
	#define FOREACH_I_Character 1
#endif

#if !defined FOREACH_I_Vehicle
	#define FOREACH_I_Vehicle 1
#endif

#if !defined FOREACH_I_Actor
	#define FOREACH_I_Actor 1
#endif

#if !defined FOREACH_I_PlayerPlayersStream
	#define FOREACH_I_PlayerPlayersStream 0
#else
	#undef FOREACH_I_PlayerPlayersStream
	#define FOREACH_I_PlayerPlayersStream 1
#endif

#if !defined FOREACH_I_PlayerVehiclesStream
	#define FOREACH_I_PlayerVehiclesStream 0
#else
	#undef FOREACH_I_PlayerVehiclesStream
	#define FOREACH_I_PlayerVehiclesStream 1
#endif

#if !defined FOREACH_I_VehiclePlayersStream
	#define FOREACH_I_VehiclePlayersStream 0
#else
	#undef FOREACH_I_VehiclePlayersStream
	#define FOREACH_I_VehiclePlayersStream 1
#endif

#if !defined FOREACH_I_PlayerActorsStream
	#define FOREACH_I_PlayerActorsStream 0
#else
	#undef FOREACH_I_PlayerActorsStream
	#define FOREACH_I_PlayerActorsStream 1
#endif

#if !defined FOREACH_I_ActorPlayersStream
	#define FOREACH_I_ActorPlayersStream 0
#else
	#undef FOREACH_I_ActorPlayersStream
	#define FOREACH_I_ActorPlayersStream 1
#endif

#if !defined FOREACH_I_PlayerInVehicle
	#define FOREACH_I_PlayerInVehicle 0
#else
	#undef FOREACH_I_PlayerInVehicle
	#define FOREACH_I_PlayerInVehicle 1
#endif

#if defined FOREACH_MULTISCRIPT
	#if FOREACH_I_Vehicle
		forward Iter_AddVehicle(vehicleid);
		forward Iter_RemoveVehicle(vehicleid);
	#endif

	#if FOREACH_I_Actor
		forward Iter_AddActor(actorid);
		forward Iter_RemoveActor(actorid);
	#endif
#endif

/*
--------------------------------------------------------------------------------
Array:
	IteratorArray
Notes:
	Creates a new iterator array start/array pair.
--------------------------------------------------------------------------------
*/

#define IteratorArray:%1[%2]<%3> %1@YSII_Cg[%2],%1@YSII_Ag[%2][%3+1]

/*
--------------------------------------------------------------------------------
Array:
	Iterator
Notes:
	Creates a new iterator start/array pair.
--------------------------------------------------------------------------------
*/

#define Iterator:%1<%2> _Y_ITER_C3:%1@YSII_Cg,%1@YSII_Ag[(%2)+1]={(%2)*2,(%2)*2-1,...}
#define iterator%0<%1> new Iterator:%0<%1>

/*
--------------------------------------------------------------------------------
Function:
	Iter_Init
Params:
	iter - Name of the iterator array to initialise.
Return:
	-
Notes:
	Wrapper for Iter_InitInternal.

native Iter_Init(IteratorArray:Name[]<>);
--------------------------------------------------------------------------------
*/

#define Iter_Init(%1) \
	Iter_InitInternal(%1@YSII_Ag,sizeof %1@YSII_Ag,sizeof %1@YSII_Ag[]-1)

/*
--------------------------------------------------------------------------------
Function:
	Iter_Add
Params:
	iter - Name of the iterator to add the data to.
	value - Value to add to the iterator.
Return:
	-
Notes:
	Wrapper for Iter_AddInternal.

native Iter_Add(Iterator:Name<>, value);
--------------------------------------------------------------------------------
*/

#define Iter_Add(%1,%2) Iter_AddInternal(_Y_ITER_ARRAY:%1@YSII_Cg,_Y_ITER_ARRAY:%1@YSII_Ag,%2,_Y_ITER_ARRAY_SIZE(%1))

/*
--------------------------------------------------------------------------------
Function:
	Iter_Free
Params:
	iter - Name of the iterator to get the first free slot in.
Return:
	-
Notes:
	Wrapper for Iter_FreeInternal.

native Iter_Free(Iterator:Name<>);
--------------------------------------------------------------------------------
*/

#define Iter_Free(%1) Iter_FreeInternal(_Y_ITER_ARRAY:%1@YSII_Ag,_Y_ITER_ARRAY_SIZE(%1))

/*
--------------------------------------------------------------------------------
Function:
	Iter_Remove
Params:
	iter - Name of the iterator to remove data from.
	value - Data to remove.
Return:
	-
Notes:
	Wrapper for Iter_RemoveInternal.

native Iter_Remove(Iterator:Name<>, value);
--------------------------------------------------------------------------------
*/

#define Iter_Remove(%1,%2) Iter_RemoveInternal(_Y_ITER_ARRAY:%1@YSII_Cg,_Y_ITER_ARRAY:%1@YSII_Ag,%2,_Y_ITER_ARRAY_SIZE(%1))

/*
--------------------------------------------------------------------------------
Function:
	Iter_Contains
Params:
	iter - Name of the iterator to check membership of.
	value - Value to check.
Return:
	-
Notes:
	Checks if the given value is in the given iterator.

native Iter_Remove(Iterator:Name<>, value);
--------------------------------------------------------------------------------
*/

#define Iter_Contains(%1,%2) Iter_ContainsInternal(_Y_ITER_ARRAY:%1@YSII_Ag,%2,_Y_ITER_ARRAY_SIZE(%1))

/*
--------------------------------------------------------------------------------
Function:
	Iter_SafeRemove
Params:
	iter - Name of the iterator to remove data from.
	value - Data to remove.
	next - Container for the pointer to the next element.
Return:
	-
Notes:
	Wrapper for Iter_SafeRemoveInternal. Common use:

	Iter_SafeRemove(iter, i, i);

native Iter_SafeRemove(Iterator:Name<>, value, &next);
--------------------------------------------------------------------------------
*/

#define Iter_SafeRemove(%1,%2,%3) Iter_SafeRemoveInternal(_Y_ITER_ARRAY:%1@YSII_Cg,_Y_ITER_ARRAY:%1@YSII_Ag,%2,%3,_Y_ITER_ARRAY_SIZE(%1))

/*
--------------------------------------------------------------------------------
Function:
	Iter_Random
Params:
	iter - Name of the iterator to get a random slot from.
Return:
	-
Notes:
	Wrapper for Iter_RandomInternal.

native Iter_Random(Iterator:Name<>);
--------------------------------------------------------------------------------
*/

#define Iter_Random(%1) Iter_RandomInternal(_Y_ITER_ARRAY:%1@YSII_Cg,_Y_ITER_ARRAY:%1@YSII_Ag,_Y_ITER_ARRAY_SIZE(%1))

/*
--------------------------------------------------------------------------------
Function:
	Iter_Count
Params:
	iter - Name of the iterator to get the number of items from.
Return:
	-
Notes:
	Returns the number of items in this iterator.

native Iter_Count(Iterator:Name<>);
--------------------------------------------------------------------------------
*/

#define Iter_Count(%1) (_Y_ITER_ARRAY:%1@YSII_Cg)

/*
--------------------------------------------------------------------------------
Function:
	Iter_Clear
Params:
	iter - Name of the iterator empty.
Return:
	-
Notes:
	Wrapper for Iter_ClearInternal.

native Iter_Clear(IteratorArray:Name[]<>);
--------------------------------------------------------------------------------
*/

#define Iter_Clear(%1) Iter_ClearInternal(_Y_ITER_ARRAY:%1@YSII_Cg,_Y_ITER_ARRAY:%1@YSII_Ag,_Y_ITER_ARRAY_SIZE(%1))

/*
--------------------------------------------------------------------------------
Function:
	Iter_Index
Params:
	iter - Name of the iterator empty.
	value - Value of the iterator element.
Return:
	-
Notes:
	Wrapper for Iter_IndexInternal.

native Iter_Index(IteratorArray:Name[]<>, index);
--------------------------------------------------------------------------------
*/

#define Iter_Index(%1,%2) Iter_IndexInternal(_Y_ITER_ARRAY:%1@YSII_Cg,_Y_ITER_ARRAY:%1@YSII_Ag,_Y_ITER_ARRAY_SIZE(%1),_Y_ITER_ARRAY_SIZE(%1),%2)

/*
--------------------------------------------------------------------------------
	Create the internal iterators.
--------------------------------------------------------------------------------
*/

#if FOREACH_I_Player
	new Iterator:Player<MAX_PLAYERS>;
#endif

#if FOREACH_I_Bot
	new Iterator:Bot<MAX_PLAYERS>;

	#define NPC@YSII_Cg Bot@YSII_Cg
	#define NPC@YSII_Ag Bot@YSII_Ag
#endif

#if FOREACH_I_Character
	new Iterator:Character<MAX_PLAYERS>;
#endif

#if FOREACH_I_Vehicle
	new Iterator:Vehicle<MAX_VEHICLES>;
#endif

#if FOREACH_I_Actor
	new Iterator:Actor<MAX_ACTORS>;
#endif

#if FOREACH_I_PlayerPlayersStream
	new Iterator:PlayerPlayersStream[MAX_PLAYERS]<MAX_PLAYERS>;
#endif

#if FOREACH_I_PlayerVehiclesStream
	new Iterator:PlayerVehiclesStream[MAX_PLAYERS]<MAX_VEHICLES>;
#endif

#if FOREACH_I_VehiclePlayersStream
	new Iterator:VehiclePlayersStream[MAX_VEHICLES]<MAX_PLAYERS>;
#endif

#if FOREACH_I_PlayerActorsStream
	new Iterator:PlayerActorsStream[MAX_PLAYERS]<MAX_ACTORS>;
#endif

#if FOREACH_I_ActorPlayersStream
	new Iterator:ActorPlayersStream[MAX_ACTORS]<MAX_PLAYERS>;
#endif

#if FOREACH_I_PlayerInVehicle
	new Iterator:PlayerInVehicle[MAX_VEHICLES]<MAX_PLAYERS>;
	static Iter_gPlayerVehicleId[MAX_PLAYERS] = {INVALID_VEHICLE_ID, ...};
#endif

/*
--------------------------------------------------------------------------------
Function:
	foreach
Params:
	data - Data to iterate through.
	as - Variable to set value to.
Return:
	-
Notes:
	Not exactly the same as PHP foreach, just iterates 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 @YSII_<gname>S for the start index and
	@YSII_<gname>A for the data array where <name> is what's entered in data.
--------------------------------------------------------------------------------
*/

#define foreach%1(%0) for(new Y_FOREACH_SECOND|||Y_FOREACH_THIRD|||%0|||)
// This allows us to use "new" multiple times - stripping off ONLY whole words.
#define new%0|||%9|||%1:%2||| %9|||%0|||%1|||%2|||

// This one is called if the new syntax is required, but the state of "new" is
// as-yet unknown. This attempts to call "%1" as a macro, if it starts with
// "new" as a whole word then it will (and will also helpfully strip off the
// "new" keyword for us).
#define Y_FOREACH_THIRD|||%0|||%1|||%2||| %1=Y_FOREACH_FIFTH|||Y_FOREACH_FOURTH|||%1:%2|||

// This is called if the "new" macro is called for a second time.
#define Y_FOREACH_FOURTH|||%0=Y_FOREACH_FIFTH|||%1|||%2||| new Y_FOREACH_SIXTH;%0|||Y_FOREACH_SEVENTH|||%2|||

// This is called when there are tags on the "new" declaration.
#define Y_FOREACH_SEVENTH|||%9Y_FOREACH_SIXTH;%0|||%1|||%2||| new %0:%1=%0:(_Y_ITER_ARRAY_SIZE(%2));_:(%1=%0:_Y_ITER_ARRAY:%2@YSII_Ag[_:%1])!=_Y_ITER_ARRAY_SIZE(%2);

// This is called when there aren't.
#define Y_FOREACH_SIXTH;%0|||Y_FOREACH_SEVENTH|||%2||| %0=_Y_ITER_ARRAY_SIZE(%2);_:(%0=_Y_ITER_ARRAY:%2@YSII_Ag[%0])!=_Y_ITER_ARRAY_SIZE(%2);

// This is called if "%1" didn't have "new" at the start.
#define Y_FOREACH_FIFTH|||Y_FOREACH_FOURTH|||%1:%2||| _Y_ITER_ARRAY_SIZE(%2);_:(%1=_Y_ITER_ARRAY:%2@YSII_Ag[%1])!=_Y_ITER_ARRAY_SIZE(%2);

// This is the old version, but DON'T add "new" because that already exists from
// the failed "new" macro call above.
#define Y_FOREACH_SECOND|||Y_FOREACH_THIRD|||%1,%2||| %2=_Y_ITER_ARRAY_SIZE(%1);_:(%2=_Y_ITER_ARRAY:%1@YSII_Ag[%2])!=_Y_ITER_ARRAY_SIZE(%1);

/*
--------------------------------------------------------------------------------
Function:
	Iter_OnFilterScriptInit
Params:
	-
Return:
	-
Notes:
	Fixes a bug where callbacks are not detected when "loadfs" is used after the
	GM has already started. If this is a GM this is just never used called.
--------------------------------------------------------------------------------
*/

public OnFilterScriptInit()
{
	Iter_gIsFilterscript = true;
	Iter_ScriptInit();

	#if defined Iter_OnFilterScriptInit
		return Iter_OnFilterScriptInit();
	#else
		return 1;
	#endif
}
#if defined _ALS_OnFilterScriptInit
	#undef OnFilterScriptInit
#else
	#define _ALS_OnFilterScriptInit
#endif

#define OnFilterScriptInit Iter_OnFilterScriptInit
#if defined Iter_OnFilterScriptInit
	forward Iter_OnFilterScriptInit();
#endif

/*
--------------------------------------------------------------------------------
Function:
	Iter_OnGameModeInit
Params:
	-
Return:
	-
Notes:
	-
--------------------------------------------------------------------------------
*/

public OnGameModeInit()
{
	if (!Iter_gIsFilterscript) {
		Iter_ScriptInit();
	}

	#if defined Iter_OnGameModeInit
		return Iter_OnGameModeInit();
	#else
		return 1;
	#endif
}
#if defined _ALS_OnGameModeInit
	#undef OnGameModeInit
#else
	#define _ALS_OnGameModeInit
#endif

#define OnGameModeInit Iter_OnGameModeInit
#if defined Iter_OnGameModeInit
	forward Iter_OnGameModeInit();
#endif

/*
--------------------------------------------------------------------------------
Function:
	Iter_ScriptInit
Params:
	-
Return:
	-
Notes:
	-
--------------------------------------------------------------------------------
*/

stock Iter_ScriptInit()
{
	#if defined GetPlayerPoolSize
		new
			LAST_PLAYER_ID = GetPlayerPoolSize() + 1,
			LAST_VEHICLE_ID = GetVehiclePoolSize() + 1,
			LAST_ACTOR_ID = GetActorPoolSize() + 1;
	#else
		#define LAST_PLAYER_ID  MAX_PLAYERS
		#define LAST_VEHICLE_ID MAX_VEHICLES
		#define LAST_ACTOR_ID   MAX_ACTORS
	#endif

	#if FOREACH_I_Player || FOREACH_I_Bot || FOREACH_I_Character
		#if FOREACH_I_Player
			Iter_Clear(Player);
		#endif

		#if FOREACH_I_Bot
			Iter_Clear(Bot);
		#endif

		#if FOREACH_I_Character
			Iter_Clear(Character);
		#endif

		for (new playerid = 0; playerid != LAST_PLAYER_ID; ++playerid) {
			if (!IsPlayerConnected(playerid)) {
				continue;
			}

			if (!IsPlayerNPC(playerid)) {
				#if FOREACH_I_Player
					Iter_Add(Player, playerid);
				#endif
			} else {
				#if FOREACH_I_Bot
					Iter_Add(Bot, playerid);
				#endif
			}

			#if FOREACH_I_Character
				Iter_Add(Character, playerid);
			#endif
		}
	#endif

	#if FOREACH_I_Vehicle
		Iter_Clear(Vehicle);

		for (new vehicleid = 1; vehicleid != LAST_VEHICLE_ID; ++vehicleid) {
			if (!GetVehicleModel(vehicleid)) {
				continue;
			}

			Iter_Add(Vehicle, vehicleid);
		}
	#endif

	#if FOREACH_I_Actor
		Iter_Clear(Actor);

		for (new actorid = 0; actorid != LAST_ACTOR_ID; ++actorid) {
			if (!IsValidActor(actorid)) {
				continue;
			}

			Iter_Add(Actor, actorid);
		}
	#endif

	#if FOREACH_I_PlayerPlayersStream
		Iter_Init(PlayerPlayersStream);

		for (new playerid = 0; playerid != LAST_PLAYER_ID; ++playerid) {
			if (!IsPlayerConnected(playerid)) {
				continue;
			}

			for (new targetid = 0; targetid != LAST_PLAYER_ID; ++targetid) {
				if (!IsPlayerStreamedIn(playerid, targetid)) {
					continue;
				}

				Iter_Add(PlayerPlayersStream[playerid], targetid);
			}
		}
	#endif

	#if FOREACH_I_PlayerVehiclesStream || FOREACH_I_VehiclePlayersStream
		#if FOREACH_I_PlayerVehiclesStream
			Iter_Init(PlayerVehiclesStream);
		#endif

		#if FOREACH_I_VehiclePlayersStream
			Iter_Init(VehiclePlayersStream);
		#endif

		for (new playerid = 0; playerid != LAST_PLAYER_ID; ++playerid) {
			if (!IsPlayerConnected(playerid)) {
				continue;
			}

			for (new vehicleid = 1; vehicleid != LAST_VEHICLE_ID; ++vehicleid) {
				if (!IsVehicleStreamedIn(vehicleid, playerid)) {
					continue;
				}

				#if FOREACH_I_PlayerVehiclesStream
					Iter_Add(PlayerVehiclesStream[playerid], vehicleid);
				#endif

				#if FOREACH_I_VehiclePlayersStream
					Iter_Add(VehiclePlayersStream[vehicleid], playerid);
				#endif
			}
		}
	#endif

	#if FOREACH_I_PlayerActorsStream || FOREACH_I_ActorPlayersStream
		#if FOREACH_I_PlayerActorsStream
			Iter_Init(PlayerActorsStream);
		#endif

		#if FOREACH_I_ActorPlayersStream
			Iter_Init(ActorPlayersStream);
		#endif

		for (new playerid = 0; playerid != LAST_PLAYER_ID; ++playerid) {
			if (!IsPlayerConnected(playerid)) {
				continue;
			}

			for (new actorid = 0; actorid != LAST_ACTOR_ID; ++actorid) {
				if (!IsActorStreamedIn(actorid, playerid)) {
					continue;
				}

				#if FOREACH_I_PlayerActorsStream
					Iter_Add(PlayerActorsStream[playerid], actorid);
				#endif

				#if FOREACH_I_ActorPlayersStream
					Iter_Add(ActorPlayersStream[actorid], playerid);
				#endif
			}
		}
	#endif
	
	#if FOREACH_I_PlayerInVehicle
		Iter_Init(PlayerInVehicle);

		for (new playerid = 0; playerid != LAST_PLAYER_ID; ++playerid) {
			if (!IsPlayerConnected(playerid)) {
				continue;
			}

			for (new vehicleid = 1; vehicleid != LAST_VEHICLE_ID; ++vehicleid) {
				if (!IsPlayerInVehicle(playerid, vehicleid)) {
					continue;
				}

				Iter_Add(PlayerInVehicle[vehicleid], playerid);
			}
		}
	#endif

	#pragma unused LAST_PLAYER_ID, LAST_VEHICLE_ID, LAST_ACTOR_ID
}

/*
	CHARACTERS
*/

#if FOREACH_I_Player || FOREACH_I_Bot || FOREACH_I_Character

	/*
	--------------------------------------------------------------------------------
	Function:
		Iter_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 @YSII_EgotS and
		@YSII_CgharacterS were the same and @YSII_EgotC and @YSII_CgharacterC were the
		same). Adding print statements which reference these variables seem to fix
		the problem, and I have tried to make sure that the values will never actually
		get printed.
	--------------------------------------------------------------------------------
	*/

	public OnPlayerConnect(playerid)
	{
		if (!IsPlayerNPC(playerid)) {
			#if FOREACH_I_Player
				Iter_Add(Player, playerid);
			#endif
		} else {
			#if FOREACH_I_Bot
				Iter_Add(Bot, playerid);
			#endif
		}

		#if FOREACH_I_Character
			Iter_Add(Character, playerid);
		#endif

		#if defined Iter_OnPlayerConnect
			return Iter_OnPlayerConnect(playerid);
		#else
			return 1;
		#endif
	}
	#if defined _ALS_OnPlayerConnect
		#undef OnPlayerConnect
	#else
		#define _ALS_OnPlayerConnect
	#endif

	#define OnPlayerConnect Iter_OnPlayerConnect
	#if defined Iter_OnPlayerConnect
		forward Iter_OnPlayerConnect(playerid);
	#endif

	/*
	--------------------------------------------------------------------------------
	Function:
		Iter_OnPlayerDisconnect
	Params:
		playerid - Player who left.
	Return:
		-
	Notes:
		Removes a player from the loop data. No longer uses "hook" to ENSURE that
		this is always last. Previously I think that the order of evaluation in
		y_hooks meant that this got called before the user "OnPlayerDisconnect".
	--------------------------------------------------------------------------------
	*/

	public OnPlayerDisconnect(playerid, reason)
	{
	#if defined Iter_OnPlayerDisconnect
		Iter_OnPlayerDisconnect(playerid, reason);
	#endif

		SetTimerEx("Iter_OPDCInternal", 0, false, "i", playerid);
		return 1;
	}
	#if defined _ALS_OnPlayerDisconnect
		#undef OnPlayerDisconnect
	#else
		#define _ALS_OnPlayerDisconnect
	#endif

	#define OnPlayerDisconnect Iter_OnPlayerDisconnect
	#if defined Iter_OnPlayerDisconnect
		forward Iter_OnPlayerDisconnect(playerid, reason);
	#endif

	/*
	--------------------------------------------------------------------------------
	Function:
		Iter_OPDCInternal
	Params:
		playerid - Player who left.
	Return:
		-
	Notes:
		Called AFTER "OnPlayerDisconnect" so that using "Kick" inside a "foreach"
		loop does not crash the server due to an OOB error.
	--------------------------------------------------------------------------------
	*/

	public Iter_OPDCInternal(playerid)
	{
		if (IsPlayerConnected(playerid)) {
			return;
		}

		if (!IsPlayerNPC(playerid)) {
			#if FOREACH_I_Player
				Iter_Remove(Player, playerid);
			#endif
		} else {
			#if FOREACH_I_Bot
				Iter_Remove(Bot, playerid);
			#endif
		}

		#if FOREACH_I_Character
			Iter_Remove(Character, playerid);
		#endif
		
		#if FOREACH_I_PlayerInVehicle
			if (Iter_gPlayerVehicleId[playerid] != INVALID_VEHICLE_ID) {
				Iter_Remove(PlayerInVehicle[Iter_gPlayerVehicleId[playerid]], playerid);
				Iter_gPlayerVehicleId[playerid] = INVALID_VEHICLE_ID;
			}
		#endif

		#if FOREACH_I_PlayerPlayersStream
			Iter_Clear(PlayerPlayersStream[playerid]);
		#endif

		#if FOREACH_I_PlayerVehiclesStream
			Iter_Clear(PlayerVehiclesStream[playerid]);
		#endif

		#if FOREACH_I_PlayerActorsStream
			Iter_Clear(PlayerActorsStream[playerid]);
		#endif
	}

#endif

/*
	CHARACTERS ENDS
*/

/*
	VEHICLES
*/

#if FOREACH_I_Vehicle

	/*
		Iter_CreateVehicle
	*/

	stock Iter_CreateVehicle(modelid, Float:x, Float:y, Float:z, Float:angle, color1, color2, respawn_delay, addsiren = 0)
	{
		new
			ret = CreateVehicle(modelid, x, y, z, angle, color1, color2, respawn_delay, addsiren);

		if (ret != INVALID_VEHICLE_ID && ret != 0) {
			#if defined FOREACH_MULTISCRIPT
				CallRemoteFunction("Iter_AddVehicle", "i", ret);
			#else
				Iter_Add(Vehicle, ret);
			#endif
		}

		return ret;
	}
	#if defined _ALS_CreateVehicle
		#undef CreateVehicle
	#else
		#define _ALS_CreateVehicle
	#endif

	#define CreateVehicle Iter_CreateVehicle

	/*
		Iter_AddStaticVehicle
	*/

	stock Iter_AddStaticVehicle(modelid, Float:spawn_x, Float:spawn_y, Float:spawn_z, Float:angle, color1, color2)
	{
		new
			ret = AddStaticVehicle(modelid, spawn_x, spawn_y, spawn_z, angle, color1, color2);

		if (ret != INVALID_VEHICLE_ID) {
			#if defined FOREACH_MULTISCRIPT
				CallRemoteFunction("Iter_AddVehicle", "i", ret);
			#else
				Iter_Add(Vehicle, ret);
			#endif
		}

		return ret;
	}
	#if defined _ALS_AddStaticVehicle
		#undef AddStaticVehicle
	#else
		#define _ALS_AddStaticVehicle
	#endif

	#define AddStaticVehicle Iter_AddStaticVehicle

	/*
		Iter_AddStaticVehicleEx
	*/

	stock Iter_AddStaticVehicleEx(modelid, Float:spawn_x, Float:spawn_y, Float:spawn_z, Float:angle, color1, color2, respawn_delay, addsiren = 0)
	{
		new
			ret = AddStaticVehicleEx(modelid, spawn_x, spawn_y, spawn_z, angle, color1, color2, respawn_delay, addsiren);

		if (ret != INVALID_VEHICLE_ID) {
			#if defined FOREACH_MULTISCRIPT
				CallRemoteFunction("Iter_AddVehicle", "i", ret);
			#else
				Iter_Add(Vehicle, ret);
			#endif
		}

		return ret;
	}
	#if defined _ALS_AddStaticVehicleEx
		#undef AddStaticVehicleEx
	#else
		#define _ALS_AddStaticVehicleEx
	#endif

	#define AddStaticVehicleEx Iter_AddStaticVehicleEx

	/*
		DestroyVehicleSafe
	*/

	stock DestroyVehicleSafe(&vehicleid)
	{
		new success = DestroyVehicle(vehicleid);
		#if defined FOREACH_MULTISCRIPT
			vehicleid = CallRemoteFunction("Iter_RemoveVehicle", "i", vehicleid);
		#else
			Iter_SafeRemove(Vehicle, vehicleid, vehicleid);
		#endif
		return success;
	}

	/*
		Iter_DestroyVehicle
	*/

	stock Iter_DestroyVehicle(vehicleid)
	{
		#if defined FOREACH_MULTISCRIPT
			CallRemoteFunction("Iter_RemoveVehicle", "i", vehicleid);
		#else
			Iter_Remove(Vehicle, vehicleid);
		#endif
		return DestroyVehicle(vehicleid);
	}
	#if defined _ALS_DestroyVehicle
		#undef DestroyVehicle
	#else
		#define _ALS_DestroyVehicle
	#endif

	#define DestroyVehicle Iter_DestroyVehicle

	/*
		Iter_AddVehicle
	*/

	#if defined FOREACH_MULTISCRIPT

		public Iter_AddVehicle(vehicleid)
		{
			return Iter_Add(Vehicle, vehicleid);
		}

	#endif

	/*
		Iter_RemoveVehicle
	*/

	#if defined FOREACH_MULTISCRIPT

		public Iter_RemoveVehicle(vehicleid)
		{
			Iter_SafeRemove(Vehicle, vehicleid, vehicleid);
			return vehicleid;
		}

	#endif

#endif

/*
	VEHICLES ENDS
*/

/*
	ACTORS
*/

#if FOREACH_I_Actor

	/*
		Iter_CreateActor
	*/

	stock Iter_CreateActor(modelid, Float:X, Float:Y, Float:Z, Float:Rotation)
	{
		new
			ret = CreateActor(modelid, X, Y, Z, Rotation);
		if (ret != INVALID_ACTOR_ID) {
			#if defined FOREACH_MULTISCRIPT
				CallRemoteFunction("Iter_AddActor", "i", ret);
			#else
				Iter_Add(Actor, ret);
			#endif
		}
		return ret;
	}
	#if defined _ALS_CreateActor
		#undef CreateActor
	#else
		#define _ALS_CreateActor
	#endif

	#define CreateActor Iter_CreateActor

	/*
		DestroyActorSafe
	*/

	stock DestroyActorSafe(&actorid)
	{
		new success = DestroyActor(actorid);
		#if defined FOREACH_MULTISCRIPT
			actorid = CallRemoteFunction("Iter_RemoveActor", "i", actorid);
		#else
			Iter_SafeRemove(Actor, actorid, actorid);
		#endif
		return success;
	}

	/*
		Iter_DestroyActor
	*/

	stock Iter_DestroyActor(actorid)
	{
		#if defined FOREACH_MULTISCRIPT
			CallRemoteFunction("Iter_RemoveActor", "i", actorid);
		#else
			Iter_Remove(Actor, actorid);
		#endif
		return DestroyActor(actorid);
	}
	#if defined _ALS_DestroyActor
		#undef DestroyActor
	#else
		#define _ALS_DestroyActor
	#endif

	#define DestroyActor Iter_DestroyActor

	/*
		Iter_AddActor
	*/

	#if defined FOREACH_MULTISCRIPT

		public Iter_AddActor(actorid)
		{
			return Iter_Add(Actor, actorid);
		}

	#endif

	/*
		Iter_RemoveActor
	*/

	#if defined FOREACH_MULTISCRIPT

		public Iter_RemoveActor(actorid)
		{
			Iter_SafeRemove(Actor, actorid, actorid);
			return actorid;
		}

	#endif

#endif

/*
	ACTORS ENDS
*/

/*
	PLAYERS STREAM
*/

#if FOREACH_I_PlayerPlayersStream

	/*
		Iter_OnPlayerStreamIn
	*/

	public OnPlayerStreamIn(playerid, forplayerid)
	{
		Iter_Add(PlayerPlayersStream[playerid], forplayerid);

		#if defined Iter_OnPlayerStreamIn
			return Iter_OnPlayerStreamIn(playerid, forplayerid);
		#else
			return 1;
		#endif
	}
	#if defined _ALS_OnPlayerStreamIn
		#undef OnPlayerStreamIn
	#else
		#define _ALS_OnPlayerStreamIn
	#endif

	#define OnPlayerStreamIn Iter_OnPlayerStreamIn
	#if defined Iter_OnPlayerStreamIn
		forward Iter_OnPlayerStreamIn(playerid, forplayerid);
	#endif

	/*
		Iter_OnPlayerStreamOut
	*/

	public OnPlayerStreamOut(playerid, forplayerid)
	{
		Iter_Remove(PlayerPlayersStream[playerid], forplayerid);

		#if defined Iter_OnPlayerStreamOut
			return Iter_OnPlayerStreamOut(playerid, forplayerid);
		#else
			return 1;
		#endif
	}
	#if defined _ALS_OnPlayerStreamOut
		#undef OnPlayerStreamOut
	#else
		#define _ALS_OnPlayerStreamOut
	#endif

	#define OnPlayerStreamOut Iter_OnPlayerStreamOut
	#if defined Iter_OnPlayerStreamOut
		forward Iter_OnPlayerStreamOut(playerid, forplayerid);
	#endif

#endif

/*
	PLAYERS STREAM ENDS
*/

/*
	VEHICLES STREAM
*/

#if FOREACH_I_PlayerVehiclesStream || FOREACH_I_VehiclePlayersStream

	/*
		Iter_OnVehicleStreamIn
	*/

	public OnVehicleStreamIn(vehicleid, forplayerid)
	{
		#if FOREACH_I_PlayerVehiclesStream
			Iter_Add(PlayerVehiclesStream[forplayerid], vehicleid);
		#endif

		#if FOREACH_I_VehiclePlayersStream
			Iter_Add(VehiclePlayersStream[vehicleid], forplayerid);
		#endif

		#if defined Iter_OnVehicleStreamIn
			return Iter_OnVehicleStreamIn(vehicleid, forplayerid);
		#else
			return 1;
		#endif
	}
	#if defined _ALS_OnVehicleStreamIn
		#undef OnVehicleStreamIn
	#else
		#define _ALS_OnVehicleStreamIn
	#endif

	#define OnVehicleStreamIn Iter_OnVehicleStreamIn
	#if defined Iter_OnVehicleStreamIn
		forward Iter_OnVehicleStreamIn(vehicleid, forplayerid);
	#endif

	/*
		Iter_OnVehicleStreamOut
	*/

	public OnVehicleStreamOut(vehicleid, forplayerid)
	{
		#if FOREACH_I_PlayerVehiclesStream
			Iter_Remove(PlayerVehiclesStream[forplayerid], vehicleid);
		#endif

		#if FOREACH_I_VehiclePlayersStream
			Iter_Remove(VehiclePlayersStream[vehicleid], forplayerid);
		#endif

		#if defined Iter_OnVehicleStreamOut
			return Iter_OnVehicleStreamOut(vehicleid, forplayerid);
		#else
			return 1;
		#endif
	}
	#if defined _ALS_OnVehicleStreamOut
		#undef OnVehicleStreamOut
	#else
		#define _ALS_OnVehicleStreamOut
	#endif

	#define OnVehicleStreamOut Iter_OnVehicleStreamOut
	#if defined Iter_OnVehicleStreamOut
		forward Iter_OnVehicleStreamOut(vehicleid, forplayerid);
	#endif

#endif

/*
	VEHICLES STREAM ENDS
*/

/*
	ACTORS STREAM
*/

#if FOREACH_I_PlayerActorsStream || FOREACH_I_ActorPlayersStream

	/*
		Iter_OnActorStreamIn
	*/

	public OnActorStreamIn(actorid, forplayerid)
	{
		#if FOREACH_I_PlayerActorsStream
			Iter_Add(PlayerActorsStream[forplayerid], actorid);
		#endif

		#if FOREACH_I_ActorPlayersStream
			Iter_Add(ActorPlayersStream[actorid], forplayerid);
		#endif

		#if defined Iter_OnActorStreamIn
			return Iter_OnActorStreamIn(actorid, forplayerid);
		#else
			return 1;
		#endif
	}
	#if defined _ALS_OnActorStreamIn
		#undef OnActorStreamIn
	#else
		#define _ALS_OnActorStreamIn
	#endif

	#define OnActorStreamIn Iter_OnActorStreamIn
	#if defined Iter_OnActorStreamIn
		forward Iter_OnActorStreamIn(actorid, forplayerid);
	#endif

	/*
		Iter_OnActorStreamOut
	*/

	public OnActorStreamOut(actorid, forplayerid)
	{
		#if FOREACH_I_PlayerActorsStream
			Iter_Remove(PlayerActorsStream[forplayerid], actorid);
		#endif

		#if FOREACH_I_ActorPlayersStream
			Iter_Remove(ActorPlayersStream[actorid], forplayerid);
		#endif

		#if defined Iter_OnActorStreamOut
			return Iter_OnActorStreamOut(actorid, forplayerid);
		#else
			return 1;
		#endif
	}
	#if defined _ALS_OnActorStreamOut
		#undef OnActorStreamOut
	#else
		#define _ALS_OnActorStreamOut
	#endif

	#define OnActorStreamOut Iter_OnActorStreamOut
	#if defined Iter_OnActorStreamOut
		forward Iter_OnActorStreamOut(actorid, forplayerid);
	#endif

#endif

/*
	ACTORS STREAM ENDS
*/

/*
	PLAYERS IN VEHICLE
*/

#if FOREACH_I_PlayerInVehicle

	/*
		Iter_OnPlayerStateChange
	*/

	public OnPlayerStateChange(playerid, newstate, oldstate)
	{
		if (newstate == PLAYER_STATE_DRIVER || newstate == PLAYER_STATE_PASSENGER) {
			Iter_gPlayerVehicleId[playerid] = GetPlayerVehicleID(playerid);
			Iter_Add(PlayerInVehicle[Iter_gPlayerVehicleId[playerid]], playerid);
		} else if (oldstate == PLAYER_STATE_DRIVER || oldstate == PLAYER_STATE_PASSENGER) {
			if (Iter_gPlayerVehicleId[playerid] != INVALID_VEHICLE_ID) {
				Iter_Remove(PlayerInVehicle[Iter_gPlayerVehicleId[playerid]], playerid);
				Iter_gPlayerVehicleId[playerid] = INVALID_VEHICLE_ID;
			}
		}

		#if defined Iter_OnPlayerStateChange
			return Iter_OnPlayerStateChange(playerid, newstate, oldstate);
		#else
			return 1;
		#endif
	}
	#if defined _ALS_OnPlayerStateChange
		#undef OnPlayerStateChange
	#else
		#define _ALS_OnPlayerStateChange
	#endif

	#define OnPlayerStateChange Iter_OnPlayerStateChange
	#if defined Iter_OnPlayerStateChange
		forward Iter_OnPlayerStateChange(playerid, newstate, oldstate);
	#endif

#endif

/*
	PLAYERS IN VEHECLE ENDS
*/

/*
--------------------------------------------------------------------------------
Function:
	Iter_RandomInternal
Params:
	count - Number of items in the iterator.
	array[] - Iterator data.
	size - Size of the iterator.
Return:
	-
Notes:
	Returns a random value from an iterator.
--------------------------------------------------------------------------------
*/

stock Iter_RandomInternal(count, const array[], size)
{
	if (count == 0) {
		return ITER_NONE;
	}
	new
		rnd = random(count),
		cur = array[size];
	while (cur != size) {
		if (rnd-- == 0) {
			return cur;
		}
		cur = array[cur];
	}
	return ITER_NONE;
}

/*
--------------------------------------------------------------------------------
Function:
	Iter_FreeInternal
Params:
	array[] - Iterator data.
	size - Size of the iterator.
Return:
	-
Notes:
	Finds the first free slot in the iterator. Iterators now HAVE to be
	sorted for this function to work correctly as it uses that fact to decide
	whether a slot is unused or the last one. If you want to use the slot
	straight after finding it the iterator will need to re-find it to add in
	the data.
--------------------------------------------------------------------------------
*/

stock Iter_FreeInternal(const array[], size)
{
	for (new i = 0; i != size; ++i) {
		if (array[i] > size) {
			return i;
		}
	}
	return ITER_NONE;
}

/*
--------------------------------------------------------------------------------
Function:
	Iter_AddInternal
Params:
	&count - Number of items in the iterator.
	array[] - Iterator data.
	value - Item to add.
	size - Size of the iterator.
Return:
	-
Notes:
	Adds a value to a given iterator set. Now detects when you try and add the
	last item multiple times, as well as all the other items. Now simplified even
	further with the new internal representation.
--------------------------------------------------------------------------------
*/

stock Iter_AddInternal(&count, array[], value, size)
{
	if (0 <= value < size && array[value] > size) {
		new
			last = size,
			next = array[last];
		while (next < value) {
			last = next;
			next = array[last];
		}
		array[last] = value;
		array[value] = next;
		++count;
		return 1;
	}
	return 0;
}

/*
--------------------------------------------------------------------------------
Function:
	Iter_RemoveInternal
Params:
	&count - Number of items in the iterator.
	array[] - Iterator data.
	value - Item to remove.
	size - Size of the iterator.
Return:
	-
Notes:
	Removes a value from an iterator.
--------------------------------------------------------------------------------
*/

stock Iter_RemoveInternal(&count, array[], value, size)
{
	new
		last;
	return Iter_SafeRemoveInternal(count, array, value, last, size);
}

/*
--------------------------------------------------------------------------------
Function:
	Iter_SafeRemoveInternal
Params:
	&count - Number of items in the iterator.
	array[] - Iterator data.
	value - Item to remove.
	&last - Pointer in which to store the last pointer.
	size - Size of the iterator.
Return:
	-
Notes:
	Removes a value from an iterator safely.
--------------------------------------------------------------------------------
*/

stock Iter_SafeRemoveInternal(&count, array[], value, &last, size)
{
	if (0 <= value < size && array[value] <= size) {
		last = size;
		new
			next = array[last];
		while (next < size) {
			if (next == value) {
				array[last] = array[value];
				array[value] = size + 1;
				--count;
				return 1;
			}
			last = next;
			next = array[last];
		}
	}
	return 0;
}

/*
--------------------------------------------------------------------------------
Function:
	Iter_ContainsInternal
Params:
	array[] - Iterator data.
	value - Item to check.
	size - Size of the iterator.
Return:
	-
Notes:
	Checks if this item is in the iterator.
--------------------------------------------------------------------------------
*/

stock Iter_ContainsInternal(const array[], value, size)
{
	return 0 <= value < size && array[value] <= size;
}

/*
--------------------------------------------------------------------------------
Function:
	Iter_ClearInternal
Params:
	&count - Number of items in the iterator.
	array[] - Iterator data.
	size - Size of the iterator.
Return:
	-
Notes:
	Resets an iterator.
--------------------------------------------------------------------------------
*/

stock Iter_ClearInternal(&count, array[], size)
{
	for (new i = 0, t = size + 1; i < size; ++i) {
		array[i] = t;
	}
	array[size] = size;
	count = 0;
}

/*-------------------------------------------------------------------------*//**
 * <param name="count">Number of items in the iterator.</param>
 * <param name="array">iterator data.</param>
 * <param name="start">Array start index.</param>
 * <param name="size">Array size.</param>
 * <param name="index">Index to find Nth value.</param>
 * <param name="wrap">Keep going around until a value is found?</param>
 * <remarks>
 *  Allows you to find the Nth value in the iterator.  DO NOT call this in a
 *  loop to get all values - that totally defeats the purpose of "foreach", just
 *  use a normal "foreach" loop with an index counter for that case.
 * </remarks>
 *//*------------------------------------------------------------------------**/

stock Iter_IndexInternal(count, const array[], start, size, index)
{
	// If there are no elements in the iterator, we can't ever return the Nth
	// item.  Also if the parameters are invalid.
	if (index < 0 || start < size || array[start] >= size) {
		return ITER_NONE;
	}
	// We could wrap around in the loop (it would work), but it is better to set
	// the limit first.
	if (index >= count) {
		return ITER_NONE;
	}
	start = array[start];
	while (index--) {
		start = array[start];
	}
	return start;
}

/*
--------------------------------------------------------------------------------
Function:
	Iter_InitInternal
Params:
	array[][] - Iterator array to initialise.
	s0 - Size of first dimension.
	s1 - Size of second dimension.
Return:
	-
Notes:
	Multi-dimensional arrays can not be initialised at compile time, so need to be
	done at run time, which is slightly annoying.
--------------------------------------------------------------------------------
*/

stock Iter_InitInternal(arr[][], s0, s1)
{
	for (new i = 0, t = s1 + 1; i < s0; ++i) {
		for (new j = 0; j < s1; ++j) {
			arr[i][j] = t;
		}
		arr[i][s1] = s1;
	}
}

/*
--------------------------------------------------------------------------------
Function:
	Iter_PrevInternal
Params:
	array[] - Iterator data.
	size - Size of the iterator.
	slot - The current slot.
Return:
	-
Notes:
	Gets the element in an iterator that points to the current element.
--------------------------------------------------------------------------------
*/

stock Iter_PrevInternal(const array[], size, slot)
{
	if (0 <= slot <= size && array[slot] <= size) {
		for (new last = slot; last--; ) {
			if (array[last] == slot) {
				return last;
			}
		}
	}
	return size;
}

/*
--------------------------------------------------------------------------------
Function:
	Iter_Begin
Params:
	iter - Name of the iterator to get the start of.
Return:
	-
Notes:
	Gets a point BEFORE the start of the iterator (the theoretical beginning).
--------------------------------------------------------------------------------
*/

#define Iter_Begin(%1) (_Y_ITER_ARRAY_SIZE(%1))
#define Iter_Start Iter_Begin

/*
--------------------------------------------------------------------------------
Function:
	Iter_End
Params:
	iter - Name of the iterator to
Return:
	-
Notes:
	Gets a point AFTER the end of the iterator (think "MAX_PLAYERS").
--------------------------------------------------------------------------------
*/

#define Iter_End(%1) (_Y_ITER_ARRAY_SIZE(%1))
#define Iter_Finish Iter_End

/*
--------------------------------------------------------------------------------
Function:
	Iter_First
Params:
	iter - Name of the iterator to
Return:
	-
Notes:
	Gets the first element in an iterator.
--------------------------------------------------------------------------------
*/

#define Iter_First(%1) (_Y_ITER_ARRAY:%1@YSII_Ag[_Y_ITER_ARRAY_SIZE(%1)])

/*
--------------------------------------------------------------------------------
Function:
	Iter_Last
Params:
	iter - Name of the iterator to
Return:
	-
Notes:
	Gets the last element in an iterator.
--------------------------------------------------------------------------------
*/

#define Iter_Last(%1) Iter_PrevInternal(_Y_ITER_ARRAY:%1@YSII_Ag,_Y_ITER_ARRAY_SIZE(%1),_Y_ITER_ARRAY_SIZE(%1))

/*
--------------------------------------------------------------------------------
Function:
	Iter_Next
Params:
	iter - Name of the iterator to
Return:
	-
Notes:
	Gets the element in an interator after the current one.
--------------------------------------------------------------------------------
*/

#define Iter_Next(%1,%2) (_Y_ITER_ARRAY:%1@YSII_Ag[(%2)])

/*
--------------------------------------------------------------------------------
Function:
	Iter_Prev
Params:
	iter - Name of the iterator to
Return:
	-
Notes:
	Gets the element in an iterator before the current one. Slow.
--------------------------------------------------------------------------------
*/

#define Iter_Prev(%1,%2) Iter_PrevInternal(_Y_ITER_ARRAY:%1@YSII_Ag,_Y_ITER_ARRAY_SIZE(%1),(%2))
#define Iter_Previous Iter_Prev
