/*
*	Created:			21.01.10
*	Author:				009
*	Last Modifed:		07.02.10
*	Description:		Основные мини-функции 
*
*	07.02.10:
*	1.Добавлены функции работы с действием игрока( SetPlayerAction , GetPlayerAction , PlayerAction )
*	2.Добавлены функции выбора действия ( AddActionSelectRow , ShowActionSelecting )
*	3.Добавлена функция показа окна помощи ( ShowHelpBoxForPlayer )
*/

#if defined _mode_core_included
	#endinput
#endif

#define _mode_core_included
#pragma library mode_core

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

// --------------------------------------------------
// defines
// --------------------------------------------------
#define GetDistanceBetweenCoords(%1,%2,%3,%4,%5,%6) floatsqroot((%4 - %1)*(%4 - %1) + (%5 - %2)*(%5 - %2) + (%6 - %3)*(%6 - %3))
#define GetMaxPlayer() MaxPlayerId
#define IsPlayerControllable(%1) ModeCore_Player[%1][pIsControllable]
#define MoveCoordsOnAngleByDistance(%1,%2,%3,%4) \
	%1 += (%4 * floatsin(-%3, degrees)); \
	%2 += (%4 * floatcos(-%3, degrees))
#define GetPlayerAction(%1) ModeCore_Player[%1][pAction]
#define PlayerAction(%1,%2) OnPlayerAction(%1,%2)
#define fixchars(%1) for(new charfixloop=0;charfixloop<strlen(%1);charfixloop++)if(%1[charfixloop]<0)%1[charfixloop]+=256
#define nullstr(%1) %1[0] = 0

#define HELP_BOX_SHOW_TIME 10000
#define MAX_ACTION_SELECT 1


// --------------------------------------------------
// enums
// --------------------------------------------------
enum ActionSelectingInfo {
	bool:aActive,
	Text:aLeft,
	Text:aCenter,
	Text:aRight,
	aAction
};
enum ModeCorePlayerInfo {
	bool:pIsControllable,
	bool:pInActionSelect,
	bool:pIsHelpBoxShowed,
	pAction,
	pLeftId,
	pCenterId,
	pRightId,
	Text:pHelpBoxText[2],
	pHelpBoxWaiting[10]
};

// --------------------------------------------------
// news
// --------------------------------------------------
new MaxPlayerId,
	ModeCore_Player[MAX_PLAYERS][ModeCorePlayerInfo];
static
	ActionSelect[MAX_ACTION_SELECT][ActionSelectingInfo],
	Float:Citys[][4] = {
		{44.60,-2892.90,2997.00,-768.00},
		{-2997.40,-1115.50,-1213.90,1659.60},
		{869.40,596.30,2997.00,2993.80}
	};

// --------------------------------------------------
// forwards
// --------------------------------------------------
forward HidePlayerHelpBox(playerid);

// --------------------------------------------------
// natives list (for pawno functions list)
// --------------------------------------------------
/*
native StripNL(str[]);
native GetMaxPlayer();
native GetDistanceBetweenCoords(Float:X1,Float:Y1,Float:Z1,Float:X2,Float:Y2,Float:Z2);
native TogglePlayerControllableEx(playerid,bool:toggle);
native IsPlayerControllable(playerid);
native MoveCoordsOnAngleByDistance(Float:X,Float:Y,Float:angle,Float:distance);
native SetPlayerAction(playerid,actionid);
native GetPlayerAction(playerid);
native PlayerAction(playerid,actionid);
native AddActionSelectRow(const actionname[],actionid);
native ShowActionSelecting(playerid);
native ShowHelpBoxForPlayer(playerid,helpboxid,info[]);
native GetPlayerClosestPlayer(playerid);
native fixchars(string[]);
native nullstr(string[]);
native IsPlayerInRangeOfPlayer(playerid,Float:range,pid);
native PreLoadAnimation(playerid,animlib[]);
native GetPlayerCity(playerid);
*/

// --------------------------------------------------
// stocks
// --------------------------------------------------
stock StripNL(str[]) // by Y_Less
{
	new l = strlen(str);
	while (l-- && str[l] <= ' ') str[l] = '\0';
}

stock TogglePlayerControllableEx(playerid,bool:toggle)
{
	ModeCore_Player[playerid][pIsControllable] = toggle;
	TogglePlayerControllable(playerid,toggle);
}

stock SetPlayerAction(playerid,actionid)
{
	OnPlayerActionChange(playerid,actionid,ModeCore_Player[playerid][pAction]);
	ModeCore_Player[playerid][pAction] = actionid;
}

stock AddActionSelectRow(actionname[],actionid)
{
	Debug(DEBUG_START,"AddActionSelectRow('%s',%d)",actionname,actionid);
	for(new id = 0;id < MAX_ACTION_SELECT;id++)
	{
		if(ActionSelect[id][aActive] == true) continue;
		// Status
		ActionSelect[id][aActive] = true;
		// Left sel
		ActionSelect[id][aLeft] = TextDrawCreate(220.0,370.0,actionname);
		TextDrawAlignment(ActionSelect[id][aLeft],3);
		TextDrawSetShadow(ActionSelect[id][aLeft],0);
		TextDrawFont(ActionSelect[id][aLeft],2);
		// Center sel
		ActionSelect[id][aCenter] = TextDrawCreate(320.0,360.0,actionname);
		TextDrawLetterSize(ActionSelect[id][aCenter],0.399999,2.400000);
		TextDrawAlignment(ActionSelect[id][aCenter],2);
		TextDrawSetShadow(ActionSelect[id][aCenter],0);
		TextDrawFont(ActionSelect[id][aCenter],2);
		// Right sel
		ActionSelect[id][aRight] = TextDrawCreate(420.0,370.0,actionname);
		TextDrawAlignment(ActionSelect[id][aRight],1);
		TextDrawSetShadow(ActionSelect[id][aRight],0);
		TextDrawFont(ActionSelect[id][aRight],2);
		// Parameters
		ActionSelect[id][aAction] = actionid;
		Debug(DEBUG_END,"AddActionSelectRow(reason: complete)");
		return id;
	}
	Debug(DEBUG_END,"AddActionSelectRow(reason: error)");
	print("[WARNING] Mode Core -> AddActionSelectRow (all slots used)");
	return MAX_ACTION_SELECT;
}

stock ShowActionSelecting(playerid)
{
	Debug(DEBUG_START,"ShowActionSelecting(%d)",playerid);
	new cid,
		rid;
	for(cid = 0;cid < MAX_ACTION_SELECT;cid++)
	{
		if(ActionSelect[cid][aActive] == false) continue;
		// Test player info for this select
		if(!OnPlayerActionSelectCheck(playerid,ActionSelect[cid][aAction])) continue;
		ModeCore_Player[playerid][pInActionSelect] = true;
		ModeCore_Player[playerid][pCenterId] = cid;
		TextDrawShowForPlayer(playerid,ActionSelect[cid][aCenter]);
		break;
	}
	if(cid == MAX_ACTION_SELECT) {Debug(DEBUG_END,"ShowActionSelecting(reason: complete [1])");return 0;}
	ModeCore_Player[playerid][pLeftId] = MAX_ACTION_SELECT;
	// Левый выбор не ищем,т.к. мы отображаем начальное.Ищем сразу правый
	for(rid = (cid + 1);rid < MAX_ACTION_SELECT;rid++)
	{
		if(ActionSelect[rid][aActive] == false) continue;
		// Test player info for this select
		if(!OnPlayerActionSelectCheck(playerid,ActionSelect[rid][aAction])) continue;
		ModeCore_Player[playerid][pRightId] = rid;
		TextDrawShowForPlayer(playerid,ActionSelect[rid][aRight]);
		break;
	}
	if(rid == MAX_ACTION_SELECT) ModeCore_Player[playerid][pRightId] = MAX_ACTION_SELECT;
	TogglePlayerControllableEx(playerid,false);
	Debug(DEBUG_END,"ShowActionSelecting(reason: complete [2])");
	return 1;
}

stock ShowHelpBoxForPlayer(playerid,helpboxid,info[])
{
	Debug(DEBUG_START,"ShowHelpBoxForPlayer(%d,%d,'%s')",playerid,helpboxid,info);
	if(ModeCore_Player[playerid][pIsHelpBoxShowed] == true)
	{
		TextDrawHideForPlayer(playerid,ModeCore_Player[playerid][pHelpBoxText][0]);
		TextDrawHideForPlayer(playerid,ModeCore_Player[playerid][pHelpBoxText][1]);
		TextDrawDestroy(ModeCore_Player[playerid][pHelpBoxText][0]);
		TextDrawDestroy(ModeCore_Player[playerid][pHelpBoxText][1]);
	}
	new Float:sizey = 1.0 + 0.6; // 1.0 - сверху и снизу отступы от краёв
	while((pos = strfind(info,"~n~",false,pos)) != -1)
	{
		sizey += 0.6;
		pos += 3;
	}	
	ModeCore_Player[playerid][pHelpBoxText][0] = TextDrawCreate(15.0,70.0,"_");
	TextDrawUseBox(ModeCore_Player[playerid][pHelpBoxText][0],1);
	TextDrawTextSize(ModeCore_Player[playerid][pHelpBoxText][0],160.0,0.0);
	TextDrawLetterSize(ModeCore_Player[playerid][pHelpBoxText][0],0.0,sizey);
	TextDrawBoxColor(ModeCore_Player[playerid][pHelpBoxText][0],0x000000FF);	
	ModeCore_Player[playerid][pHelpBoxText][1] = TextDrawCreate(15.5,70.5,info);
	TextDrawShowForPlayer(playerid,ModeCore_Player[playerid][pHelpBoxText][0]);
	TextDrawShowForPlayer(playerid,ModeCore_Player[playerid][pHelpBoxText][1]);
	ModeCore_Player[playerid][pIsHelpBoxShowed] = true;
	SetTimerEx("HidePlayerHelpBox",HELP_BOX_SHOW_TIME,0,"d",playerid);
	Debug(DEBUG_END,"ShowHelpBoxForPlayer(reason: complete)");
	return 1;
}

stock GetPlayerClosestPlayer(playerid)
{
	Debug(DEBUG_START,"GetPlayerClosestPlayer(%d)",playerid);
	if(!IsPlayerConnected(playerid))
	{
		Debug(DEBUG_END,"GetPlayerClosestPlayer(reason: error)");
		printf("[ERROR] Mode Core -> GetPlayerClosestPlayer (invalid player - %d)",playerid);
		return INVALID_PLAYER_ID;
	}
	new pid = INVALID_PLAYER_ID,
		Float:distance = 69000.0,
		Float:tmp[7];
	GetPlayerPos(playerid,tmp[0],tmp[1],tmp[2]);
	for(new i = 0;i <= GetMaxPlayer();i++)
	{
		if(i == playerid) continue;
		if(!IsPlayerConnected(i)) continue;
		if(!IsPlayerStreamedIn(i,playerid)) continue;
		GetPlayerPos(i,tmp[3],tmp[4],tmp[5]);
		tmp[6] = GetDistanceBetweenCoords(tmp[0],tmp[1],tmp[2],tmp[3],tmp[4],tmp[5]);
		if(distance < tmp[6]) continue;
		distance = tmp[6];
		pid = i;
	}
	Debug(DEBUG_END,"GetPlayerClosestPlayer(reason: complete)");
	return pid;
}

stock IsPlayerInRangeOfPlayer(playerid,Float:range,pid)
{
	Debug(DEBUG_START,"IsPlayerInRangeOfPlayer(%d,%f,%d)",playerid,range,pid);
	new Float:tmp[3];
	GetPlayerPos(pid,tmp[0],tmp[1],tmp[2]);
	Debug(DEBUG_END,"IsPlayerInRangeOfPlayer(reason: complete)");
	return IsPlayerInRangeOfPoint(playerid,range,tmp[0],tmp[1],tmp[2]);
}

stock PreLoadAnimation(playerid,animlib[])
{
	Debug(DEBUG_START,"PreLoadAnimation(%d,'%s')",playerid,animlib);
	ApplyAnimation(playerid,animlib,"",0.0,0,0,0,0,0);
	Debug(DEBUG_END,"PreLoadAnimation(reason: complete)");
}

stock GetPlayerCity(playerid)
{
	Debug(DEBUG_START,"GetPlayerCity(%d)",playerid);
	new Float:X,
		Float:Y,
		Float:Z;
	GetPlayerPos(playerid,X,Y,Z);
	for(new i = 0;i < sizeof(Citys);i++)
	{
		if((X > Citys[i][0]) && (X < Citys[i][2]) && (Y > Citys[i][1]) && (Y < Citys[i][3])) {Debug(DEBUG_END,"GetPlayerCity(reason: complete)");return i;}
	}
	Debug(DEBUG_END,"GetPlayerCity(reason: complete)");
	return -1;
}

/*
stock adler32(buf[])
{
	new length=strlen(buf);
	new s1 = 1;
	new s2 = 0;
	for (new n=0; n<length; n++)
	{
		s1 = (s1 + buf[n]) % 65521;
		s2 = (s2 + s1) % 65521;
	}
	return (s2 << 16) + s1;
}
*/

// --------------------------------------------------
// Obligatory functions
// --------------------------------------------------
ModeCore_OnPlayerConnect(playerid)
{
	Debug(DEBUG_START,"ModeCore_OnPlayerConnect(%d)",playerid);
	if(MaxPlayerId < playerid) MaxPlayerId = playerid;
	Debug(DEBUG_END,"ModeCore_OnPlayerConnect (reason: complete");
}

ModeCore_OnPlayerDisconnect(playerid,reason)
{
	Debug(DEBUG_START,"ModeCore_OnPlayerDisconnect(%d,%d)",playerid,reason);
	if(MaxPlayerId == playerid) 
	{
		do MaxPlayerId--;
		while((IsPlayerConnected(MaxPlayerId) == 0) && (MaxPlayerId > 0));
	}
	Debug(DEBUG_END,"ModeCore_OnPlayerDisconnect (reason: complete");
}

ModeCore_OnPlayerKeyStateChange(playerid,newkeys,oldkeys)
{
	Debug(DEBUG_START,"ModeCore_OnPlayerKeyStateChange(%d,%d,%d)",playerid,newkeys,oldkeys);
	switch(ModeCore_Player[playerid][pInActionSelect])
	{
		case false:
		{
			if(newkeys == ACTION_SELECT_KEY) ShowActionSelecting(playerid);
		}
		case true:
		{
			switch(newkeys)
			{
				case KEY_ANALOG_LEFT:
				{
					if(ModeCore_Player[playerid][pLeftId] == MAX_ACTION_SELECT) {Debug(DEBUG_END,"ModeCore_OnPlayerKeyStateChange(reason: complete [1])");return 1;}
					if(ModeCore_Player[playerid][pRightId] != MAX_ACTION_SELECT) TextDrawHideForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pRightId] ][aRight]);
					TextDrawShowForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pCenterId] ][aRight]);
					ModeCore_Player[playerid][pRightId] = ModeCore_Player[playerid][pCenterId];
					TextDrawHideForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pCenterId] ][aCenter]);		
					ModeCore_Player[playerid][pCenterId] = ModeCore_Player[playerid][pLeftId];
					TextDrawShowForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pCenterId] ][aCenter]);
					if(ModeCore_Player[playerid][pLeftId] != MAX_ACTION_SELECT) TextDrawHideForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pLeftId] ][aLeft]);
					new lid;
					for(lid = (ModeCore_Player[playerid][pCenterId] - 1);lid >= 0;lid--)
					{
						if(ActionSelect[lid][aActive] == false) continue;
						// Test player info for this select
						if(!OnPlayerActionCheck(playerid,ActionSelect[lid][aAction])) continue;
						ModeCore_Player[playerid][pLeftId] = lid;
						TextDrawShowForPlayer(playerid,ActionSelect[lid][aLeft]);
						break;
					}
					if(lid == -1) ModeCore_Player[playerid][pLeftId] = MAX_ACTION_SELECT;
					Debug(DEBUG_END,"ModeCore_OnPlayerKeyStateChange(reason: complete [2])");
					return 1;
				}
				case KEY_ANALOG_RIGHT:
				{
					if(ModeCore_Player[playerid][pRightId] == MAX_ACTION_SELECT) {Debug(DEBUG_END,"ModeCore_OnPlayerKeyStateChange(reason: complete [3])");return 1;}
					if(ModeCore_Player[playerid][pLeftId] != MAX_ACTION_SELECT) TextDrawHideForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pLeftId] ][aLeft]);
					TextDrawShowForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pCenterId] ][aLeft]);
					ModeCore_Player[playerid][pLeftId] = ModeCore_Player[playerid][pCenterId];
					TextDrawHideForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pCenterId] ][aCenter]);
					ModeCore_Player[playerid][pCenterId] = ModeCore_Player[playerid][pRightId];
					TextDrawShowForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pCenterId] ][aCenter]);
					if(ModeCore_Player[playerid][pRightId] != MAX_ACTION_SELECT) TextDrawHideForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pRightId] ][aRight]);
					new rid;
					for(rid = (ModeCore_Player[playerid][pCenterId] + 1);rid < MAX_ACTION_SELECT;rid++)
					{
						if(ActionSelect[rid][aActive] == false) continue;
						// Test player info for this select
						if(!OnPlayerActionCheck(playerid,ActionSelect[rid][aAction])) continue;
						ModeCore_Player[playerid][pRightId] = rid;
						TextDrawShowForPlayer(playerid,ActionSelect[rid][aRight]);
						break;
					}
					if(rid == MAX_ACTION_SELECT) ModeCore_Player[playerid][pRightId] = MAX_ACTION_SELECT;
					Debug(DEBUG_END,"ModeCore_OnPlayerKeyStateChange(reason: complete [4])");
					return 1;
				}
				case KEY_SPRINT:
				{
					OnPlayerActionSelect(playerid,ActionSelect[ ModeCore_Player[playerid][pCenterId] ][aAction]);
					if(ModeCore_Player[playerid][pLeftId] != MAX_ACTION_SELECT) 
					{
						TextDrawHideForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pLeftId] ][aLeft]);
						ModeCore_Player[playerid][pLeftId] = MAX_ACTION_SELECT;
					}
					if(ModeCore_Player[playerid][pCenterId] != MAX_ACTION_SELECT) 
					{
						TextDrawHideForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pCenterId] ][aCenter]);
						ModeCore_Player[playerid][pCenterId] = MAX_ACTION_SELECT;
					}
					if(ModeCore_Player[playerid][pRightId] != MAX_ACTION_SELECT) 
					{
						TextDrawHideForPlayer(playerid,ActionSelect[ ModeCore_Player[playerid][pRightId] ][aRight]);
						ModeCore_Player[playerid][pRightId] = MAX_ACTION_SELECT;
					}
					ModeCore_Player[playerid][pInActionSelect] = false;
					TogglePlayerControllableEx(playerid,true);
					Debug(DEBUG_END,"ModeCore_OnPlayerKeyStateChange(reason: complete [5])");
					return 1;
				}
			}
		}
	}
	Debug(DEBUG_END,"ModeCore_OnPlayerKeyStateChange(reason: complete [6])");
	return 0;
}

// --------------------------------------------------
// publics
// --------------------------------------------------
public HidePlayerHelpBox(playerid)
{
	Debug(DEBUG_START,"HidePlayerHelpBox(%d)",playerid);
	TextDrawHideForPlayer(playerid,ModeCore_Player[playerid][pHelpBoxText][0]);
	TextDrawHideForPlayer(playerid,ModeCore_Player[playerid][pHelpBoxText][1]);
	TextDrawDestroy(ModeCore_Player[playerid][pHelpBoxText][0]);
	TextDrawDestroy(ModeCore_Player[playerid][pHelpBoxText][1]);
	ModeCore_Player[playerid][pIsHelpBoxShowed] = false;
	Debug(DEBUG_END,"HidePlayerHelpBox(reason: complete)");
}