/*
*	Created:			15.04.09
*	Author:				009
*	Last Modifed:		29.12.09
*	Description:		Функции передвижения камеры игрока
*
*	29.12.09:
*	1.Добавлена проверка аргументов на ошибки
*	2.Добавлен дебаг
*	3.Добавлен native list
*
*	20.10.09:
*	1.Добавлен вызов паблика OnPlayerCameraCompleteMoving по окончании перемещения камеры
*	2.Добавлены иды камеры наподобии идов диалоговых окон
*	3.Добавлена функция MovePlayerCameraAroundXYZEx(playerid,cameraid,Float:rad,Float:X,Float:Y,Float:Z,Float:mingrad,Float:maxgrad,bool:back)
*	4.Круговое движение имеет направление(лево\право , аргумент back)
*
*	12.09.09:
*	1.Добавлена функция ModeCamera_ResetStat
*
*	09.09.09
*	1.Добавлена функция IsPlayerCameraMoving
*
*	04.09.09:
*	1.Заменён GetDistanceXYZtoXYZ на IsPosInRangeOfPoint
*	2.В циклах MAX_PLAYERS заменено GetMaxPlayer() для большей производительности
*/

/*
				SetPlayerCameraPos(playerid, x+a*floatcos((angle < 180.0)?(angle):(floatadd(360, -angle)), degrees), y+a*floatsin((angle < 180.0)?(angle):(floatadd(360, -angle)), degrees), z+0.2);
*/

#if defined _mode_camera_included
#endinput
#endif

#define _mode_camera_included
#pragma library mode_camera

// --------------------------------------------------
// includes
// --------------------------------------------------
#include "mode_debug"
#include "mode_core"

// --------------------------------------------------
// defines
// --------------------------------------------------
#define CAMERA_Z_OFFSET -1000.0
#define INVALID_MODECAMERA_ID -1

// --------------------------------------------------
// enums
// --------------------------------------------------
enum {
	CAMERA_MODE_MOVE_NONE,
	CAMERA_MODE_MOVE_POS,
	CAMERA_MODE_MOVE_POS_EX,
	CAMERA_MODE_MOVE_POS_AROUND,
	CAMERA_MODE_MOVE_POS_AROUND2,
	CAMERA_MODE_MOVE_POS_AROUND3
};
enum {
	DIRECTION_LEFT,
	DIRECTION_RIGHT
};
enum AroundInfo {
	Float:AROUND_INFO_RADIUS,
	Float:AROUND_INFO_ANGLE,
	Float:AROUND_INFO_ANGLE2
};

enum ModeCameraAroundInfo {
	aInfo[AroundInfo],
	aPlayerId,
	aDirection
};
enum ModeCameraPlayerInfo {
	pLookPosObjectId,
	pPosObjectId,
	pCameraMode,
	Float:pCoords[3],
	pAround[ModeCameraAroundInfo],
	pCameraId
};

// --------------------------------------------------
// news
// --------------------------------------------------
new ModeCamera_Player[MAX_PLAYERS][ModeCameraPlayerInfo],
	ModeCameraObjectsOffsets[MAX_OBJECTS];

// --------------------------------------------------
// natives list (for pawno functions list)
// --------------------------------------------------
/*
native MovePlayerCameraPos(playerid,cameraid,Float:startX,Float:startY,Float:startZ,Float:endX,Float:endY,Float:endZ,Float:speed);
native MovePlayerCameraLookPos(playerid,Float:startX,Float:startY,Float:startZ,Float:endX,Float:endY,Float:endZ,Float:speed);
native MovePlayerCameraPosEx(playerid,cameraid,Float:startX,Float:startY,Float:startZ,Float:endX,Float:endY,Float:endZ,Float:lookX,Float:lookY,Float:lookZ,Float:speed);
native MovePlayerCameraAroundPlayer(playerid,cameraid,aroundid,Float:radius,direction);
native MovePlayerCameraAroundXYZ(playerid,cameraid,Float:X,Float:Y,Float:Z,Float:radius,direction);
native MovePlayerCameraAroundXYZEx(playerid,cameraid,Float:X,Float:Y,Float:Z,Float:radius,Float:minAngle,Float:maxAngle,direction);
native Float:GetPlayerCameraAroundRadius(playerid);
native SetPlayerCameraAroundRadius(playerid,Float:radius);
native GetPlayerCameraAroundCenter(playerid,&Float:X,&Float:Y,&Float:Z);
native SetPlayerCameraAroundCenter(playerid,Float:X,Float:Y,Float:Z);
native GetPlayerCameraAroundDirection(playerid);
native SetPlayerCameraAroundDirection(playerid,direction);
native StopPlayerCamera(playerid,bool:returncamera);
native IsPlayerCameraMoving(playerid);
*/

// --------------------------------------------------
// forwards
// --------------------------------------------------
forward CameraUpdate();
forward OnPlayerCameraCompleteMoving(playerid,cameraid);

// --------------------------------------------------
// publics
// --------------------------------------------------
public CameraUpdate()
{
	Debug(DEBUG_START,"CameraUpdate");
	for(new playerid = 0;playerid < GetMaxPlayer();playerid++)
	{
		if(!IsPlayerConnected(playerid)) continue;
		
		switch(ModeCamera_Player[playerid][pCameraMode])
		{
			case CAMERA_MODE_MOVE_POS:
			{
				new Float:pos[3];
				GetPlayerObjectPos(playerid,ModeCamera_Player[playerid][pPosObjectId],pos[0],pos[1],pos[2]);
				SetPlayerCameraPos(playerid,pos[0],pos[1],(pos[2] - CAMERA_Z_OFFSET));
			}
			case CAMERA_MODE_MOVE_POS_EX:
			{
				new Float:pos[3];
				GetPlayerObjectPos(playerid,ModeCamera_Player[playerid][pPosObjectId],pos[0],pos[1],pos[2]);
				SetPlayerCameraPos(playerid,pos[0],pos[1],(pos[2] - CAMERA_Z_OFFSET));
				SetPlayerCameraLookAt(playerid,ModeCamera_Player[playerid][pCoords][0],ModeCamera_Player[playerid][pCoords][1],ModeCamera_Player[playerid][pCoords][2]);
			}
			case CAMERA_MODE_MOVE_POS_AROUND:
			{
				if(IsPlayerConnected(ModeCamera_Player[playerid][pAround][aPlayerId]))
				{
					if(GetPlayerVirtualWorld(ModeCamera_Player[playerid][pAround][aPlayerId]) != GetPlayerVirtualWorld(playerid)) SetPlayerVirtualWorld(playerid,GetPlayerVirtualWorld(ModeCamera_Player[playerid][pAround][aPlayerId]));
					new Float:pos[3];
					GetPlayerPos(ModeCamera_Player[playerid][pAround][aPlayerId],pos[0],pos[1],pos[2]);
					SetPlayerCameraLookAt(playerid,pos[0],pos[1],pos[2]);
					pos[0] += (ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] * floatsin(-ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE], degrees));
					pos[1] += (ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] * floatcos(-ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE], degrees));
					SetPlayerCameraPos(playerid,pos[0],pos[1],(pos[2] + 2.0));
					switch(ModeCamera_Player[playerid][pAround][aDirection])
					{
						case DIRECTION_LEFT: ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] -= 0.5;
						case DIRECTION_RIGHT: ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] += 0.5;
					}
				}
				else
				{
					if(!OnPlayerCameraCompleteMoving(playerid,ModeCamera_Player[playerid][pCameraId])) ModeCamera_ResetStat(playerid);
				}
			}
			case CAMERA_MODE_MOVE_POS_AROUND2:
			{
				new Float:pos[2];
				pos[0] = ModeCamera_Player[playerid][pCoords][0];
				pos[1] = ModeCamera_Player[playerid][pCoords][1];
				pos[0] += (ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] * floatsin(-ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE], degrees));
				pos[1] += (ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] * floatcos(-ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE], degrees));
				SetPlayerCameraPos(playerid,pos[0],pos[1],(ModeCamera_Player[playerid][pCoords][2] + (ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] / 2.0)));
				SetPlayerCameraLookAt(playerid,ModeCamera_Player[playerid][pCoords][0],ModeCamera_Player[playerid][pCoords][1],ModeCamera_Player[playerid][pCoords][2]);
				switch(ModeCamera_Player[playerid][pAround][aDirection])
				{
					case DIRECTION_LEFT: ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] -= 0.1;
					case DIRECTION_RIGHT: ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] += 0.1;
				}
			}
			case CAMERA_MODE_MOVE_POS_AROUND3:
			{
				new Float:pos[2];
				pos[0] = ModeCamera_Player[playerid][pCoords][0];
				pos[1] = ModeCamera_Player[playerid][pCoords][1];
				pos[0] += (ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] * floatsin(-ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE], degrees));
				pos[1] += (ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] * floatcos(-ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE], degrees));
				SetPlayerCameraPos(playerid,pos[0],pos[1],(ModeCamera_Player[playerid][pCoords][2] + (ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] / 2.0)));
				SetPlayerCameraLookAt(playerid,ModeCamera_Player[playerid][pCoords][0],ModeCamera_Player[playerid][pCoords][1],ModeCamera_Player[playerid][pCoords][2]);
				switch(ModeCamera_Player[playerid][pAround][aDirection])
				{
					case DIRECTION_LEFT: 
					{
						if((ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] - ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE2]) < 0.5)
						{
							if(!OnPlayerCameraCompleteMoving(playerid,ModeCamera_Player[playerid][pCameraId])) ModeCamera_ResetStat(playerid);
						}
						else ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] -= 0.1;
					}
					case DIRECTION_RIGHT: 
					{
						if((ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE2] - ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE]) < 0.5)
						{
							if(!OnPlayerCameraCompleteMoving(playerid,ModeCamera_Player[playerid][pCameraId])) ModeCamera_ResetStat(playerid);
						}
						else ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] += 0.1;
					}
				}
			}
		}
		if(ModeCamera_Player[playerid][pLookPosObjectId] != INVALID_OBJECT_ID)
		{
			new Float:pos[3];
			GetPlayerObjectPos(playerid,ModeCamera_Player[playerid][pLookPosObjectId],pos[0],pos[1],pos[2]);
			SetPlayerCameraLookAt(playerid,pos[0],pos[1],(pos[2] - CAMERA_Z_OFFSET));
		}
	}
	Debug(DEBUG_END,"CameraUpdate(reason: complete)");
}

// --------------------------------------------------
// stocks
// --------------------------------------------------
stock MovePlayerCameraPos(playerid,cameraid,Float:startX,Float:startY,Float:startZ,Float:endX,Float:endY,Float:endZ,Float:speed)
{
	Debug(DEBUG_START,"MovePlayerCameraPos(%d,%d,%f,%f,%f,%f,%f,%f,%f,%f)",playerid,cameraid,startX,startY,startZ,endX,endY,endZ,speed);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"MovePlayerCameraPos(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraPos (offline player, playerid = %d)",playerid);
		return 0;
	}
	if(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_NONE)
	{
		Debug(DEBUG_END,"MovePlayerCameraPos(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraPos (camera also moved, playerid = %d)",playerid);
		return 0;
	}
	Debug(DEBUG_ACTION,"create object and move");
	ModeCamera_Player[playerid][pPosObjectId] = CreatePlayerObject(playerid,1253,startX,startY,(startZ + CAMERA_Z_OFFSET),0.0,0.0,0.0);
	ModeCameraObjectsOffsets[ ModeCamera_Player[playerid][pPosObjectId] ] = playerid;
	MovePlayerObject(playerid,ModeCamera_Player[playerid][pPosObjectId],endX,endY,(endZ + CAMERA_Z_OFFSET),speed);
	ModeCamera_Player[playerid][pCameraMode] = CAMERA_MODE_MOVE_POS;
	ModeCamera_Player[playerid][pCameraId] = cameraid;
	Debug(DEBUG_END,"MovePlayerCameraPos(reason: complete)");
	return 1;
}

stock MovePlayerCameraLookPos(playerid,Float:startX,Float:startY,Float:startZ,Float:endX,Float:endY,Float:endZ,Float:speed)
{
	Debug(DEBUG_START,"MovePlayerCameraLookPos(%d,%f,%f,%f,%f,%f,%f,%f,%f)",playerid,startX,startY,startZ,endX,endY,endZ,speed);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"MovePlayerCameraLookPos(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraLookPos (offline player, playerid = %d)",playerid);
		return 0;
	}
	if((ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_NONE) && 
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS))
	{
		Debug(DEBUG_END,"MovePlayerCameraLookPos(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraLookPos (camera look pos also moving)");
		return 0;
	}
	Debug(DEBUG_ACTION,"create object and move");
	ModeCamera_Player[playerid][pLookPosObjectId] = CreatePlayerObject(playerid,1253,startX,startY,(startZ + CAMERA_Z_OFFSET),0.0,0.0,0.0);
	ModeCameraObjectsOffsets[ ModeCamera_Player[playerid][pLookPosObjectId] ] = playerid;
	MovePlayerObject(playerid,ModeCamera_Player[playerid][pLookPosObjectId],endX,endY,(endZ + CAMERA_Z_OFFSET),speed);
	Debug(DEBUG_END,"MovePlayerCameraLookPos(reason: complete)");
	return 1;
}

stock MovePlayerCameraPosEx(playerid,cameraid,Float:startX,Float:startY,Float:startZ,Float:endX,Float:endY,Float:endZ,Float:lookX,Float:lookY,Float:lookZ,Float:speed)
{
	Debug(DEBUG_START,"MovePlayerCameraPosEx(%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f)",playerid,cameraid,startX,startY,startZ,endX,endY,endZ,lookX,lookY,lookZ,speed);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"MovePlayerCameraPosEx(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraPosEx (offline player, playerid = %d)",playerid);
		return 0;
	}
	if(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_NONE)
	{
		Debug(DEBUG_END,"MovePlayerCameraPosEx(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraPosEx (camera also moved, playerid = %d)",playerid);
		return 0;
	}
	if(ModeCamera_Player[playerid][pLookPosObjectId] != INVALID_OBJECT_ID)
	{
		Debug(DEBUG_END,"MovePlayerCameraPosEx(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraPosEx (look pos moved)");
		return 0;
	}
	Debug(DEBUG_ACTION,"create object and move");
	ModeCamera_Player[playerid][pPosObjectId] = CreatePlayerObject(playerid,1253,startX,startY,(startZ + CAMERA_Z_OFFSET),0.0,0.0,0.0);
	ModeCameraObjectsOffsets[ ModeCamera_Player[playerid][pPosObjectId] ] = playerid;
	MovePlayerObject(playerid,ModeCamera_Player[playerid][pPosObjectId],endX,endY,(endZ + CAMERA_Z_OFFSET),speed);
	ModeCamera_Player[playerid][pCoords][0] = lookX;
	ModeCamera_Player[playerid][pCoords][1] = lookY;
	ModeCamera_Player[playerid][pCoords][2] = lookZ;
	ModeCamera_Player[playerid][pCameraMode] = CAMERA_MODE_MOVE_POS_EX;
	ModeCamera_Player[playerid][pCameraId] = cameraid;
	Debug(DEBUG_END,"MovePlayerCameraPosEx(reason: complete)");
	return 1;
}

stock MovePlayerCameraAroundPlayer(playerid,cameraid,aroundid,Float:radius,direction)
{
	Debug(DEBUG_START,"MovePlayerCameraAroundPlayer(%d,%d,%d,%f,%d)",playerid,cameraid,aroundid,radius,direction);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"MovePlayerCameraAroundPlayer(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraAroundPlayer (offline player, playerid = %d)",playerid);
		return 0;
	}
	if(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_NONE)
	{
		Debug(DEBUG_END,"MovePlayerCameraAroundPlayer(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraAroundPlayer (camera also moved, playerid = %d)",playerid);
		return 0;
	}
	if(ModeCamera_Player[playerid][pLookPosObjectId] != INVALID_OBJECT_ID)
	{
		Debug(DEBUG_END,"MovePlayerCameraAroundPlayer(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraAroundPlayer (look pos moved)");
		return 0;
	}
	if(!IsPlayerConnected(aroundid))
	{
		Debug(DEBUG_END,"MovePlayerCameraAroundPlayer(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraAroundPlayer (offline player, playerid = %d)",aroundid);
		return 0;
	}
	Debug(DEBUG_ACTION,"set data");
	ModeCamera_Player[playerid][pCameraMode] = CAMERA_MODE_MOVE_POS_AROUND;
	ModeCamera_Player[playerid][pCameraId] = cameraid;
	ModeCamera_Player[playerid][pAround][aPlayerId] = aroundid;
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] = radius;
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] = 0.0;
	ModeCamera_Player[playerid][pAround][aDirection] = direction;
	Debug(DEBUG_END,"MovePlayerCameraAroundPlayer(reason: complete)");
	return 1;
}

stock MovePlayerCameraAroundXYZ(playerid,cameraid,Float:X,Float:Y,Float:Z,Float:radius,direction)
{
	Debug(DEBUG_START,"MovePlayerCameraAroundXYZ(%d,%d,%f,%f,%f,%f,%d)",playerid,cameraid,X,Y,Z,radius,direction);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"MovePlayerCameraAroundXYZ(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraAroundXYZ (offline player, playerid = %d)",playerid);
		return 0;
	}
	if(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_NONE)
	{
		Debug(DEBUG_END,"MovePlayerCameraAroundXYZ(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraAroundXYZ (camera also moved, playerid = %d)",playerid);
		return 0;
	}
	if(ModeCamera_Player[playerid][pLookPosObjectId] != INVALID_OBJECT_ID)
	{
		Debug(DEBUG_END,"MovePlayerCameraAroundXYZ(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraAroundXYZ (look pos moved)");
		return 0;
	}
	Debug(DEBUG_ACTION,"set data");
	ModeCamera_Player[playerid][pCameraMode] = CAMERA_MODE_MOVE_POS_AROUND2;
	ModeCamera_Player[playerid][pCameraId] = cameraid;
	ModeCamera_Player[playerid][pCoords][0] = X;
	ModeCamera_Player[playerid][pCoords][1] = Y;
	ModeCamera_Player[playerid][pCoords][2] = Z;
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] = radius;
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] = 0.0;
	ModeCamera_Player[playerid][pAround][aDirection] = direction;	
	Debug(DEBUG_END,"MovePlayerCameraAroundXYZ(reason: complete)");
	return 1;
}

stock MovePlayerCameraAroundXYZEx(playerid,cameraid,Float:X,Float:Y,Float:Z,Float:radius,Float:minAngle,Float:maxAngle,direction)
{
	Debug(DEBUG_START,"MovePlayerCameraAroundXYZEx(%d,%d,%f,%f,%f,%f,%d)",playerid,cameraid,X,Y,Z,radius,direction);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"MovePlayerCameraAroundXYZEx(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraAroundXYZEx (offline player, playerid = %d)",playerid);
		return 0;
	}
	if(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_NONE)
	{
		Debug(DEBUG_END,"MovePlayerCameraAroundXYZEx(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraAroundXYZEx (camera also moved, playerid = %d)",playerid);
		return 0;
	}
	if(ModeCamera_Player[playerid][pLookPosObjectId] != INVALID_OBJECT_ID)
	{
		Debug(DEBUG_END,"MovePlayerCameraAroundXYZEx(reason: error)");
		printf("[ERROR] Mode camera -> MovePlayerCameraAroundXYZEx (look pos moved)");
		return 0;
	}
	Debug(DEBUG_ACTION,"set data");
	ModeCamera_Player[playerid][pCameraMode] = CAMERA_MODE_MOVE_POS_AROUND3;
	ModeCamera_Player[playerid][pCameraId] = cameraid;
	ModeCamera_Player[playerid][pCoords][0] = X;
	ModeCamera_Player[playerid][pCoords][1] = Y;
	ModeCamera_Player[playerid][pCoords][2] = Z;
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] = radius;
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] = minAngle;
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE2] = maxAngle;
	ModeCamera_Player[playerid][pAround][aDirection] = direction;	
	Debug(DEBUG_END,"MovePlayerCameraAroundXYZEx(reason: complete)");
	return 1;
}

stock Float:GetPlayerCameraAroundRadius(playerid)
{
	Debug(DEBUG_START,"GetPlayerCameraAroundRadius(%d)",playerid);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"GetPlayerCameraAroundRadius(reason: error)");
		printf("[ERROR] Mode camera -> GetPlayerCameraAroundRadius (offline player, playerid = %d)",playerid);
		return 0;
	}
	if((ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND2) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND3))
	{
		Debug(DEBUG_END,"GetPlayerCameraAroundRadius(reason: error)");
		printf("[ERROR] Mode camera -> GetPlayerCameraAroundRadius (camera not moved around, playerid = %d)",playerid);
		return 0;
	}
	Debug(DEBUG_END,"GetPlayerCameraAroundRadius(reason: complete)");
	return ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS];
}

stock SetPlayerCameraAroundRadius(playerid,Float:radius)
{
	Debug(DEBUG_START,"SetPlayerCameraAroundRadius(%d,%f)",playerid,radius);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"SetPlayerCameraAroundRadius(reason: error)");
		printf("[ERROR] Mode camera -> SetPlayerCameraAroundRadius (offline player, playerid = %d)",playerid);
		return 0;
	}
	if((ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND2) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND3))
	{
		Debug(DEBUG_END,"SetPlayerCameraAroundRadius(reason: error)");
		printf("[ERROR] Mode camera -> SetPlayerCameraAroundRadius (camera not moved around, playerid = %d)",playerid);
		return 0;
	}
	Debug(DEBUG_ACTION,"set data");
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] = radius;
	Debug(DEBUG_END,"SetPlayerCameraAroundRadius(reason: complete)");
	return 1;
}

stock GetPlayerCameraAroundCenter(playerid,&Float:X,&Float:Y,&Float:Z)
{
	Debug(DEBUG_START,"GetPlayerCameraAroundCenter(%d)",playerid);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"GetPlayerCameraAroundCenter(reason: error)");
		printf("[ERROR] Mode camera -> GetPlayerCameraAroundCenter (offline player, playerid = %d)",playerid);
		return 0;
	}
	if((ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND2) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND3))
	{
		Debug(DEBUG_END,"GetPlayerCameraAroundCenter(reason: error)");
		printf("[ERROR] Mode camera -> GetPlayerCameraAroundCenter (camera not moved around, playerid = %d)",playerid);
		return 0;
	}
	X = ModeCamera_Player[playerid][pCoords][0];
	Y = ModeCamera_Player[playerid][pCoords][1];
	Z = ModeCamera_Player[playerid][pCoords][2];
	Debug(DEBUG_END,"GetPlayerCameraAroundCenter(reason: complete)");
	return 1;
}

stock SetPlayerCameraAroundCenter(playerid,Float:X,Float:Y,Float:Z)
{
	Debug(DEBUG_START,"SetPlayerCameraAroundCenter(%d,%f,%f,%f)",playerid,X,Y,Z);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"SetPlayerCameraAroundCenter(reason: error)");
		printf("[ERROR] Mode camera -> SetPlayerCameraAroundCenter (offline player, playerid = %d)",playerid);
		return 0;
	}
	if((ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND2) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND3))
	{
		Debug(DEBUG_END,"SetPlayerCameraAroundCenter(reason: error)");
		printf("[ERROR] Mode camera -> SetPlayerCameraAroundCenter (camera not moved around, playerid = %d)",playerid);
		return 0;
	}
	ModeCamera_Player[playerid][pCoords][0] = X;
	ModeCamera_Player[playerid][pCoords][1] = Y;
	ModeCamera_Player[playerid][pCoords][2] = Z;
	Debug(DEBUG_END,"SetPlayerCameraAroundCenter(reason: complete)");
	return 1;
}

stock GetPlayerCameraAroundDirection(playerid)
{
	Debug(DEBUG_START,"GetPlayerCameraAroundDirection(%d)",playerid);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"GetPlayerCameraAroundDirection(reason: error)");
		printf("[ERROR] Mode camera -> GetPlayerCameraAroundDirection (offline player, playerid = %d)",playerid);
		return 0;
	}
	if((ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND2) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND3))
	{
		Debug(DEBUG_END,"GetPlayerCameraAroundDirection(reason: error)");
		printf("[ERROR] Mode camera -> GetPlayerCameraAroundDirection (camera not moved around, playerid = %d)",playerid);
		return 0;
	}
	Debug(DEBUG_END,"GetPlayerCameraAroundDirection(reason: complete)");
	return ModeCamera_Player[playerid][pAround][aDirection];
}

stock SetPlayerCameraAroundDirection(playerid,direction)
{
	Debug(DEBUG_START,"SetPlayerCameraAroundDirection(%d,%d)",playerid,direction);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"SetPlayerCameraAroundDirection(reason: error)");
		printf("[ERROR] Mode camera -> SetPlayerCameraAroundDirection (offline player, playerid = %d)",playerid);
		return 0;
	}
	if((ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND2) &&
		(ModeCamera_Player[playerid][pCameraMode] != CAMERA_MODE_MOVE_POS_AROUND3))
	{
		Debug(DEBUG_END,"SetPlayerCameraAroundDirection(reason: error)");
		printf("[ERROR] Mode camera -> SetPlayerCameraAroundDirection (camera not moved around, playerid = %d)",playerid);
		return 0;
	}
	Debug(DEBUG_END,"SetPlayerCameraAroundDirection(reason: complete)");
	ModeCamera_Player[playerid][pAround][aDirection] = direction;
	new Float:tmp = ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE];
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] = ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE2];
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE2] = tmp;
	return 1;
}

stock StopPlayerCamera(playerid,bool:returncamera)
{
	Debug(DEBUG_START,"StopPlayerCamera(%d,%b)",playerid,returncamera);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"StopPlayerCamera(reason: error)");
		printf("[ERROR] Mode camera -> StopPlayerCamera (offline player, playerid = %d)",playerid);
		return 0;
	}
	if((ModeCamera_Player[playerid][pCameraMode] == CAMERA_MODE_MOVE_NONE) &&
		(ModeCamera_Player[playerid][pLookPosObjectId] == INVALID_OBJECT_ID))
	{
		Debug(DEBUG_END,"StopPlayerCamera(reason: error)");
		printf("[ERROR] Mode camera -> StopPlayerCamera (camera not moved)");
		return 0;
	}
	if(ModeCamera_Player[playerid][pLookPosObjectId] != INVALID_OBJECT_ID)
	{
		DestroyPlayerObject(playerid,ModeCamera_Player[playerid][pLookPosObjectId]);
		ModeCamera_Player[playerid][pLookPosObjectId] = INVALID_OBJECT_ID;
	}
	if(ModeCamera_Player[playerid][pPosObjectId] != INVALID_OBJECT_ID)
	{
		DestroyPlayerObject(playerid,ModeCamera_Player[playerid][pPosObjectId]);
		ModeCamera_Player[playerid][pPosObjectId] = INVALID_OBJECT_ID;
	}
	ModeCamera_ResetStat(playerid);
	if(returncamera == true) SetCameraBehindPlayer(playerid);
	Debug(DEBUG_END,"StopPlayerCamera(reason: complete)");
	return 1;
}

stock IsPlayerCameraMoving(playerid)
{
	Debug(DEBUG_START,"IsPlayerCameraMoving(%d)",playerid);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"IsPlayerCameraMoving(reason: error)");
		printf("[ERROR] Mode camera -> IsPlayerCameraMoving (offline player, playerid = %d)",playerid);
		return 0;
	}
	Debug(DEBUG_END,"IsPlayerCameraMoving(reason: complete)");
	if((ModeCamera_Player[playerid][pCameraMode] == CAMERA_MODE_MOVE_NONE) && (ModeCamera_Player[playerid][pLookPosObjectId] == INVALID_OBJECT_ID)) return 0;
	return 1;
}

// --------------------------------------------------
// Obligatory functions
// --------------------------------------------------
ModeCamera_OnGameModeInit()
{
	Debug(DEBUG_START,"ModeCamera_OnGameModeInit");
	for(new i = 0;i < MAX_OBJECTS;i++) ModeCameraObjectsOffsets[i] = INVALID_PLAYER_ID;
	SetTimer("CameraUpdate",20,1);
	print("Mode camera system loaded.");
	Debug(DEBUG_END,"ModeCamera_OnGameModeInit");
}

ModeCamera_ResetStat(playerid)
{
	Debug(DEBUG_START,"ModeCamera_ResetStat(%d)",playerid);
	if(ModeCamera_Player[playerid][pPosObjectId] != INVALID_OBJECT_ID)
	{
		ModeCameraObjectsOffsets[ ModeCamera_Player[playerid][pPosObjectId] ] = INVALID_PLAYER_ID;
		ModeCamera_Player[playerid][pPosObjectId] = INVALID_OBJECT_ID;
	}
	if(ModeCamera_Player[playerid][pLookPosObjectId] != INVALID_OBJECT_ID)
	{
		ModeCameraObjectsOffsets[ ModeCamera_Player[playerid][pLookPosObjectId] ] = INVALID_PLAYER_ID;
		ModeCamera_Player[playerid][pLookPosObjectId] = INVALID_OBJECT_ID;
	}
	ModeCamera_Player[playerid][pCameraMode] = CAMERA_MODE_MOVE_NONE;
	ModeCamera_Player[playerid][pCameraId] = INVALID_MODECAMERA_ID;
	for(new i = 0;i < 3;i++) ModeCamera_Player[playerid][pCoords][i] = 0.0;
	ModeCamera_Player[playerid][pAround][aPlayerId] = INVALID_PLAYER_ID;
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] = 0.0;
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] = 0.0;
	ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE2] = 0.0;
	ModeCamera_Player[playerid][pAround][aDirection] = 0;	
	Debug(DEBUG_END,"ModeCamera_ResetStat");
}

ModeCamera_OnObjectMoved(objectid)
{
	Debug(DEBUG_START,"ModeCamera_OnObjectMoved(%d)",objectid);
	if(ModeCameraObjectsOffsets[objectid] != INVALID_PLAYER_ID)
	{
		new playerid = ModeCameraObjectsOffsets[objectid];
		Debug(DEBUG_ACTION,"attached to %d",playerid);
		if(ModeCamera_Player[playerid][pPosObjectId] == objectid)
		{
			DestroyPlayerObject(playerid,ModeCamera_Player[playerid][pPosObjectId]);
			OnPlayerCameraCompleteMoving(playerid,ModeCamera_Player[playerid][pCameraId]);
			ModeCameraObjectsOffsets[ ModeCamera_Player[playerid][pPosObjectId] ] = INVALID_PLAYER_ID;
			ModeCamera_Player[playerid][pPosObjectId] = INVALID_OBJECT_ID;
			ModeCamera_Player[playerid][pCameraMode] = CAMERA_MODE_MOVE_NONE;
			ModeCamera_Player[playerid][pCameraId] = INVALID_MODECAMERA_ID;
			ModeCamera_Player[playerid][pAround][aPlayerId] = INVALID_PLAYER_ID;
			ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_RADIUS] = 0.0;
			ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE] = 0.0;
			ModeCamera_Player[playerid][pAround][aInfo][AROUND_INFO_ANGLE2] = 0.0;
			ModeCamera_Player[playerid][pAround][aDirection] = 0;
		}
		if(ModeCamera_Player[playerid][pLookPosObjectId] == objectid)
		{
			DestroyPlayerObject(playerid,ModeCamera_Player[playerid][pLookPosObjectId]);
			ModeCameraObjectsOffsets[ ModeCamera_Player[playerid][pLookPosObjectId] ] = INVALID_PLAYER_ID;
			ModeCamera_Player[playerid][pLookPosObjectId] = INVALID_OBJECT_ID;
			for(new i = 0;i < 3;i++) ModeCamera_Player[playerid][pCoords][i] = 0.0;
		}
	}
	Debug(DEBUG_END,"ModeCamera_OnObjectMoved");
}