// This include file holds all functions for doing convoys
forward Convoy_Timer(Convoy);

// This function is called only once and is used to setup the textdraws and default data for convoys
Convoys_Init()
{
	for (new i; i < MAX_CONVOYS; i++)
	{
		AConvoys[i][ConvoyTextLeader] = TextDrawCreate(320.0, 1.0, " "); // Create the textdraw for the leader
		TextDrawSetShadow(AConvoys[i][ConvoyTextLeader], 1); // Reduce the shadow to 1
		TextDrawAlignment(AConvoys[i][ConvoyTextLeader], 2); // Align the convoy-infobar to the center for the leader
		TextDrawUseBox(AConvoys[i][ConvoyTextLeader], 1); // Set the missiontext to display inside a box
		TextDrawBoxColor(AConvoys[i][ConvoyTextLeader] ,0x00000066); // Set the box color of the missiontext

		AConvoys[i][ConvoyTextMember] = TextDrawCreate(320.0, 1.0, " "); // Create the textdraw for the members
		TextDrawSetShadow(AConvoys[i][ConvoyTextLeader], 1); // Reduce the shadow to 1
		TextDrawAlignment(AConvoys[i][ConvoyTextMember], 2); // Align the convoy-infobar to the center for the members
		TextDrawUseBox(AConvoys[i][ConvoyTextMember], 1); // Set the missiontext to display inside a box
		TextDrawBoxColor(AConvoys[i][ConvoyTextMember] ,0x00000066); // Set the box color of the missiontext
	}
}

// This function is used when a player selected an empty convoy-slot (the player will start the convoy and become the leader)
Convoy_Create(playerid, Convoy)
{
	// Setup local variables
	new Name[24], Msg[128];

	// Get the name of the player
	GetPlayerName(playerid, Name, sizeof(Name));

	// Check if the player is allowed to create a convoy (he must be a trucker without a job and not part of a convoy yet)
	if (Convoy_PlayerAllowed(playerid))
	{
		// Set status of the convoy to "open"
		AConvoys[Convoy][Status] = CONVOY_OPEN;
		// Set the player as leader of the convoy
		AConvoys[Convoy][Members][0] = playerid;
		// Set the player as a member of a convoy
		APlayerData[playerid][InConvoy] = true;
		APlayerData[playerid][ConvoyID] = Convoy;

		// Set all other member-indices to "-1" (no player yet)
		for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
		    AConvoys[Convoy][Members][i] = -1;
		// Start the convoy-timer (this timer updates and checks everything for the whole convoy), it runs every second
		AConvoys[Convoy][ConvoyTimer] = SetTimerEx("Convoy_Timer", 1000, true, "i", Convoy);

		// Let all players know that this player wants to start a convoy
		format(Msg, 128, TXT_PlayerStartsConvoy, Name);
		SendClientMessageToAll(0xFFFFFFFF, Msg);
	}
}



// This function is used to let another player join a convoy
Convoy_Join(playerid, Convoy)
{
	// Setup local variables
	new Name[24], Msg[128];

	// Get the name of the player
	GetPlayerName(playerid, Name, sizeof(Name));

	// Check if the player is allowed to join the convoy (he must be a trucker without a job and not part of a convoy yet)
	if (Convoy_PlayerAllowed(playerid))
	{
	    // Check if the convoy isn't full already
		if (Convoy_CountMembers(Convoy) < CONVOY_MAX_MEMBERS)
		{
			// Inform all the members of the convoy that this player joined the convoy
			format(Msg, 128, TXT_PlayerJoinedConvoy, Name);
			Convoy_SendMessage(Convoy, Msg);
			// Inform the player that he joined the convoy
			SendClientMessage(playerid, 0xFFFFFFFF, TXT_YouJoinedConvoy);

			// Set the player as member of the convoy (find a free spot for this player)
			for (new i; i < CONVOY_MAX_MEMBERS; i++)
			{
			    if (AConvoys[Convoy][Members][i] == -1) // Check if this member-spot is empty
				{
					AConvoys[Convoy][Members][i] = playerid; // Put the player in this member-spot
					break; // Stop the for-loop
				}
			}
			// Set the player as a member of a convoy
			APlayerData[playerid][InConvoy] = true;
			APlayerData[playerid][ConvoyID] = Convoy;

			// Set the convoystatus as "Full" if all member-spots are occupied
			if (Convoy_CountMembers(Convoy) == CONVOY_MAX_MEMBERS)
			    AConvoys[Convoy][Status] = CONVOY_FULL;

			// Also update the player's missiontext to inform the player that he must wait for the leader to start a job
			TextDrawSetString(APlayerData[playerid][MissionText], TXT_WaitingLeaderJob);
		}
		else
		    SendClientMessage(playerid, 0xFFFFFFFF, TXT_ConvoyFull);
	}
}



// This function is used to let a player leave a convoy (when he disconnects, finishes the convoy, when he dies, ...)
Convoy_Leave(playerid)
{
	// Setup local variables
	new Convoy, NumMembers, MemberID;

	// First theck if the player is part of a convoy
	if (APlayerData[playerid][InConvoy] == false)
	    return 1; // Exit the function if the player isn't part of a convoy

	// Get the convoy-id from the player
	Convoy = APlayerData[playerid][ConvoyID];

	// Get the number of members in the convoy
	NumMembers = Convoy_CountMembers(Convoy);

	// If there is only 1 member in the convoy (convoy will have no members if this one leaves), cancel the convoy
	if (NumMembers == 1)
	{
		// Cancel the convoy
		Convoy_Cancel(Convoy);
		// Exit the function
		return 1;
	}

	// Remove the player from the convoy
	APlayerData[playerid][InConvoy] = false;
	APlayerData[playerid][ConvoyID] = 0;
	// Hide both convoy-textdraws (for leader and members) as the member leaves the convoy
	TextDrawHideForPlayer(playerid, AConvoys[Convoy][ConvoyTextLeader]);
	TextDrawHideForPlayer(playerid, AConvoys[Convoy][ConvoyTextMember]);
	// Also update the player's missiontext to inform the player that he can start a job now (if there isn't a job started)
	if (APlayerData[playerid][JobStarted] == false)
		TextDrawSetString(APlayerData[playerid][MissionText], Trucker_NoJobText);

    // If the player is the leader
	if (AConvoys[Convoy][Members][0] == playerid)
	{
		// Set another player as leader
		for (new j = 1; j < CONVOY_MAX_MEMBERS; j++)
		{
			// Get the playerid of the member
			MemberID = AConvoys[Convoy][Members][j];
			if (MemberID != -1) // If a valid playerid is found
			{
				// Hide the member-textdraw as the member just became the leader
				TextDrawHideForPlayer(MemberID, AConvoys[Convoy][ConvoyTextMember]);
                // Set this member as leader
				AConvoys[Convoy][Members][0] = MemberID;
                // Clear this index, or the player would be twice in the same convoy
				AConvoys[Convoy][Members][j] = -1;
                // Exit the function
				return 1;
			}
		}
	}
	else // The leaving player isn't the leader
	{
		// Find the player inside the convoy
		for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
		{
			// If the current player is this player
			if (AConvoys[Convoy][Members][i] == playerid)
			{
			    // Reset the stored playerid in the convoy
			    AConvoys[Convoy][Members][i] = -1;
				// Stop the job for this player (all data gets cleared, including the missiontext)
				Trucker_EndJob(playerid);

				return 1; // Exit the function
			}
		}
	}

	return 1;
}

// This function cancels the convoy, kicking every member in it
Convoy_Cancel(Convoy)
{
	// Setup local variables
	new MemberID;

	// Loop through all members
	for (new i; i < CONVOY_MAX_MEMBERS; i++)
	{
		// Get the member's playerid
	    MemberID = AConvoys[Convoy][Members][i];
		// If a valid playerid is found
		if (MemberID != -1)
		{
			// Remove the player from the convoy
			APlayerData[MemberID][InConvoy] = false;
			APlayerData[MemberID][ConvoyID] = 0;
			// Hide both convoy-textdraws (for leader and members)
   	        TextDrawHideForPlayer(MemberID, AConvoys[Convoy][ConvoyTextLeader]);
   	        TextDrawHideForPlayer(MemberID, AConvoys[Convoy][ConvoyTextMember]);
			// Cancel the trucker-job
			Trucker_EndJob(MemberID);
		    // Reset the stored playerid in the convoy
		    AConvoys[Convoy][Members][i] = -1;
			// Send the member a message that the convoy was cancelled by the leader
			SendClientMessage(MemberID, 0xFFFFFFFF, TXT_LeaderCancelledConvoy);
		}
	}

	// Clear all the data of the convoy
	AConvoys[Convoy][LoadID] = 0;
	AConvoys[Convoy][Location1] = 0;
	AConvoys[Convoy][Location2] = 0;
	AConvoys[Convoy][Status] = CONVOY_EMPTY;
	AConvoys[Convoy][ConvoyStep] = 0;
	AConvoys[Convoy][TrailerModel] = 0;
	AConvoys[Convoy][LeaderInformedTrailers] = false;
	// Kill the convoy-timer
	KillTimer(AConvoys[Convoy][ConvoyTimer]);
}



// This function is called for every member when the leader of the convoy started a job (missiontext is updated, loading-checkpoint is created, ...
Convoy_StartMemberJob(playerid, Convoy)
{
    // Setup local variables
	new StartLoc[50], EndLoc[50], Load[50], RouteText[255], Float:x, Float:y, Float:z, LoadMsg[128];

	// Job has started
	APlayerData[playerid][JobStarted] = true;
	// Copy the convoy-data to this player
	APlayerData[playerid][LoadID] = AConvoys[Convoy][LoadID];
	APlayerData[playerid][JobLoc1] = AConvoys[Convoy][Location1];
	APlayerData[playerid][JobLoc2] = AConvoys[Convoy][Location2];

	// Store the vehicleID (required to be able to check if the player left his vehicle)
	APlayerData[playerid][VehicleID] = GetPlayerVehicleID(playerid);
	// Store the trailerID (required to be able to check if the player lost his trailer)
	APlayerData[playerid][TrailerID] = GetVehicleTrailer(GetPlayerVehicleID(playerid));

	// Set jobstep to 1 (going to load the goods)
	APlayerData[playerid][JobStep] = 1;
	// Get the startlocation, endlocation and the load texts
	format(StartLoc, 50, ALocations[APlayerData[playerid][JobLoc1]][LocationName]);
	format(EndLoc, 50, ALocations[APlayerData[playerid][JobLoc2]][LocationName]);
	format(Load, 50, ALoads[APlayerData[playerid][LoadID]][LoadName]);
	// Combine it all into a string for the TextDraw (the player can see this all the time) to describe the mission
	format(RouteText, 255, TXT_HaulingCargoFromToPickup, Load, StartLoc, EndLoc);
	// Set the TextDraw so the player can see it
	TextDrawSetString(APlayerData[playerid][MissionText], RouteText);
	// Grab the x, y, z positions for the first location
	x = ALocations[APlayerData[playerid][JobLoc1]][LocX];
	y = ALocations[APlayerData[playerid][JobLoc1]][LocY];
	z = ALocations[APlayerData[playerid][JobLoc1]][LocZ];
	// Create a checkpoint where the player should load the goods
	SetPlayerCheckpoint(playerid, x, y, z, 7);
	// Set the job-fail-time for the global vehicle-timer
	APlayerData[playerid][VehicleTimerTime] = Job_TimeToFailMission;
	// Inform the player that he must load his goods
	format(LoadMsg, 128, TXT_PickupCargoAt, Load, StartLoc);
	SendClientMessage(playerid, 0xFFFFFFFF, LoadMsg);
	SendClientMessage(playerid, 0xFFFFFFFF, TXT_MeetOtherConvoyMembers);
}



// This function is called when all convoy-members have loaded their cargo (it updates the missiontext and creates the unload-checkpoint)
Convoy_UpdateMemberJob(playerid)
{
    // Setup local variables
	new StartLoc[50], EndLoc[50], Load[50], RouteText[255], Float:x, Float:y, Float:z, UnloadMsg[128];

	// Set the jobstep to 3 (going to unload the cargo at the destination)
	APlayerData[playerid][JobStep] = 3;
	// Get the startlocation, endlocation and the load texts
	format(StartLoc, 50, ALocations[APlayerData[playerid][JobLoc1]][LocationName]);
	format(EndLoc, 50, ALocations[APlayerData[playerid][JobLoc2]][LocationName]);
	format(Load, 50, ALoads[APlayerData[playerid][LoadID]][LoadName]);
	// Update the missiontext
	format(RouteText, 255, TXT_HaulingCargoFromToDeliver, Load, StartLoc, EndLoc);
	// Set the TextDraw so the player can see it
	TextDrawSetString(APlayerData[playerid][MissionText], RouteText);
	// Grab the x, y, z positions for the second location (to unload the goods)
	x = ALocations[APlayerData[playerid][JobLoc2]][LocX];
	y = ALocations[APlayerData[playerid][JobLoc2]][LocY];
	z = ALocations[APlayerData[playerid][JobLoc2]][LocZ];
	// Create a checkpoint where the player should unload the goods
	SetPlayerCheckpoint(playerid, x, y, z, 7);
	// Inform the player that he must unload his goods
	format(UnloadMsg, 128, TXT_DeliverCargoTo, Load, EndLoc);
	SendClientMessage(playerid, 0xFFFFFFFF, UnloadMsg);
}



// This is the timer used by every convoy (it updates and checks everything), is executed every 2.5 seconds
public Convoy_Timer(Convoy)
{
	// Setup local variables
	new LeaderID, MemberID;

	// Update the textdraws for all convoy members
    Convoy_UpdateTextDraws(Convoy);
	// Get the leader-id
	LeaderID = AConvoys[Convoy][Members][0];

    // Check the jobstep for the entire convoy
	switch (AConvoys[Convoy][ConvoyStep])
	{
		case 0: // Convoy has just been created, but a job hasn't started yet by the leader
		{
			new bool:AllSameTrailer = true;

			// Keep checking if the leader has started a job already
			if (APlayerData[LeaderID][JobStarted] == true)
			{
				// Copy the job-data from the leader to the convoy
				AConvoys[Convoy][LoadID] = APlayerData[LeaderID][LoadID];
				AConvoys[Convoy][Location1] = APlayerData[LeaderID][JobLoc1];
				AConvoys[Convoy][Location2] = APlayerData[LeaderID][JobLoc2];
				// Set the trailer-model required by all members to the convoy
				AConvoys[Convoy][TrailerModel] = GetVehicleModel(GetVehicleTrailer(GetPlayerVehicleID(LeaderID)));

				// First check if the leader has a trailer attached or not
				if (AConvoys[Convoy][TrailerModel] != 0)
				{
					// First check if all players have the correct trailer (except for the leader)
					for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
					{
						MemberID = AConvoys[Convoy][Members][i]; // Get the member-id from this member-spot
						if (MemberID != -1) // Check if the member-id is a valid playerid
						{
						    // Check if the player has the same trailer-model attached to his vehicle as the convoy requires
							if (GetVehicleModel(GetVehicleTrailer(GetPlayerVehicleID(MemberID))) != AConvoys[Convoy][TrailerModel])
							{
							    // Inform the player that he hasn't got the correct trailer
							    switch (AConvoys[Convoy][TrailerModel])
							    {
									case VehicleTrailerCargo, VehicleTrailerCargo2: TextDrawSetString(APlayerData[MemberID][MissionText], TXT_MemberNeedsCargoTrailer);
									case VehicleTrailerOre: TextDrawSetString(APlayerData[MemberID][MissionText], TXT_MemberNeedsOreTrailer);
									case VehicleTrailerFluids: TextDrawSetString(APlayerData[MemberID][MissionText], TXT_MemberNeedsFluidsTrailer);
								}
								// Not everyone has the same trailer
								AllSameTrailer = false;
							}
						}
					}
				}
				else // Leader has no trailer attached, so check for the vehiclemodel
				{
					// First check if all players have the correct trailer (except for the leader)
					for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
					{
						MemberID = AConvoys[Convoy][Members][i]; // Get the member-id from this member-spot
						if (MemberID != -1) // Check if the member-id is a valid playerid
						{
						    // Get the vehiclemodel of the member
						    new vModel = GetVehicleModel(GetPlayerVehicleID(MemberID));
						    // Check if the member has a valid trucking vehicle (flatbed or DFT30)
							switch (vModel)
							{
								case VehicleFlatbed, VehicleDFT30: AllSameTrailer = true;
								default:
								{
									TextDrawSetString(APlayerData[MemberID][MissionText], "You need a Flatbed or DFT-30");
									AllSameTrailer = false;
								}
							}
						}
					}
				}

				// If all members have the same trailer
				if (AllSameTrailer == true)
				{
					// Inform the leader that everyone has the same trailer
					SendClientMessage(LeaderID, 0xFFFFFFFF, TXT_AllMembersSameTrailer);

					// Start the same job for every member if they all have the same trailer
					for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
					{
						MemberID = AConvoys[Convoy][Members][i]; // Get the member-id from this member-spot
						if (MemberID != -1) // Check if the member-id is a valid playerid
							Convoy_StartMemberJob(MemberID, Convoy); // Start the job for the member
					}

					// Select the next step for the convoy (all members are now en-route to the loading-point)
	                AConvoys[Convoy][ConvoyStep] = 1;
					// Also close the convoy so no more members can join
				    AConvoys[Convoy][Status] = CONVOY_CLOSED;
				}
				else
				{
				    // Check if the leader has been informed already that not all members have the same trailer
					if (AConvoys[Convoy][LeaderInformedTrailers] == false)
					{
						// Inform the leader that not every member has the same trailer, convoy cannot start yet
						SendClientMessage(LeaderID, 0xFFFFFFFF, TXT_AllMembersNotSameTrailer);
						AConvoys[Convoy][LeaderInformedTrailers] = true; // Leader is informed now
					}
				}
			}
		}
		case 1: // Everyone has received their job-data (but haven't loaded their cargo yet)
		{
			new bool:AllMembersLoaded = true;

			// Check if everyone has loaded their cargo before moving on to convoystep 2
			for (new i; i < CONVOY_MAX_MEMBERS; i++)
			{
				MemberID = AConvoys[Convoy][Members][i]; // Get the playerid of the member
				if (MemberID != -1) // Check if the memberid is a valid id
					if (APlayerData[MemberID][JobStep] != 2) // Check if the player hasn't loaded his cargo yet
					    AllMembersLoaded = false; // Not all members have loaded their cargo yet
			}

			// Check if everyone has loaded their cargo
			if (AllMembersLoaded == true)
			{
				// Inform the leader that everyone has the same trailer
				SendClientMessage(LeaderID, 0xFFFFFFFF, TXT_AllMembersLoadedCargo);

				// Update the job for every member if they all have loaded their cargo
				for (new i; i < CONVOY_MAX_MEMBERS; i++)
				{
					MemberID = AConvoys[Convoy][Members][i]; // Get the member-id from this member-spot
					if (MemberID != -1) // Check if the member-id is a valid playerid
						Convoy_UpdateMemberJob(MemberID); // Start the job for the member
				}

				// Select the next step for the convoy (all members are now en-route to the unloading-point)
                AConvoys[Convoy][ConvoyStep] = 2;
			}
		}
		case 2: // Everybody has loaded their cargo and all members have their job updated, all members are en-route to the destination
		{
			// Check if everyone is staying close to the leader and check if all members have unloaded their cargo
			new bool:AllMembersUnloaded = true;

			// Also check if all players have delivered their load
			for (new i; i < CONVOY_MAX_MEMBERS; i++)
			{
				MemberID = AConvoys[Convoy][Members][i]; // Get the playerid of the member
				if (MemberID != -1) // Check if the memberid is a valid id
					if (APlayerData[MemberID][JobStep] != 4) // Check if the player hasn't unloaded his cargo yet
					    AllMembersUnloaded = false; // Not all members have unloaded their cargo yet
			}

			if (AllMembersUnloaded == true) // Check if all members have unloaded their cargo (nobody cleared this variable)
				AConvoys[Convoy][ConvoyStep] = 3; // Set the jobstep for the entire convoy to 3 (everybody unloaded their cargo, but jobs must still be payed out)
		}
		case 3: // Everybody has unloaded their cargo (now it's time to pay all members and finish the job)
		{
		    // Setup local variables
			new Float:x1, Float:y1, Float:x2, Float:y2, Float:Distance, Message[128], Payment, Bonus, NumMembers, Name[24], BonusMsg[128];

			// Count the number of members in the convoy
			NumMembers = Convoy_CountMembers(Convoy);

			// Get the name of the convoy-leader
			GetPlayerName(LeaderID, Name, sizeof(Name));

			// Grab the x, y, z positions for the first location (to load the goods)
			x1 = ALocations[APlayerData[LeaderID][JobLoc1]][LocX];
			y1 = ALocations[APlayerData[LeaderID][JobLoc1]][LocY];
			// Grab the x, y, z positions for the second location (to unload the goods)
			x2 = ALocations[APlayerData[LeaderID][JobLoc2]][LocX];
			y2 = ALocations[APlayerData[LeaderID][JobLoc2]][LocY];
			// Calculate the distance between both points
			Distance = floatsqroot(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));

			// Calculate the payment for the player
			Payment = floatround((Distance * ALoads[APlayerData[LeaderID][LoadID]][PayPerUnit]), floatround_floor);

			// Check if the convoy has done the bonus mission
			if (RandomBonusMission[MissionFinished] == false)
			{
				// Check all paramters (load, startlocation and end-location)
				if (RandomBonusMission[RandomLoad] == APlayerData[LeaderID][LoadID])
					if (RandomBonusMission[RandomStartLoc] == APlayerData[LeaderID][JobLoc1])
						if (RandomBonusMission[RandomEndLoc] == APlayerData[LeaderID][JobLoc2])
						{
						    Payment = Payment * 2; // Double the payment is the player was the first to do the bonus mission
                            RandomBonusMission[MissionFinished] = true; // Only one player/convoy can do the bonus mission, a new one is chosen next
							format(BonusMsg, 128, "{00BBFF}Convoy with leader {FFBB00}%s{00BBFF} has finished the bonus mission", Name);
							SendClientMessageToAll(0xFFFFFFFF, BonusMsg);
						}
			}

		    // Calculate convoy-bonus (standard payment of 100% and 25% extra for each convoy-member)
		    Bonus = (NumMembers * 25) + 100; // For every member, 25% bonus is added to the payment, on top of the standard payment
			// Calculate total payment for each member
			Payment = (Payment * Bonus) / 100;

			// Pay every member and finish their mission
			for (new i; i < CONVOY_MAX_MEMBERS; i++)
			{
				MemberID = AConvoys[Convoy][Members][i]; // Get the playerid of the member
				if (MemberID != -1) // Check if the memberid is a valid id
				{
					// Reward the player (give cash and points)
					RewardPlayer(MemberID, Payment, 5);

					// Increase the stats for completing a trucking job while in a convoy
					APlayerData[MemberID][StatsConvoyJobs]++;
					// Also save the data (in case the server crashes, progress would be lost)
					PlayerFile_Save(MemberID);

					// End the member's job
					Trucker_EndJob(MemberID);
					// Send a message to let the player know he finished his mission and got paid
					format(Message, 128, TXT_FinishedConvoy, Payment);
					SendClientMessage(MemberID, 0xFFFFFFFF, Message);
					// Also update the player's missiontext to inform the player that he must wait for the leader to start a job
					if (i != 0) // Skip this if the current index is the leader (the leader doesn't have to wait for a new job)
						TextDrawSetString(APlayerData[MemberID][MissionText], TXT_WaitingLeaderJob);
				}
			}

			// Clear the data in the convoy
			AConvoys[Convoy][LoadID] = 0; // Clear the load-id
			AConvoys[Convoy][Location1] = 0; // Clear the loadingpoint id
			AConvoys[Convoy][Location2] = 0; // Clear the unloading point id
			AConvoys[Convoy][Status] = CONVOY_OPEN; // Set status to "open" again, so new members can join
			AConvoys[Convoy][ConvoyStep] = 0; // Set convoystep to 0 (wait for a new job to be started by the leader)
			AConvoys[Convoy][TrailerModel] = 0; // Clear trailer model (the next job can be for another trailer)
			AConvoys[Convoy][LeaderInformedTrailers] = false; // Allow the leader to be informed again if not all members have the correct trailer
		}
	}

	return 1;
}



// This function is used to update the textdraws for the leader and all members (used by the convoy-timer)
Convoy_UpdateTextDraws(Convoy)
{
	// Setup local variables
	new LeaderID, MemberID, LeaderName[24], NumMembers, TextLeader[128], TextMember[128], LastMember[24], LastMemberID, Float:Distance;

	// Get the leader-id
	LeaderID = AConvoys[Convoy][Members][0];
	// Get the name of the convoy-leader
	GetPlayerName(LeaderID, LeaderName, sizeof(LeaderName));
	// Get the number of members of the convoy
	NumMembers = Convoy_CountMembers(Convoy);

	// Check if there members besides the leader
	if (NumMembers > 1)
	{
	    LastMemberID = Convoy_GetFurthestMember(Convoy); // Get the playerid of the member who is furthest away from the leader
		GetPlayerName(LastMemberID, LastMember, sizeof(LastMember)); // Get the name of the furthest member
		Distance = PlayerToPlayer(LeaderID, LastMemberID); // Get the distance to the last member
	}
	else // No other members are in the convoy yet
	{
		format(LastMember, 24, " - ");
		Distance = 0.0;
	}

	// Update the convoy-textdraw for the leader
	format(TextLeader, 128, TXT_LeaderInfoBar, NumMembers, LastMember, Distance);
	TextDrawSetString(AConvoys[Convoy][ConvoyTextLeader], TextLeader);
	// Enable the convoy-textDraw for the leader
	TextDrawShowForPlayer(LeaderID, AConvoys[Convoy][ConvoyTextLeader]);

	// Update the convoy-textdraw for every member
	for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
	{
		MemberID = AConvoys[Convoy][Members][i]; // Get the playerid of the member
		if (MemberID != -1) // Check if the memberid is a valid id
		{
			// Calculate the distance to the leader
			Distance = PlayerToPlayer(LeaderID, MemberID);
			// Update the textdraw for the members
			format(TextMember, 128, TXT_MemberInfoBar, LeaderName, Distance, NumMembers);
			TextDrawSetString(AConvoys[Convoy][ConvoyTextMember], TextMember);
			TextDrawShowForPlayer(MemberID, AConvoys[Convoy][ConvoyTextMember]);
		}
	}
}



// This function counts the members in the convoy
Convoy_CountMembers(Convoy)
{
	// Setup local variables
	new NumMembers;

	// Loop through all members
	for (new i; i < CONVOY_MAX_MEMBERS; i++)
	{
		// Check if there is a valid member-id stored (playerid)
		if (AConvoys[Convoy][Members][i] != -1)
		    NumMembers++; // Increase the number of members
	}

	// Return the number of members to the calling routine
	return NumMembers;
}



// This function checks the player and determines if he's a valid trucker who's able to create or join a convoy
Convoy_PlayerAllowed(playerid)
{
	// Make sure that the leader is a trucker
	if (APlayerData[playerid][PlayerClass] == ClassTruckDriver)
	{
		// Check if the player isn't a member of a convoy already
		if (APlayerData[playerid][InConvoy] == false)
		{
			// Make sure that the player hasn't started a job
			if (APlayerData[playerid][JobStarted] == false)
				return true; // The player is allowed to create or join a convoy
			else
			    SendClientMessage(playerid, 0xFFFFFFFF, TXT_CannotJoinJobStarted);
		}
		else
		    SendClientMessage(playerid, 0xFFFFFFFF, TXT_ConvoyAllreadyJoined);
	}
	else
	    SendClientMessage(playerid, 0xFFFFFFFF, TXT_ConvoyNeedsTruckerClass);

	// If any condition wasn't true, the player isn't allowed to create or join a convoy
	return false;
}

// This function sends the given message to all members of the convoy
Convoy_SendMessage(Convoy, Message[])
{
	// Setup local variables
	new MemberID;

	// Loop through all members
	for (new i; i < CONVOY_MAX_MEMBERS; i++)
	{
	    MemberID = AConvoys[Convoy][Members][i]; // Get the member-id on this index
	    if (MemberID != -1) // Check if this member has a valid playerid
		{
			SendClientMessage(MemberID, 0xFFFFFFFF, Message); // Send the given message to the member
		}
	}
}

// This function returns "true" is the given player is the leader of the convoy
stock Convoy_IsLeader(playerid, Convoy)
{
	// Check if the player is part of a convoy
	if ((APlayerData[playerid][InConvoy] == true) && (AConvoys[Convoy][Members][0] = playerid))
	    return true; // Player is in a convoy AND he's the leader of it
	else
	    return false; // Player is a member of the convoy (or not in the same convoy)
}

// This function returns true if the player is a member of the given convoy
stock Convoy_IsMember(playerid, Convoy)
{
	// Loop through all members (excluding the leader)
	for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
	    if (AConvoys[Convoy][Members][i] == playerid) // Check if this member is the given player
			return true; // Return true (the player is a member of the convoy)

	// If the given playerid wasn't found among the members, return false
	return false;
}



// A function that returns the member of a convoy that's the furthest away from the leader
Convoy_GetFurthestMember(Convoy)
{
	// Setup local variables
	new Float:distance = 0.0, Float:distance2 = 0.0, LeaderID, MemberID, result = -1;

	// Get the leader-id
	LeaderID = AConvoys[Convoy][Members][0];

	// Loop through all members (excluding the leader)
	for(new i = 1; i < CONVOY_MAX_MEMBERS; i++)
	{
		MemberID = AConvoys[Convoy][Members][i]; // Get the playerid of the member
		if (MemberID != -1) // Check if the memberid is a valid id
		{
			// Get the distance between leader and member
			distance2 = PlayerToPlayer(LeaderID, MemberID);
			// Check if the distance is bigger than the previous distance
			if(distance2 > distance)
			{
				// Store the distance
				distance = distance2;
				// Store the member-id
				result = MemberID;
			}
		}
	}

	// Return the vehicle-id of the closest vehicle
	return result;
}

// Get the distance between the two players
PlayerToPlayer(player1, player2)
{
	// Setup local variables
	new Float:pX, Float:pY, Float:pZ, Float:cX, Float:cY, Float:cZ, Float:distance;
	// Get the player1 position
	GetPlayerPos(player1, pX, pY, pZ);
	// Get the player2 position
	GetPlayerPos(player2, cX, cY, cZ);
	// Calculate the distance
	distance = floatsqroot(floatpower(floatabs(floatsub(cX, pX)), 2) + floatpower(floatabs(floatsub(cY, pY)), 2) + floatpower(floatabs(floatsub(cZ, pZ)), 2));
	// Return the distance to the calling routine
	return floatround(distance);
}

