// This file holds all common functions that don't fit in any other file

// This functions gives the player the given amount of money and scorepoints
RewardPlayer(playerid, Money, Points)
{
	// Add the given amount of money to the player's account
	APlayerData[playerid][PlayerMoney] = APlayerData[playerid][PlayerMoney] + Money;
	// Add the given amount of scorepoints to the player's account
	APlayerData[playerid][PlayerScore] = APlayerData[playerid][PlayerScore] + Points;
}

// This function creates the vehicle and saves the vehicle-lodel in the AVehicleData-array (can only be used during GameModeInit)
// It also sets the fuel to maximum
Vehicle_AddStatic(vModel, Float:vX, Float:vY, Float:vZ, Float:vRotation, vC1, vC2, vSpawnDelay)
{
	// Create a new static vehicle during GameModeInit
	new vid = AddStaticVehicleEx(vModel, vX, vY, vZ, vRotation, vC1, vC2, vSpawnDelay);
	// Save the vehicle-model
    AVehicleData[vid][Model] = vModel;
	// Set the fuel to maximum so the vehicle can be used
    AVehicleData[vid][Fuel] = MaxFuel;
	// Save the colors
    AVehicleData[vid][Color1] = vC1;
    AVehicleData[vid][Color2] = vC2;
	// Set this vehicle as a static vehicle
	AVehicleData[vid][StaticVehicle] = true;

	return vid;
}

// This function is the same as Vehicle_AddStatic, but uses CreateVehicle instead of AddStaticVehicleEx, so can be used everywhere
Vehicle_Create(vModel, Float:vX, Float:vY, Float:vZ, Float:vRotation, vC1, vC2, vSpawnDelay)
{
	// Create a new static vehicle during GameModeInit
	new vid = CreateVehicle(vModel, vX, vY, vZ, vRotation, vC1, vC2, vSpawnDelay);
	// Save the vehicle-model
    AVehicleData[vid][Model] = vModel;
	// Set the fuel to maximum so the vehicle can be used
    AVehicleData[vid][Fuel] = MaxFuel;
	// Save the colors
    AVehicleData[vid][Color1] = vC1;
    AVehicleData[vid][Color2] = vC2;

	return vid;
}

// This function deletes the vehicle and clears all the data (is only used for player-owned vehicles)
Vehicle_Delete(vid)
{
	// Setup local variables
	new HouseID, CarSlot;

	// Get the HouseID and CarSlot where the vehicle is linked to
	HouseID = AVehicleData[vid][BelongsToHouse];

	// Check if this was a valid HouseID
	if (HouseID != 0)
	{
		// Loop through all carslots of this house to find the vehicle-id
		for (new i; i < 10; i++)
		{
			// Check if this carslot holds the same vehicle-id
		    if (AHouseData[HouseID][VehicleIDs][i] == vid)
		    {
		        CarSlot = i; // The carslot has been found where the vehicle is stored, remember it
				break; // Stop the for-loop
			}
		}

		// Remove the vehicle from the house
		AHouseData[HouseID][VehicleIDs][CarSlot] = 0;
	}

	// Delete the vehicle
	DestroyVehicle(vid);
	// Clear the data
	AVehicleData[vid][Owned] = false;
	AVehicleData[vid][Owner] = 0;
	AVehicleData[vid][Model] = 0;
	AVehicleData[vid][PaintJob] = 0;
	for (new i; i < 14; i++)
	    AVehicleData[vid][Components][i] = 0;
	AVehicleData[vid][Color1] = 0;
	AVehicleData[vid][Color2] = 0;
	AVehicleData[vid][SpawnX] = 0.0;
	AVehicleData[vid][SpawnY] = 0.0;
	AVehicleData[vid][SpawnZ] = 0.0;
	AVehicleData[vid][SpawnRot] = 0.0;
	AVehicleData[vid][BelongsToHouse] = 0;
}

// This function returns "1" if both locations are not closeby and returns "0" if both locations are close to eachother
Locations_CheckDistance(LocationA, LocationB, Float:Range)
{
	// Setup local variables
	new Float:Xa, Float:Ya, Float:Xb, Float:Yb, Float:X, Float:Y;

	// Get the coordinates of LocationA
	Xa = ALocations[LocationA][LocX];
	Ya = ALocations[LocationA][LocY];
	// Get the coordinates of LocationB
	Xb = ALocations[LocationB][LocX];
	Yb = ALocations[LocationB][LocY];

	// Calculate the distances between both locations
	Y = Yb - Ya;
	X = Xb - Xa;

	// Check if both locations are further apart then the range indicates
	if (((X * X) + (Y * Y)) > (Range * Range))
		return 1; // Location B is further away from Location A than Range indicates
	else
	    return 0; // both locations are closer to eachother than Range indicates
}

// This function ports all non-admin players out of the given area to the location specified
Player_PortOutAdminZone(playerid, Float:x1, Float:y1, Float:z1, Float:x2, Float:y2, Float:z2, Float:x3, Float:y3, Float:z3)
{
	// Setup local variables
	new Float:x, Float:y, Float:z;

	// Get the player's coordinates
	GetPlayerPos(playerid, x, y, z);

	// Check if the player is not an admin
	if (APlayerData[playerid][PlayerLevel] == 0)
		if ((x1 < x) && (x < x2))
		    if ((y1 < y) && (y < y2))
		        if ((z1 < z) && (z < z2))
				{
					SendClientMessage(playerid, 0xFFFFFFFF, "{FF0000}You're not allowed inside an admin-area");
					SetPlayerPos(playerid, x3, y3, z3); // Port the player out of the area
				}
}

// This function sends the given text to all admins
SendAdminText(playerid, command[], text[])
{
	// Setup local variables
	new Name[24], Msg[128];

	// Loop through all players
	for (new i; i < MAX_PLAYERS; i++)
	{
		// Check if the player is an admin
		if (APlayerData[i][PlayerLevel] > 0)
		{
			// Get the player's name
			GetPlayerName(playerid, Name, sizeof(Name));
			// Send the given text to the admin
			format(Msg, 128, "{00FFCC}%s used: %s %s", Name, command, text);
			SendClientMessage(i, 0xFFFFFFFF, Msg);
		}
	}

	// Also log all used commands in the server.log file
	format(Msg, 128, "%s used: %s %s", Name, command, text);
	print(Msg);
}

// This timer informs the player how long he will be frozen
forward Player_FreezeTimer(playerid);
public Player_FreezeTimer(playerid)
{
	// Setup local variables
	new Msg[128];

	// Decrease the remaining time this player will be frozen
    APlayerData[playerid][PlayerFrozen]--;

	// Check if the player is allowed to move again
	if (APlayerData[playerid][PlayerFrozen] > 0)
	{
		// Construct the message to inform the player how long he stays frozen
		if (APlayerData[playerid][PlayerFrozen] >= 60)
			format(Msg, 128, "Frozen for %i minutes", APlayerData[playerid][PlayerFrozen] / 60);
		else
			format(Msg, 128, "Frozen for %i seconds", APlayerData[playerid][PlayerFrozen]);

		// Display the message to inform the player how long he stays frozen
		GameTextForPlayer(playerid, Msg, 1000, 4);
	}
	else // The timer has run out, so allow his to move again
	    TogglePlayerControllable(playerid, 1);
}

// This function creates a list of commands, starting from the FirstCommand and automatically shows the dialog
CommandList_Create(playerid)
{
	// Setup local variables
	new Counter, CommandList[1000], DialogTitle[128];

	// Only add 4 commands to the list, starting from the FirstItem
	for (new i = APlayerData[playerid][DialogFirstItem]; i < sizeof(ACommands); i++)
	{
		// Increase a counter (which holds the number of commands that have been added to the list
		Counter++;

		// Check if the maximum hasn't been reached yet
		if (Counter <= 5)
		{
		    // Check if this command is valid for this player
			if (APlayerData[playerid][PlayerLevel] >= ACommands[i][CommandLevel])
			{
				// Check if the command is used for admins or not
				if (ACommands[i][CommandLevel] == 0)
				{
				    // Add the commandname and description to the list
					format(CommandList, 500, "%s%s{00FF00}%s", CommandList, "\n", ACommands[i][CommandStructure]); // Add the name of the next command to the list on the next line
					format(CommandList, 500, "%s%s\t\t{FFFF00}%s", CommandList, "\n", ACommands[i][CommandDescription]); // Add the description of the next command to the list on the next line
				}
				else
				{
				    // Add the commandname and description to the list
					format(CommandList, 500, "%s%sLvl %i: {00FF00}%s", CommandList, "\n", ACommands[i][CommandLevel], ACommands[i][CommandStructure]); // Add the name of the next command to the list on the next line
					format(CommandList, 500, "%s%s\t\t{FFFF00}%s", CommandList, "\n", ACommands[i][CommandDescription]); // Add the description of the next command to the list on the next line
				}
			}
			else
				break;
		}
		else // 5 commands have been added to the list (now Counter = 6)
		{
		    // Add an empty line and "Next..." to the list to let the player know there are more commands
			format(CommandList, 500, "%s%s%s", CommandList, "\n \n", TXT_DialogEntryNext);
			// Also stop the For-loop
			break;
		}
	}

	// Construct the title for the dialog (to include a page number)
	format(DialogTitle, 128, TXT_DialogCommandTitle, (APlayerData[playerid][DialogFirstItem] / 5) + 1);
	// Show the commands in a dialog
	ShowPlayerDialog(playerid, DialogPlayerCommands, DIALOG_STYLE_LIST, DialogTitle, CommandList, TXT_DialogButtonSelect, TXT_DialogButtonCancel);

	return 1;
}

// This function returns "1" if the given vehicle-id is a plane or helicopter
IsVehicleAirVehicle(vid)
{
	switch (GetVehicleModel(vid))
	{
		case 592, 577, 511, 512, 593, 520, 553, 476, 519, 460, 513, 548, 425, 417, 487, 488, 497, 563, 447, 469: return 1;
		default: return 0;
	}

	return 0;
}

// This function creates a speedcamera (store data and create the objects)
SetupSpeedCamera(CamID, Float:x, Float:y, Float:z, Float:rot, MaxSpeed)
{
	// Store all the given values
    ACameras[CamID][CamX] = x;
    ACameras[CamID][CamY] = y;
    ACameras[CamID][CamZ] = z;
    ACameras[CamID][CamAngle] = rot;
    ACameras[CamID][CamSpeed] = MaxSpeed;
	// Create both camera objects and store their reference
    ACameras[CamID][CamObj1] = CreateObject(18880, x, y, z, 0.0, 0.0, rot);
    ACameras[CamID][CamObj2] = CreateObject(18880, x, y, z, 0.0, 0.0, rot + 180.0);
}



// This function sends the report to all admins
SendReportToAdmins(OffenderID, Reason[], bool:AutoReport = false)
{
	// Setup local variables
	new Name[24], Msg[128], TxtMsg[128], TotalReason[128];

	// Get the name of the offender
	GetPlayerName(OffenderID, Name, sizeof(Name));

	// Construct the report message for all admins
	if (AutoReport == false)
	{
	    // Construct the report messages for a normal report
		format(Msg, 128, "{00FFFF}*** Report: %s (%i): %s", Name, OffenderID, Reason);
		format(TxtMsg, 128, "Report:~n~~g~%s (%i)~n~~r~%s", Name, OffenderID, Reason);
		format(TotalReason, 128, Reason);
	}
	else
	{
	    // Construct the report messages for an automated report (sent by the AntiHack function)
		format(Msg, 128, "{00FFFF}*** Auto-Report: %s (%i): %s", Name, OffenderID, Reason);
		format(TxtMsg, 128, "Auto-Report:~n~~g~%s (%i)~n~~r~%s", Name, OffenderID, Reason);
		format(TotalReason, 128, "%s (by AntiHack)", Reason);
		// For automated reports, preset the time to 60 seconds to stop the Anti-Hack system reporting the player every half a second
		APlayerData[OffenderID][AutoReportTime] = 120; // The time must be doubled, as the speedometer runs twice every second
	}

	// Loop through all the players to find all online admins
	for (new playerid; playerid < MAX_PLAYERS; playerid++)
	{
	    // Check if this player is an admin
	    if (APlayerData[playerid][PlayerLevel] > 0)
	    {
			// Send a message to the admin to inform him about the report
			SendClientMessage(playerid, 0xFFFFFFFF, Msg);
			// Also send the admin a GameText-message so he can see it more clearly
			GameTextForPlayer(playerid, TxtMsg, 10000, 4);
	    }
	}

	// Add the report to the AReports-array so admins can review it in a dialog (maximum 50 reports can be stored)
	AddReport(OffenderID, TotalReason);
}

// This function adds the report to the AReports array automatically
AddReport(OffenderID, Reason[])
{
	// Setup local variables
	new ReportID = -1, Name[24];

	// Check if there is a free spot in the AReports array
	for (new i; i < 50; i++)
	{
		// Check if this report-spot is empty
		if (AReports[i][ReportUsed] == false)
		{
		    ReportID = i;
		    break; // If this spot hasn't been used yet, stop the for-loop
		}
	}

	// If no spot is free (ReportID is still -1)
	if (ReportID == -1)
	{
		// Drop the report on ID 0, and move them all downwards
		for (new i = 1; i < 50; i++)
		{
			AReports[i - 1][ReportUsed] = AReports[i][ReportUsed];
			format(AReports[i - 1][ReportName], 24, "%s", AReports[i][ReportName]);
			format(AReports[i - 1][ReportReason], 128, "%s", AReports[i][ReportReason]);
		}

		// ReportID 49 is available now, so use this to add the new report
		ReportID = 49;
	}

	// Get the name of the offender
	GetPlayerName(OffenderID, Name, sizeof(Name));

	// Store the data into the array
	AReports[ReportID][ReportUsed] = true;
	format(AReports[ReportID][ReportName], 24, "%s", Name);
	format(AReports[ReportID][ReportReason], 128, "%s", Reason);
}



// This function converts an ip-address into 4 separate integer parts and returns a string that only holds the first three parts
GetFirstThreeDigitsFromIP(PlayerIP[])
{
	// Setup local variables
	new Part1, Part2, Part3, DotLoc, RetIP[16];

	// Get the first part of the IP-address
	Part1 = strval(PlayerIP[0]);

	// Find the first dot
	DotLoc = strfind(PlayerIP, ".", false, 0);
	// Get the second part of the IP-address (the part that follows the first dot)
	Part2 = strval(PlayerIP[DotLoc+1]);

	// Find the second dot
	DotLoc = strfind(PlayerIP, ".", false, DotLoc+1);
	// Get the third part of the IP-address (the part that follows the second dot)
	Part3 = strval(PlayerIP[DotLoc+1]);

	// Combine them all into an IP that only holds the first three digits, followed by a dot
	format(RetIP, 16, "%i.%i.%i.", Part1, Part2, Part3);
	// Return it to the calling function
	return RetIP;
}



// This timer is executed every 2 minutes and sends all timedmessages one at a time
forward Timer_TimedMessages();
public Timer_TimedMessages()
{
	// Send the message
	SendClientMessageToAll(0xFFFFFFFF, ATimedMessages[LastTimedMessage]);

	// Select the next message
    LastTimedMessage++;

	// Check if the next chosen message exists (the messagenumber is the same as the size of the array of messages)
	if (LastTimedMessage == sizeof(ATimedMessages))
	    LastTimedMessage = 0; // Select the first message again

	return 1;
}

// This timer is executed every 5 minutes and sends the data about a random bonus mission to every trucker
forward ShowRandomBonusMission();
public ShowRandomBonusMission()
{
	// Setup local variables
	new bool:MissionSet = false, Msg1[128], Msg2[128], Msg3[128], lName[50], sName[50], eName[50], tName[100];

	// Check if there is no mission defined yet (only happens when server is restarted), or when the mission has been completed by a player
	if ((RandomBonusMission[RandomLoad] == 0) || (RandomBonusMission[MissionFinished] == true))
	{
		// Keep checking until a valid mission has been set
		while (MissionSet == false)
		{
			// Choose a random LoadID
	        RandomBonusMission[RandomLoad] = random(sizeof(ALoads));

			switch (RandomBonusMission[RandomLoad])
			{
				case 0: MissionSet = false; // If the dummy load has been chosen, allow the while loop to run again to search for another valid load
				default: // If another load has been chosen, check if it is a trucker load
				{
					switch(ALoads[RandomBonusMission[RandomLoad]][PCV_Required]) // Check the class & vehicle variable
					{
					    case PCV_TruckerOreTrailer, PCV_TruckerFluidsTrailer, PCV_TruckerCargoTrailer, PCV_TruckerCementTruck, PCV_TruckerNoTrailer:
					    {
					        // Now only the loads for truckers are checked
							MissionSet = true; // The load has been determined now as it's a valid load for truckers only
					    }
					    default: MissionSet = false; // If another class & vehicle has been chosen (mafia or pilot load), search again
					}
				}
			}
		}

		// Find a random startlocation and endlocation from the chosen load
	    RandomBonusMission[RandomStartLoc] = Product_GetRandomStartLoc(RandomBonusMission[RandomLoad]);
	    RandomBonusMission[RandomEndLoc] = Product_GetRandomEndLoc(RandomBonusMission[RandomLoad]);
		// Set the new random mission as not-completed yet
		RandomBonusMission[MissionFinished] = false;
	}

	// Get the names of the load, start-location and end-location
	format(lName, 50, ALoads[RandomBonusMission[RandomLoad]][LoadName]);
	format(sName, 50, ALocations[RandomBonusMission[RandomStartLoc]][LocationName]);
	format(eName, 50, ALocations[RandomBonusMission[RandomEndLoc]][LocationName]);
	// Setup the name of the vehicle you'll need for this mission
	switch(ALoads[RandomBonusMission[RandomLoad]][PCV_Required])
	{
		case PCV_TruckerOreTrailer: format(tName, 128, "truck with ore trailer");
		case PCV_TruckerFluidsTrailer: format(tName, 128, "truck with fluids trailer");
		case PCV_TruckerCargoTrailer: format(tName, 128, "truck with cargo trailer");
		case PCV_TruckerCementTruck: format(tName, 128, "cement truck");
		case PCV_TruckerNoTrailer: format(tName, 128, "Flatbed or DFT-30");
	}

	// Construct the messages that describe the mission
	format(Msg1, 128, "{00BBFF}Bonus mission: transport {FFBB00}%s", lName);
	format(Msg2, 128, "{00BBFF}from {FFBB00}%s{00BBFF} to {FFBB00}%s", sName, eName);
	format(Msg3, 128, "{00BBFF}You'll need a {FFBB00}%s{00BBFF} to complete this mission", tName);

	// Now send the data about the random mission to all truckers
	for (new playerid; playerid < MAX_PLAYERS; playerid++)
	{
		// Check if this player is online
		if (APlayerData[playerid][LoggedIn] == true)
		{
			// Check if this player is a trucker
			if (APlayerData[playerid][PlayerClass] == ClassTruckDriver)
			{
				SendClientMessage(playerid, 0xFFFFFFFF, Msg1);
				SendClientMessage(playerid, 0xFFFFFFFF, Msg2);
				SendClientMessage(playerid, 0xFFFFFFFF, Msg3);
			}
		}
	}

	return 1;
}



// This function displays the main bank menu dialog
ShowBankMenu(playerid)
{
	// Setup local variables
	new BankOptions[256], BankTitle[128];

    // Construct the title of the bank dialog
	format(BankTitle, sizeof(BankTitle), "{FFFFFF}Your bank funds: {00FF00}$%i", APlayerData[playerid][BankMoney]);

    // Construct the options of the bank dialog
	format(BankOptions, sizeof(BankOptions), "{00FF00}Deposit money\n");
	format(BankOptions, sizeof(BankOptions), "%s{00FF00}Withdraw money\n", BankOptions);
	format(BankOptions, sizeof(BankOptions), "%s{00FF00}Transfer money\n", BankOptions);
	format(BankOptions, sizeof(BankOptions), "%s{00FF00}Cancel bank account\n", BankOptions);

	// Show the bank dialog
	ShowPlayerDialog(playerid, DialogBankOptions, DIALOG_STYLE_LIST, BankTitle, BankOptions, TXT_DialogButtonSelect, TXT_DialogButtonCancel);
}

// This timer increases the variable "CurrentIntrestTime" every hour
forward Bank_IntrestTimer();
public Bank_IntrestTimer()
{
	// Setup local variables
	new IntrestAmount, Msg[128];

	// Increase the variable by one
    CurrentIntrestTime++;

	// And save it to the file
	IntrestTime_Save();

	// Process intrest for all online player with a bank account if intrest is enabled
	if (IntrestEnabled == true)
	{
		// Loop through all players
		for (new playerid; playerid < MAX_PLAYERS; playerid++)
		{
			// Check if this player is logged in
			if (APlayerData[playerid][LoggedIn] == true)
			{
				// Check if this player has a bank account (just check if there is money in the bank, it's useless to process the intrest for
				// a bank account which doesn't have any money in it, and having BankMoney also means the player has a bank account)
				if (APlayerData[playerid][BankMoney] > 0)
				{
					// Calculate the intrest
					IntrestAmount = floatround(floatmul(APlayerData[playerid][BankMoney], BankIntrest), floatround_floor);
					// Add intrest to this player's bank account
					APlayerData[playerid][BankMoney] = APlayerData[playerid][BankMoney] + IntrestAmount;
					// Save the CurrentIntrestTime for this bank account
					APlayerData[playerid][LastIntrestTime] = CurrentIntrestTime;
					// Save the player's bank account
					BankFile_Save(playerid);

					// Inform the player that he received intrest on his bank account and how much
					format(Msg, 128, "{00BBFF}You've received {FFBB00}$%i{00BBFF} intrest on your bank account", IntrestAmount);
					SendClientMessage(playerid, 0xFFFFFFFF, Msg);
				}
			}
		}
	}
}



// This function creates a list of help-items, for which the player can get information about it
HelpList_Create(playerid)
{
	// Setup local variables
	new HelpList[1000], DialogTitle[128];

	// Construct the title for the dialog (to include a page number)
	format(DialogTitle, 128, "Here you can get help about any of these items:");

    // Add all help-topics to the list
	for (new i; i < sizeof(AHelpTopics); i++)
	{
		format(HelpList, 1000, "%s%s\n", HelpList, AHelpTopics[i]);
	}

	// Show the commands in a dialog
	ShowPlayerDialog(playerid, DialogHelpItemChosen, DIALOG_STYLE_LIST, DialogTitle, HelpList, TXT_DialogButtonSelect, TXT_DialogButtonCancel);

	return 1;
}

