/* AMX Mod X 
*
* by the AMX Mod X Development Team
*  originally developed by OLO
*
*
*  This program is free software; you can redistribute it and/or modify it
*  under the terms of the GNU General Public License as published by the
*  Free Software Foundation; either version 2 of the License, or (at
*  your option) any later version.
*
*  This program is distributed in the hope that it will be useful, but
*  WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
*  General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software Foundation,
*  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*  In addition, as a special exception, the author gives permission to
*  link the code of this program with the Half-Life Game Engine ("HL
*  Engine") and Modified Game Libraries ("MODs") developed by Valve,
*  L.L.C ("Valve"). You must obey the GNU General Public License in all
*  respects for all of the code used other than the HL Engine and MODs
*  from Valve. If you modify this file, you may extend this exception
*  to your version of the file, but you are not obligated to do so. If
*  you do not wish to do so, delete this exception statement from your
*  version.
*/

#include <time.h>
#include "amxmodx.h"

static cell AMX_NATIVE_CALL get_xvar_id(AMX *amx, cell *params)
{
  int len;
  char* sName = get_amxstring(amx,params[1],0,len);
  cell ptr;

  for ( CPluginMngr::iterator a = g_plugins.begin(); a ; ++a )
  {
  if ( (*a).isValid() && amx_FindPubVar( (*a).getAMX() , sName , &ptr ) == AMX_ERR_NONE )
    return g_xvars.put( (*a).getAMX() , get_amxaddr(  (*a).getAMX() , ptr )  );
  }
  return -1;
}

static cell AMX_NATIVE_CALL get_xvar_num(AMX *amx, cell *params)
{
  return  g_xvars.getValue(params[1]);
}

static cell AMX_NATIVE_CALL set_xvar_num(AMX *amx, cell *params)
{
  if ( g_xvars.setValue( params[1] , params[2] ) ){
  amx_RaiseError(amx,AMX_ERR_NATIVE);
  return 0;
  }
  return 1;
}

static cell AMX_NATIVE_CALL xvar_exists(AMX *amx, cell *params)
{
   return (get_xvar_id( amx , params ) != -1) ? 1 : 0;
}

static cell AMX_NATIVE_CALL emit_sound(AMX *amx, cell *params) /* 7 param */
{

  int len;
  char* szSample = get_amxstring(amx,params[3],0,len);
  REAL vol = amx_ctof(params[4]);
  REAL att = amx_ctof(params[5]);
  int channel = params[2];
  int pitch = params[7];
  int flags = params[6];

  if (params[1] == 0) {
    for(int i = 1; i <= gpGlobals->maxClients ; ++i){
      CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
      if (pPlayer->ingame)
        EMIT_SOUND_DYN2(pPlayer->pEdict,channel, szSample, vol, att,flags , pitch);
    }
  }
  else
  {
  edict_t* pEdict = INDEXENT(params[1]);
  if (!FNullEnt(pEdict))
    EMIT_SOUND_DYN2(pEdict,channel , szSample, vol, att, flags, pitch);
  }

  return 1;
}

static cell AMX_NATIVE_CALL server_print(AMX *amx, cell *params) /* 1 param */
{
  int len;
  g_langMngr.SetDefLang(LANG_SERVER);			// Default language = server
  char* message = format_amxstring(amx,params,1,len);
  if ( len > 254 ) len = 254;
  message[len++]='\n';
  message[len]=0;
  SERVER_PRINT( message );
  return len;
}

static cell AMX_NATIVE_CALL engclient_print(AMX *amx, cell *params)  /* 3 param */
{
	int len;
	char *msg;
	if (params[1] == 0)
	{
		for(int i = 1; i <= gpGlobals->maxClients; ++i)
		{
			CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
			if (pPlayer->ingame)
			{
				g_langMngr.SetDefLang(i);
				msg = format_amxstring(amx, params, 3, len);
				msg[len++] = '\n';
				msg[len] = 0;
				CLIENT_PRINT(pPlayer->pEdict, (PRINT_TYPE)(int)params[2], msg);
			}
		}
	}
	else
	{
		int index = params[1];
		if (index < 1 || index > gpGlobals->maxClients){
			amx_RaiseError(amx,AMX_ERR_NATIVE);
			return 0;
		}
		CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
		if (pPlayer->ingame)
		{
			g_langMngr.SetDefLang(index);
			msg = format_amxstring(amx, params, 3, len);
			msg[len++] = '\n';
			msg[len] = 0;
			CLIENT_PRINT(pPlayer->pEdict, (PRINT_TYPE)(int)params[2], msg);
		}
	}
	return len;
}

static cell AMX_NATIVE_CALL console_cmd(AMX *amx, cell *params) /* 2 param */
{
  int index = params[1];
  g_langMngr.SetDefLang(index);
  int len;
  char* cmd = format_amxstring(amx,params,2,len);
  cmd[len++]='\n';
  cmd[len]=0;

  if (index < 1 || index > gpGlobals->maxClients){
    SERVER_COMMAND( cmd );
  }
  else{
    CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
    if ( !pPlayer->bot && pPlayer->initialized )  CLIENT_COMMAND(pPlayer->pEdict, UTIL_VarArgs("%s", cmd) );
  }

  return len;
}

static cell AMX_NATIVE_CALL console_print(AMX *amx, cell *params) /* 2 param */
{
	int index = params[1];
	if (index < 1 || index > gpGlobals->maxClients)
		g_langMngr.SetDefLang(LANG_SERVER);
	else
		g_langMngr.SetDefLang(index);

	int len;
	char* message = format_amxstring(amx,params,2,len);
	if (len > 254 )
		len = 254;
	message[len++] = '\n';
	message[len] = 0;
	if (index < 1 || index > gpGlobals->maxClients)
		SERVER_PRINT( message );
	else
	{
		CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
		if (pPlayer->ingame)
			UTIL_ClientPrint(pPlayer->pEdict, 2 , message );
	}
	return len;
}


static cell AMX_NATIVE_CALL client_print(AMX *amx, cell *params) /* 3 param */
{
	int len = 0;
	char *msg;
	if (params[1] == 0)
	{
		for (int i = 1; i <= gpGlobals->maxClients; ++i)
		{
			CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
			if (pPlayer->ingame)
			{
				g_langMngr.SetDefLang(i);
				msg = format_amxstring(amx, params, 3, len);
				msg[len++] = '\n';
				msg[len] = 0;
				UTIL_ClientPrint(pPlayer->pEdict, params[2], msg);
			}
		}
	}
	else
	{
		int index = params[1];
		if (index < 1 || index > gpGlobals->maxClients)
		{
			amx_RaiseError(amx,AMX_ERR_NATIVE);
			return 0;
		}
		CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
		g_langMngr.SetDefLang(index);
		msg = format_amxstring(amx, params, 3, len);
		msg[len++] = '\n';
		msg[len] = 0;
		if (pPlayer->ingame)
			UTIL_ClientPrint(pPlayer->pEdict, params[2], msg); //format_amxstring(amx, params, 3, len));
	}
	return len;
}

static cell AMX_NATIVE_CALL show_motd(AMX *amx, cell *params)  /* 3 param */
{
  int ilen;
  const char* szHead = get_amxstring(amx,params[3],0,ilen);
  if ( !ilen ) szHead = hostname->string;
  char* szBody = get_amxstring(amx,params[2],1,ilen);
  int iFile = 0;
  char* sToShow = NULL; // = szBody;
  if (ilen<128) sToShow = (char*)LOAD_FILE_FOR_ME( szBody , &iFile );
  if (!iFile)
    sToShow = szBody;
  else
    ilen = iFile;
  if (params[1] == 0) {
    for(int i = 1; i <= gpGlobals->maxClients; ++i){
      CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
      if (pPlayer->ingame)
        UTIL_ShowMOTD(pPlayer->pEdict, sToShow , ilen, szHead);
    }
  }
  else {
    int index = params[1];
    if (index < 1 || index > gpGlobals->maxClients){
      amx_RaiseError(amx,AMX_ERR_NATIVE);
      if (iFile) FREE_FILE(sToShow);
      return 0;
    }
    CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
    if (pPlayer->ingame)
      UTIL_ShowMOTD(pPlayer->pEdict, sToShow,ilen, szHead );
  }
  if (iFile) FREE_FILE(sToShow);
  return 1;
}

static cell AMX_NATIVE_CALL set_hudmessage(AMX *amx, cell *params)  /* 11 param */
{
  g_hudset.a1 = 0;
  g_hudset.a2 = 0;
  g_hudset.r2 = 255;
  g_hudset.g2 = 255;
  g_hudset.b2 = 250;
  g_hudset.r1 = params[1];
  g_hudset.g1 = params[2];
  g_hudset.b1 = params[3];
  g_hudset.x = amx_ctof(params[4]);
  g_hudset.y = amx_ctof(params[5]);
  g_hudset.effect = params[6];
  g_hudset.fxTime = amx_ctof(params[7]);
  g_hudset.holdTime = amx_ctof(params[8]);
  g_hudset.fadeinTime = amx_ctof(params[9]);
  g_hudset.fadeoutTime = amx_ctof(params[10]);
  g_hudset.channel = params[11];
  return 1;
}

static cell AMX_NATIVE_CALL show_hudmessage(AMX *amx, cell *params)  /* 2 param */
{
	int len=0;
	g_langMngr.SetDefLang(params[1]);
	char* message = NULL;
	if (params[1] == 0)
	{
		for (int i = 1; i <= gpGlobals->maxClients; ++i)
		{
			CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
			if (pPlayer->ingame)
			{
				g_langMngr.SetDefLang(i);
				message = UTIL_SplitHudMessage(format_amxstring(amx, params, 2, len));
				UTIL_HudMessage(pPlayer->pEdict, g_hudset, message);
			}
		}
	}
	else
	{
		message = UTIL_SplitHudMessage(format_amxstring(amx,params,2,len));
		int index = params[1];
		if (index < 1 || index > gpGlobals->maxClients){
			amx_RaiseError(amx,AMX_ERR_NATIVE);
			return 0;
		}
		CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
		if (pPlayer->ingame)
			UTIL_HudMessage(pPlayer->pEdict, g_hudset, message );
	}
	return len;
}

static cell AMX_NATIVE_CALL get_user_name(AMX *amx, cell *params)  /* 3 param */
{
  int index = params[1];
  return set_amxstring(amx,params[2],(index<1||index>gpGlobals->maxClients) ?
    hostname->string : g_players[index].name.c_str() , params[3]);
}

static cell AMX_NATIVE_CALL get_user_index(AMX *amx, cell *params)  /* 1 param */
{
  int i;
  char* sptemp = get_amxstring(amx,params[1],0,i);
  for(i = 1; i <= gpGlobals->maxClients; ++i) {
    CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
    if ( strcmp(pPlayer->name.c_str(), sptemp) == 0 )
      return i;
  }

  return 0;
}

static cell AMX_NATIVE_CALL is_dedicated_server(AMX *amx, cell *params)
{
  return (IS_DEDICATED_SERVER() ? 1 : 0);
}

static cell AMX_NATIVE_CALL is_linux_server(AMX *amx, cell *params)
{
#ifdef __linux__
  return 1;
#else
  return 0;
#endif
}

static cell AMX_NATIVE_CALL is_amd64_server(AMX *amx, cell *params)
{
#if PAWN_CELL_SIZE==64
  return 1;
#else
  return 0;
#endif
}

static cell AMX_NATIVE_CALL is_jit_enabled(AMX *amx, cell *params)		// PM: Useless ;P
{
#ifdef JIT
	return 1;
#else
	return 0;
#endif
}

static cell AMX_NATIVE_CALL is_map_valid(AMX *amx, cell *params)  /* 1 param */
{
  int ilen;
  return (IS_MAP_VALID(get_amxstring(amx,params[1],0,ilen)) ? 1 : 0);
}

static cell AMX_NATIVE_CALL is_user_connected(AMX *amx, cell *params) /* 1 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  return (pPlayer->ingame ? 1 : 0);
}

static cell AMX_NATIVE_CALL is_user_connecting(AMX *amx, cell *params) /* 1 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  return ( !pPlayer->ingame && pPlayer->initialized
    && (GETPLAYERUSERID(pPlayer->pEdict)>0) ) ? 1 : 0;
}

static cell AMX_NATIVE_CALL is_user_bot(AMX *amx, cell *params) /* 1 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  return (GET_PLAYER_POINTER_I(index)->bot ? 1 : 0);
}


static cell AMX_NATIVE_CALL is_user_hltv(AMX *amx, cell *params) /* 1 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer *pPlayer = GET_PLAYER_POINTER_I(index);
  if (!pPlayer->initialized)
    return 0;
  if (pPlayer->pEdict->v.flags & FL_PROXY)
	  return 1;
  const char *authid = GETPLAYERAUTHID(pPlayer->pEdict);
  if (authid && stricmp(authid, "HLTV") == 0)
	  return 1;
  return 0;
}

static cell AMX_NATIVE_CALL is_user_alive(AMX *amx, cell *params) /* 1 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  return ((pPlayer->ingame && pPlayer->IsAlive()) ? 1 : 0);
}

static cell AMX_NATIVE_CALL get_user_frags(AMX *amx, cell *params) /* 1 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  return (cell)(pPlayer->ingame ? pPlayer->pEdict->v.frags : 0);
}

static cell AMX_NATIVE_CALL get_user_deaths(AMX *amx, cell *params) /* 1 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  return (cell)(pPlayer->ingame ? pPlayer->deaths : 0);
}


static cell AMX_NATIVE_CALL get_user_armor(AMX *amx, cell *params) /* 1 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  return (cell)(pPlayer->ingame ? pPlayer->pEdict->v.armorvalue : 0);
}

static cell AMX_NATIVE_CALL get_user_health(AMX *amx, cell *params) /*  param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  return (cell)(pPlayer->ingame ? pPlayer->pEdict->v.health : 0);
}

static cell AMX_NATIVE_CALL get_user_userid(AMX *amx, cell *params) /* 1 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  return pPlayer->initialized ? GETPLAYERUSERID(pPlayer->pEdict) : -1;
}


static cell AMX_NATIVE_CALL get_user_authid(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  const char* authid = 0;
  if (index>0&&index<=gpGlobals->maxClients)
  authid = GETPLAYERAUTHID(g_players[index].pEdict);
  return set_amxstring(amx,params[2], authid ? authid : "" ,params[3]);
}

static cell AMX_NATIVE_CALL is_user_authorized(AMX *amx, cell *params)
{
  int index = params[1];
  if (index < 1 || index > gpGlobals->maxClients)
    return 0;
  return GET_PLAYER_POINTER_I(index)->authorized;
}

static cell AMX_NATIVE_CALL get_weaponname(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  if (index < 1 || index >= MAX_WEAPONS ){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  return set_amxstring(amx,params[2],g_weaponsData[index].fullName.c_str(),params[3]);
}

static cell AMX_NATIVE_CALL get_user_weapons(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  if (index < 1 || index > gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (pPlayer->ingame){
    cell *cpNum = get_amxaddr(amx,params[3]);
    cell *cpIds = get_amxaddr(amx,params[2]);
	*cpIds = 0;
    int weapons = pPlayer->pEdict->v.weapons & ~(1<<31); // don't count last element
    for(int i = 1; i < MAX_WEAPONS; ++i){
      if (weapons & (1<<i)) {
        *(cpIds+(*cpNum)) = i;
        (*cpNum)++;
      }
    }
    return weapons;
  }
  return 0;
}

static cell AMX_NATIVE_CALL get_user_origin(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  if (index < 1 || index > gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (pPlayer->ingame){
    int mode = params[3];
    cell *cpOrigin = get_amxaddr(amx,params[2]);
    if (mode == 4) {
      cpOrigin[0] = (long int)pPlayer->lastHit.x;
      cpOrigin[1] = (long int)pPlayer->lastHit.y;
      cpOrigin[2] = (long int)pPlayer->lastHit.z;
      return 1;
    }
    edict_t* edict = pPlayer->pEdict;
    Vector pos = edict->v.origin;
    if (mode && mode!=2)
      pos = pos + edict->v.view_ofs;
    if (mode > 1) {
      Vector vec;
      Vector v_angle = edict->v.v_angle;
      float v_vec[3];
      v_vec[0] = v_angle.x;
      v_vec[1] = v_angle.y;
      v_vec[2] = v_angle.z;
      ANGLEVECTORS( v_vec, vec, NULL, NULL);
      TraceResult trEnd;
      Vector v_dest = pos+vec  * 9999;
      float f_pos[3];
      f_pos[0] = pos.x;
      f_pos[1] = pos.y;
      f_pos[2] = pos.z;
      float f_dest[3];
      f_dest[0] = v_dest.x;
      f_dest[1] = v_dest.y;
      f_dest[2] = v_dest.z;
      TRACE_LINE( f_pos , f_dest,  0 , edict, &trEnd );
      pos = (trEnd.flFraction < 1.0) ? trEnd.vecEndPos : Vector(0,0,0);
    }
    cpOrigin[0] = (long int)pos.x;
    cpOrigin[1] = (long int)pos.y;
    cpOrigin[2] = (long int)pos.z;
    return 1;
  }
  return 0;
}

static cell AMX_NATIVE_CALL get_user_ip(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  char *ptr;
  char szIp[32];
  strcpy(szIp,(index<1||index>gpGlobals->maxClients)?
    CVAR_GET_STRING("net_address"):g_players[index].ip.c_str());
  if (params[4] && (ptr = strstr(szIp,":"))!=0)
    *ptr = '\0';
  return set_amxstring(amx,params[2],szIp,params[3]);
}

static cell AMX_NATIVE_CALL get_user_attacker(AMX *amx, cell *params) /* 2 param */
{
  int index = params[1];
  if (index < 1 || index > gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  edict_t *enemy = NULL;
  if (pPlayer->ingame){
    enemy = pPlayer->pEdict->v.dmg_inflictor;
    if (!FNullEnt(enemy)) {
      int weapon = 0;
      if (enemy->v.flags & (FL_CLIENT | FL_FAKECLIENT) ){
        pPlayer = GET_PLAYER_POINTER(enemy);
        weapon = pPlayer->current;
      }
      else if( g_grenades.find( enemy, &pPlayer, weapon  ) )
        enemy = pPlayer->pEdict;
      else
        enemy = NULL;

      if (enemy){
        switch(*params/sizeof(cell)){
        case 3: *get_amxaddr(amx,params[3]) = pPlayer->aiming;
        case 2: *get_amxaddr(amx,params[2]) = weapon;
        }
      }
    }
  }
  return (enemy ? pPlayer->index : 0);
}

static cell AMX_NATIVE_CALL user_has_weapon(AMX *amx,cell *params)
{
  int index = params[1];
  if (index < 1 || index > gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  edict_t *pEntity = pPlayer->pEdict;
  if (params[3] == -1)
  {
    if ((pEntity->v.weapons & (1<<params[2])) > 0)
    {
      return 1;
    }
  }
  else
  {
    if ((pEntity->v.weapons & (1<<params[2])) > 0)
    {
      if (params[3] == 0)
      {
        pEntity->v.weapons &= ~(1<<params[2]);
        return 1;
      }
      return 0;
    }
    else
    {
      if (params[3] == 1)
      {
        pEntity->v.weapons |= (1<<params[2]);
        return 1;
      }
    }
    return 0;
  }
  return 0;
}

static cell AMX_NATIVE_CALL get_user_weapon(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  if (index < 1 || index > gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (pPlayer->ingame){
  int wpn = pPlayer->current;
    cell *cpTemp = get_amxaddr(amx,params[2]);
    *cpTemp = pPlayer->weapons[wpn].clip;
    cpTemp = get_amxaddr(amx,params[3]);
    *cpTemp = pPlayer->weapons[wpn].ammo;
    return wpn;
  }
  return 0;
}

static cell AMX_NATIVE_CALL get_user_ammo(AMX *amx, cell *params) /* 4 param */
{
  int index = params[1];
  if (index < 1 || index > gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (pPlayer->ingame){
    int wpn = params[2];
    if (wpn < 1 || wpn >= MAX_WEAPONS ){
      amx_RaiseError(amx,AMX_ERR_NATIVE);
      return 0;
    }
    cell *cpTemp = get_amxaddr(amx,params[3]);
    *cpTemp = pPlayer->weapons[wpn].clip;
    cpTemp = get_amxaddr(amx,params[4]);
    *cpTemp = pPlayer->weapons[wpn].ammo;
    return 1;
  }
  return 0;
}

static cell AMX_NATIVE_CALL get_user_team(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return -1;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (pPlayer->ingame){
    // SidLuke , DoD fix
    if ( g_bmod_dod ){
		int iTeam = pPlayer->pEdict->v.team;
        if ( params[3] ){
		  char *szTeam = "";
		  switch(iTeam){
		  case 1:
			  szTeam = "Allies";
			  break;
		  case 2:
			  szTeam = "Axis";
			  break;
		  }
		  set_amxstring(amx,params[2],szTeam,params[3]);
		}
		return iTeam;
	}
	//
    if ( params[3] )
	  set_amxstring(amx,params[2],pPlayer->team.c_str(),params[3]);

    return pPlayer->teamId;
  }
  return -1;
}

static cell AMX_NATIVE_CALL show_menu(AMX *amx, cell *params) /* 3 param */
{
  int ilen=0, ilen2=0;
  char *sMenu = get_amxstring(amx, params[3], 0, ilen);
  char *lMenu = get_amxstring(amx, params[5], 1, ilen2);
  int menuid = 0;
  if (ilen2 && lMenu)
  {
    menuid = g_menucmds.findMenuId(lMenu, amx);
  } else {
    menuid = g_menucmds.findMenuId(sMenu, amx);
  }
  int keys = params[2];
  int time = params[4];
  if (params[1] == 0) {
    for(int i = 1; i <= gpGlobals->maxClients; ++i){
      CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
      if (pPlayer->ingame){
        pPlayer->keys = keys;
        pPlayer->menu = menuid;
		pPlayer->newmenu = -1;
		pPlayer->page = 0;
        UTIL_ShowMenu(pPlayer->pEdict, keys, time, sMenu, ilen );
      }
    }
  }
  else {
    int index = params[1];
    if (index < 1 || index > gpGlobals->maxClients){
      amx_RaiseError(amx,AMX_ERR_NATIVE);
      return 0;
    }
    CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
    if (pPlayer->ingame){
      pPlayer->keys = keys;
      pPlayer->menu = menuid;
	  pPlayer->newmenu = -1;
	  pPlayer->page = 0;
      UTIL_ShowMenu(pPlayer->pEdict, keys, time, sMenu, ilen );
    }
  }
  return 1;
}



static cell AMX_NATIVE_CALL register_plugin(AMX *amx, cell *params) /* 3 param */
{
  CPluginMngr::CPlugin* a = g_plugins.findPluginFast( amx );
  int i;
  a->setTitle(  get_amxstring(amx,params[1],0,i) );
  a->setVersion( get_amxstring(amx,params[2],0,i) );
  a->setAuthor(  get_amxstring(amx,params[3],0,i)  );
  return 1;
}

static cell AMX_NATIVE_CALL register_menucmd(AMX *amx, cell *params) /* 3 param */
{
  CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx );
  int ilen, idx;
  char* sptemp = get_amxstring(amx,params[3],0,ilen);

  idx = registerSPForwardByName(amx, sptemp, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
  if (idx == -1)
  {
	  LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", sptemp);
	  return 0;
  }

  g_menucmds.registerMenuCmd( plugin , params[1] ,  params[2] , idx );

  return 1;
}

static cell AMX_NATIVE_CALL get_plugin(AMX *amx, cell *params) /* 11 param */
{
  CPluginMngr::CPlugin* a;

  if ( params[1]<0 )
  a = g_plugins.findPluginFast( amx );
  else
  a = g_plugins.findPlugin( (int)params[1] );

  if (a){
    set_amxstring(amx,params[2],a->getName(),params[3]);
    set_amxstring(amx,params[4],a->getTitle(),params[5]);
    set_amxstring(amx,params[6],a->getVersion(),params[7]);
    set_amxstring(amx,params[8],a->getAuthor(),params[9]);
    set_amxstring(amx,params[10],a->getStatus(),params[11]);
    return a->getId();
  }
  return -1;
}

static cell AMX_NATIVE_CALL amx_md5(AMX *amx, cell *params)
{
	int len = 0;
	char *str = get_amxstring(amx, params[1], 0, len);
	char buffer[33];

	MD5 md5;
	md5.update((unsigned char *)str, len);
	md5.finalize();
	md5.hex_digest(buffer);

	return set_amxstring(amx, params[2], buffer, 32);
}

static cell AMX_NATIVE_CALL amx_md5_file(AMX *amx, cell *params)
{
	int len = 0;
	char *str = get_amxstring(amx, params[1], 0, len);
	char buffer[33];

	FILE *fp = fopen(str, "rb");
	if (!fp)
	{
		amx_RaiseError(amx, AMX_ERR_NATIVE);
		return 0;
	}

	MD5 md5;
	md5.update(fp);			//closes for you
	md5.finalize();
	md5.hex_digest(buffer);

	return set_amxstring(amx, params[2], buffer, 32);
}

static cell AMX_NATIVE_CALL get_pluginsnum(AMX *amx, cell *params)
{
  return g_plugins.getPluginsNum();
}

static cell AMX_NATIVE_CALL register_concmd(AMX *amx, cell *params) /* 4 param */
{
  CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx );
  int i, idx = 0;
  char* temp = get_amxstring(amx,params[2],0, i );
  idx = registerSPForwardByName(amx, temp, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
  if (idx == -1)
  {
    LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp);
    return 0;
  }
  temp = get_amxstring(amx,params[1],0, i );
  char* info = get_amxstring(amx,params[4],1, i );
  CmdMngr::Command* cmd;
  int access = params[3];
  bool listable = true;
  if ( access < 0 ) { // is access is -1 then hide from listing
  access = 0;
  listable = false;
  }
  if ( (cmd = g_commands.registerCommand( plugin , idx ,  temp ,  info , access ,listable )) == NULL)
    return 0;
  cmd->setCmdType(  CMD_ConsoleCommand );

  REG_SVR_COMMAND( (char*)cmd->getCommand() , plugin_srvcmd );
  return 1;
}

static cell AMX_NATIVE_CALL register_clcmd(AMX *amx, cell *params) /* 4 param */
{
  CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx );
  int i, idx = 0;
  char* temp = get_amxstring(amx,params[2],0, i );
  idx = registerSPForwardByName(amx, temp, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
  if(idx==-1)
  {
    LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp);
    return 0;
  }
  temp = get_amxstring(amx,params[1],0, i );
  char* info = get_amxstring(amx,params[4],1, i );
  CmdMngr::Command* cmd;
  int access = params[3];
  bool listable = true;
  if ( access < 0 ) { // is access is -1 then hide from listing
  access = 0;
  listable = false;
  }
  if ( (cmd = g_commands.registerCommand(plugin , idx , temp ,  info , access , listable )) == NULL)
    return 0;
  cmd->setCmdType( CMD_ClientCommand );
  return 1;
}

static cell AMX_NATIVE_CALL register_srvcmd(AMX *amx, cell *params) /* 2 param */
{
  CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx );
  int i, idx = 0;
  char* temp = get_amxstring(amx,params[2],0, i );
  idx = registerSPForwardByName(amx, temp, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
  if (idx==-1)
  {
    LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp);
    return 0;
  }
  temp = get_amxstring(amx,params[1],0, i );
  char* info = get_amxstring(amx,params[4],1, i );
  CmdMngr::Command* cmd;
  int access = params[3];
  bool listable = true;
  if ( access < 0 ) { // is access is -1 then hide from listing
  access = 0;
  listable = false;
  }
  if ( (cmd = g_commands.registerCommand(plugin ,idx , temp , info ,access,listable )) == NULL)
    return 0;
  cmd->setCmdType( CMD_ServerCommand );
  REG_SVR_COMMAND( (char*)cmd->getCommand()  , plugin_srvcmd );
  return 0;
}

static cell AMX_NATIVE_CALL get_concmd(AMX *amx, cell *params) /* 7 param */
{
  int who = params[8];

  if ( who > 0 ) // id of player - client command
    who = CMD_ClientCommand;
  else if ( who == 0 ) // server
    who = CMD_ServerCommand;
  else // -1 parameter - all commands
    who = CMD_ConsoleCommand;

  CmdMngr::Command* cmd = g_commands.getCmd(params[1], who, params[7]);

  if ( cmd == 0 ) return 0;
    set_amxstring(amx,params[2], cmd->getCmdLine() ,params[3]);
    set_amxstring(amx,params[5], cmd->getCmdInfo() ,params[6]);
    cell *cpFlags = get_amxaddr(amx,params[4]);
    *cpFlags = cmd->getFlags();
    return 1;
}

static cell AMX_NATIVE_CALL get_clcmd(AMX *amx, cell *params) /* 7 param */
{
  CmdMngr::Command* cmd = g_commands.getCmd(params[1] ,CMD_ClientCommand ,  params[7]);
  if ( cmd == 0 ) return 0;
    set_amxstring(amx,params[2], cmd->getCmdLine() ,params[3]);
    set_amxstring(amx,params[5], cmd->getCmdInfo() ,params[6]);
    cell *cpFlags = get_amxaddr(amx,params[4]);
    *cpFlags = cmd->getFlags();

    return 1;
}

static cell AMX_NATIVE_CALL get_srvcmd(AMX *amx, cell *params)
{
  CmdMngr::Command* cmd = g_commands.getCmd(params[1] ,CMD_ServerCommand  , params[7] );
  if ( cmd == 0 ) return 0;
    set_amxstring(amx,params[2], cmd->getCmdLine() ,params[3]);
    set_amxstring(amx,params[5], cmd->getCmdInfo() ,params[6]);
    cell *cpFlags = get_amxaddr(amx,params[4]);
    *cpFlags = cmd->getFlags();
    return 1;
}

static cell AMX_NATIVE_CALL get_srvcmdsnum(AMX *amx, cell *params)
{
  return g_commands.getCmdNum(  CMD_ServerCommand  ,  params[1] );
}

static cell AMX_NATIVE_CALL get_clcmdsnum(AMX *amx, cell *params) /* 1 param */
{
  return g_commands.getCmdNum(  CMD_ClientCommand  ,  params[1] );
}

static cell AMX_NATIVE_CALL get_concmdsnum(AMX *amx, cell *params) /* 1 param */
{
  int who = params[2];
  if ( who > 0 )
  return g_commands.getCmdNum(  CMD_ClientCommand  ,  params[1] );
  if ( who == 0 )
  return g_commands.getCmdNum(  CMD_ServerCommand  ,  params[1] );
  return g_commands.getCmdNum(  CMD_ConsoleCommand  ,  params[1] );
}


static cell AMX_NATIVE_CALL register_event(AMX *amx, cell *params) /* 2 param */
{
  CPluginMngr::CPlugin* plugin = g_plugins.findPluginFast( amx );

  int len, pos, iFunction;

  char* sTemp = get_amxstring(amx,params[1],0,len);

  if ( (pos = g_events.getEventId(  sTemp  )) == 0 ) {
    AMXXLOG_Log("[AMXX] Invalid event (name \"%s\") (plugin \"%s\")", sTemp , plugin->getName() );
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }

  sTemp = get_amxstring(amx,params[2],0,len);
  iFunction = registerSPForwardByName(amx, sTemp, FP_CELL, FP_DONE);
  if (iFunction==-1)
  {
    LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", sTemp);
    return 0;
  }

  int numparam = *params/sizeof(cell);

  int flags = 0;

  if ( numparam > 2)
    flags = UTIL_ReadFlags( get_amxstring(amx,params[3],0,len) );

  EventsMngr::ClEvent* a =
    g_events.registerEvent( plugin , iFunction , flags , pos   );

  if ( a == 0 ) return 0;

  for(int i = 4; i <= numparam; ++i)
  a->registerFilter( get_amxstring(amx,params[i],0,len) );

  return 1;
}

static cell AMX_NATIVE_CALL user_kill(AMX *amx, cell *params) /* 2 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (pPlayer->ingame && pPlayer->IsAlive()){
  float bef = pPlayer->pEdict->v.frags;
    MDLL_ClientKill(pPlayer->pEdict);
    if (params[2]) pPlayer->pEdict->v.frags = bef;
    return 1;
  }

  return 0;
}

static cell AMX_NATIVE_CALL user_slap(AMX *amx, cell *params) /* 2 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  int power = abs((int)params[2]);
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (pPlayer->ingame && pPlayer->IsAlive()){
    if (pPlayer->pEdict->v.health <= power) {
      float bef = pPlayer->pEdict->v.frags;
      MDLL_ClientKill(pPlayer->pEdict);
      pPlayer->pEdict->v.frags = bef;
    }
    else {
      edict_t *pEdict = pPlayer->pEdict;
      int numparam = *params/sizeof(cell);
      if (numparam<3 || params[3]) {
        pEdict->v.velocity.x += RANDOM_LONG(-600,600);
        pEdict->v.velocity.y += RANDOM_LONG(-180,180);
        pEdict->v.velocity.z += RANDOM_LONG(100,200);
      }
      else {
        Vector v_forward, v_right;
	Vector vang = pEdict->v.angles;
	float fang[3];
	fang[0] = vang.x;
	fang[1] = vang.y;
	fang[2] = vang.z;
        ANGLEVECTORS( fang, v_forward, v_right, NULL );
        pEdict->v.velocity = pEdict->v.velocity + v_forward * 220 + Vector(0,0,200);
      }
      pEdict->v.punchangle.x = RANDOM_LONG(-10,10);
      pEdict->v.punchangle.y = RANDOM_LONG(-10,10);
      pEdict->v.health -= power;
      int armor = (int)pEdict->v.armorvalue;
      armor -= power;
      if (armor < 0) armor = 0;
      pEdict->v.armorvalue = armor;
      pEdict->v.dmg_inflictor = pEdict;
      if (g_bmod_cstrike){
        static const char *cs_sound[4] = {
          "player/bhit_flesh-3.wav",
          "player/bhit_flesh-2.wav",
          "player/pl_die1.wav",
          "player/pl_pain6.wav"  };
        EMIT_SOUND_DYN2(pEdict, CHAN_VOICE, cs_sound[RANDOM_LONG(0,3)], 1.0, ATTN_NORM, 0, PITCH_NORM);
      }
      else{
        static const char *bit_sound[3] = {
          "weapons/cbar_hitbod1.wav",
          "weapons/cbar_hitbod2.wav",
          "weapons/cbar_hitbod3.wav" };
        EMIT_SOUND_DYN2(pEdict, CHAN_VOICE, bit_sound[RANDOM_LONG(0,2)], 1.0, ATTN_NORM, 0, PITCH_NORM);
      }
    }
    return 1;
  }

  return 0;
}

static cell AMX_NATIVE_CALL server_cmd(AMX *amx, cell *params) /* 1 param */
{
  int len;
  g_langMngr.SetDefLang(LANG_SERVER);
  char* cmd = format_amxstring(amx,params,1,len);
  cmd[len++]='\n';
  cmd[len]=0;
  SERVER_COMMAND( cmd );
  return len;
}

static cell AMX_NATIVE_CALL client_cmd(AMX *amx, cell *params) /* 2 param */
{
  int len;
  char* cmd = format_amxstring(amx,params,2,len);
  cmd[len++]='\n';
  cmd[len]=0;

  if (params[1] == 0) {
    for(int i = 1; i <= gpGlobals->maxClients; ++i){
      CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
      if (!pPlayer->bot &&  pPlayer->initialized /*&& pPlayer->ingame*/ )
        CLIENT_COMMAND(pPlayer->pEdict, UTIL_VarArgs("%s", cmd) );
    }
  }
  else {
    int index = params[1];
    if (index < 1 || index > gpGlobals->maxClients){
      amx_RaiseError(amx,AMX_ERR_NATIVE);
      return 0;
    }
    CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
    if ( !pPlayer->bot && pPlayer->initialized /*&& pPlayer->ingame*/ )
    CLIENT_COMMAND(pPlayer->pEdict, UTIL_VarArgs("%s", cmd) );
  }
  return len;
}

static cell AMX_NATIVE_CALL get_cvar_string(AMX *amx, cell *params) /* 3 param */
{
  int ilen;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  return set_amxstring(amx,params[2],CVAR_GET_STRING(sptemp),params[3]);
}

static cell AMX_NATIVE_CALL get_cvar_float(AMX *amx, cell *params) /* 1 param */
{
  int ilen;
  REAL pFloat = CVAR_GET_FLOAT(get_amxstring(amx,params[1],0,ilen));
  return amx_ftoc(pFloat);
}

static cell AMX_NATIVE_CALL set_cvar_float(AMX *amx, cell *params) /* 2 param */
{
  int ilen;
  CVAR_SET_FLOAT(get_amxstring(amx,params[1],0,ilen), amx_ctof(params[2]));
  return 1;
}

static cell AMX_NATIVE_CALL get_cvar_num(AMX *amx, cell *params) /* 1 param */
{
  int ilen;
  return (int)CVAR_GET_FLOAT(get_amxstring(amx,params[1],0,ilen));
}

static cell AMX_NATIVE_CALL set_cvar_num(AMX *amx, cell *params) /* 2 param */
{
  int ilen;
  CVAR_SET_FLOAT(get_amxstring(amx,params[1],0,ilen),(float)params[2]);
  return 1;
}

static cell AMX_NATIVE_CALL set_cvar_string(AMX *amx, cell *params) /* 2 param */
{
  int ilen;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  char* szValue = get_amxstring(amx,params[2],1,ilen);
  CVAR_SET_STRING(sptemp,szValue);
  return 1;
}

static cell AMX_NATIVE_CALL message_begin(AMX *amx, cell *params) /* 4 param */
{
	int numparam = *params/sizeof(cell);
	float vecOrigin[3];
	cell *cpOrigin;

	if (params[2] < 1 || ((params[2] > 63)		// maximal number of engine messages
		&& !GET_USER_MSG_NAME(PLID, params[2], NULL)))
	{
		AMXXLOG_Log("[AMXX] Plugin called message_begin with an invalid message id (%d).", params[2]);
		amx_RaiseError(amx, AMX_ERR_NATIVE);
		return 0;
	}
	switch (params[1]){
  case MSG_BROADCAST:
  case MSG_ALL:
  case MSG_SPEC:
	  MESSAGE_BEGIN( params[1], params[2],NULL );
	  break;
  case MSG_PVS: case MSG_PAS:
  case MSG_PVS_R: case MSG_PAS_R:
	  if (numparam < 3) {
		  amx_RaiseError(amx,AMX_ERR_NATIVE);
		  return 0;
	  }
	  cpOrigin = get_amxaddr(amx,params[3]);
	  vecOrigin[0] = *cpOrigin;
	  vecOrigin[1] = *(cpOrigin+1);
	  vecOrigin[2] = *(cpOrigin+2);
	  MESSAGE_BEGIN( params[1], params[2] , vecOrigin );
	  break;
  case MSG_ONE_UNRELIABLE:
  case MSG_ONE:
	  if (numparam < 4) {
		  amx_RaiseError(amx,AMX_ERR_NATIVE);
		  return 0;
	  }
	  MESSAGE_BEGIN( params[1], params[2], NULL, INDEXENT(params[4]) );
	  break;
	}

	return 1;
}

static cell AMX_NATIVE_CALL message_end(AMX *amx, cell *params)
{
	MESSAGE_END();
	return 1;
}

static cell AMX_NATIVE_CALL write_byte(AMX *amx, cell *params) /* 1 param */
{
	WRITE_BYTE( params[1] );
	return 1;
}

static cell AMX_NATIVE_CALL write_char(AMX *amx, cell *params) /* 1 param */
{
	WRITE_CHAR( params[1] );
	return 1;
}

static cell AMX_NATIVE_CALL write_short(AMX *amx, cell *params)  /* 1 param */
{
	WRITE_SHORT( params[1] );
	return 1;
}

static cell AMX_NATIVE_CALL write_long(AMX *amx, cell *params)  /* 1 param */
{
	WRITE_LONG( params[1] );
	return 1;
}

static cell AMX_NATIVE_CALL write_entity(AMX *amx, cell *params) /* 1 param */
{
	WRITE_ENTITY( params[1] );
	return 1;
}

static cell AMX_NATIVE_CALL write_angle(AMX *amx, cell *params) /* 1 param */
{
	WRITE_ANGLE( params[1] );
	return 1;
}

static cell AMX_NATIVE_CALL write_coord(AMX *amx, cell *params) /* 1 param */
{
	WRITE_COORD( params[1] );
	return 1;
}

static cell AMX_NATIVE_CALL write_string(AMX *amx, cell *params) /* 1 param */
{
	int a;
	WRITE_STRING( get_amxstring(amx,params[1],3,a) );
	return 1;
}

static cell AMX_NATIVE_CALL log_message(AMX *amx, cell *params) /* 1 param */
{
  int len;
  g_langMngr.SetDefLang(LANG_SERVER);
  char* message =  format_amxstring(amx,params,1,len);
  message[len++]='\n';
  message[len]=0;
  ALERT( at_logged, "%s", message );
  return len;
}

static cell AMX_NATIVE_CALL log_to_file(AMX *amx, cell *params) /* 1 param */
{
  int ilen;
  char* szFile = get_amxstring(amx,params[1],0,ilen);
  FILE*fp;
  char file[256];
  if (strchr(szFile, '/') || strchr(szFile, '\\'))
  {
	  build_pathname_r(file, sizeof(file)-1, "%s", szFile);
  } else {
	  build_pathname_r(file, sizeof(file)-1, "%s/%s", g_log_dir.c_str(), szFile);
  }
  bool first_time = true;
  if ((fp=fopen(file,"r"))!=NULL){
    first_time = false;
    fclose(fp);
  }
  if ((fp=fopen(file,"a")) == NULL){
    //amx_RaiseError(amx,AMX_ERR_NATIVE);
  //would cause too much troubles in old plugins
    return 0;
  }
  char date[32];
  time_t td; time(&td);
  strftime(date,31,"%m/%d/%Y - %H:%M:%S",localtime(&td));
  int len;
  g_langMngr.SetDefLang(LANG_SERVER);
  char* message =  format_amxstring(amx,params,2,len);
  message[len++]='\n';
  message[len]=0;
  if ( first_time ){
    fprintf(fp,"L %s: Log file started (file \"%s\") (game \"%s\") (amx \"%s\")\n",
      date,file,g_mod_name.c_str(),Plugin_info.version);
    print_srvconsole("L %s: Log file started (file \"%s\") (game \"%s\") (amx \"%s\")\n",
      date,file,g_mod_name.c_str(),Plugin_info.version);
  }
  fprintf(fp,"L %s: %s",date,message);
  print_srvconsole("L %s: %s",date,message);
  fclose(fp);
  return 1;
}

static cell AMX_NATIVE_CALL num_to_word(AMX *amx, cell *params) /* 3 param */
{
  char sptemp[512];
  UTIL_IntToString(params[1], sptemp);
  return set_amxstring(amx,params[2],sptemp,params[3]);
}


static cell AMX_NATIVE_CALL get_timeleft(AMX *amx, cell *params)
{
  float flCvarTimeLimit = mp_timelimit->value;

  if (flCvarTimeLimit) {
    int iReturn = (int)((g_game_timeleft + flCvarTimeLimit * 60.0) - gpGlobals->time);
    return (iReturn < 0) ? 0 : iReturn;
  }

  return 0;
}

static cell AMX_NATIVE_CALL get_time(AMX *amx, cell *params) /* 3 param */
{
  int ilen;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  time_t td = time(NULL);
  tm* lt = localtime(&td);
  if ( lt == 0 ) {
  amx_RaiseError(amx,AMX_ERR_NATIVE);
  return 0;
  }
  char szDate[512];
  strftime(szDate,511,sptemp, lt );
  return set_amxstring(amx,params[2],szDate,params[3]);
}

static cell AMX_NATIVE_CALL format_time(AMX *amx, cell *params) /* 3 param */
{
  int ilen;
  char* sptemp = get_amxstring(amx,params[3],0,ilen);
  time_t tim = params[4];
  time_t td = ( tim  != -1 ) ? tim : time(NULL);
  tm* lt = localtime(&td);
  if ( lt == 0 )  {
  amx_RaiseError(amx,AMX_ERR_NATIVE);
  return 0;
  }
  char szDate[512];
  strftime(szDate,511,sptemp, lt );
  return set_amxstring(amx,params[1],szDate,params[2]);

}

static cell AMX_NATIVE_CALL parse_time(AMX *amx, cell *params) /* 3 param */
{
  int ilen;
  char* sTime = get_amxstring(amx,params[1],1,ilen);
  char* sFormat = get_amxstring(amx,params[2],0,ilen);
  tm* mytime;
  time_t td;
  if ( params[3] == -1 )  {
  td = time(NULL);
  mytime = localtime(&td);
  if ( mytime == 0 ){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  strptime (sTime,sFormat,mytime , 0 );
  }
  else  {
  td = params[3];
  mytime = localtime(&td);
  if ( mytime == 0 ){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  strptime (sTime,sFormat,mytime , 1 );
  }
  return mktime(mytime);
}

static cell AMX_NATIVE_CALL get_systime(AMX *amx, cell *params) /* 3 param */
{
  time_t td = time(NULL);
  td  += params[1];
  return td;
}

static cell AMX_NATIVE_CALL read_datanum(AMX *amx, cell *params) /* 0 param */
{
  return g_events.getArgNum();
}

static cell AMX_NATIVE_CALL read_data(AMX *amx, cell *params) /* 3 param */
{
	if (params[0] == 0)
	{
		return g_events.getCurrentMsgType();
	}
	switch( *params/sizeof(cell) ) {
		case 1:
			return g_events.getArgInteger( params[1] );
		case 3:
			return set_amxstring(amx,params[2], g_events.getArgString( params[1] ),*get_amxaddr(amx,params[3]));
		default:
			cell *fCell = get_amxaddr(amx, params[2]);
			float fparam = g_events.getArgFloat(params[1]);
			fCell[0] = amx_ftoc(fparam);
			return (int)fparam;
	}
}

static cell AMX_NATIVE_CALL get_playersnum(AMX *amx, cell *params)
{
  if (!params[1])
    return g_players_num;

  int a = 0;
  for(int i = 1; i <= gpGlobals->maxClients; ++i){
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
    if ( pPlayer->initialized && (GETPLAYERUSERID(pPlayer->pEdict) > 0) )
      ++a;
  }

  return a;
}

static cell AMX_NATIVE_CALL get_players(AMX *amx, cell *params) /* 4 param */
{
  int iNum = 0;
  int ilen;
  char* sptemp = get_amxstring(amx,params[3],0,ilen);
  int flags = UTIL_ReadFlags(sptemp);

  cell *aPlayers = get_amxaddr(amx,params[1]);
  cell *iMax = get_amxaddr(amx,params[2]);

  int team = 0;

  if (flags & 48) {
    sptemp = get_amxstring(amx,params[4],0,ilen);

    if ( flags & 16 ) {
      if (flags & 64)
        team = g_teamsIds.findTeamId( sptemp );
      else
        team = g_teamsIds.findTeamIdCase( sptemp );
    }
  }

  for(int i = 1; i <= gpGlobals->maxClients; ++i){
    CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
    if (pPlayer->ingame){
      if (pPlayer->IsAlive() ? (flags & 2) : (flags & 1))
        continue;
      if (pPlayer->bot ? (flags & 4) : (flags & 8))
        continue;
      if ((flags & 16) && (pPlayer->teamId != team) )
    continue;
      if (flags & 32){
          if (flags & 64){
            if (stristr(pPlayer->name.c_str(),sptemp)==NULL)
              continue;
          }
          else if (strstr(pPlayer->name.c_str(),sptemp)==NULL)
              continue;
      }
      aPlayers[iNum++] = i;
    }
  }

  *iMax = iNum;
  return 1;
}

static cell AMX_NATIVE_CALL find_player(AMX *amx, cell *params) /* 1 param */
{
  int ilen, userid = 0;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  int flags = UTIL_ReadFlags(sptemp);
  if (flags&31)
    sptemp = get_amxstring(amx,params[2],0,ilen);
  else if (flags&1024)
    userid = *get_amxaddr(amx,params[2]);
  // a b c d e f g h i j k l
  int result = 0;
  for(int i = 1; i <= gpGlobals->maxClients; ++i){
    CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
    if (pPlayer->ingame){
      if (pPlayer->IsAlive()?(flags&64):(flags&32))
        continue;
      if (pPlayer->bot?(flags&128):(flags&256))
        continue;
      if (flags&1){
        if (flags&2048) {
          if (stricmp(pPlayer->name.c_str(),sptemp))
            continue;
        }
        else if (strcmp(pPlayer->name.c_str(),sptemp))
          continue;
      }
      if (flags&2){
        if (flags&2048) {
          if (stristr(pPlayer->name.c_str(),sptemp)==NULL)
            continue;
        }
        else if (strstr(pPlayer->name.c_str(),sptemp)==NULL)
          continue;
      }
      if (flags&4){
        const char* authid = GETPLAYERAUTHID(pPlayer->pEdict);
        if (!authid || strcmp(authid,sptemp))
          continue;
      }
      if (flags&1024){
        if (userid != GETPLAYERUSERID(pPlayer->pEdict))
          continue;
      }
      if (flags&8){
        if (strncmp(pPlayer->ip.c_str(),sptemp,ilen))
          continue;
      }
      if (flags&16){
        if (flags&2048) {
          if (stricmp(pPlayer->team.c_str(),sptemp))
            continue;
        }
        else if (strcmp(pPlayer->team.c_str(),sptemp))
          continue;
      }
      result = i;
      if ((flags&512)==0)
        break;
    }
  }

  return result;
}

static cell AMX_NATIVE_CALL get_maxplayers(AMX *amx, cell *params)
{
  return gpGlobals->maxClients;
}

static cell AMX_NATIVE_CALL get_gametime(AMX *amx, cell *params)
{
  REAL pFloat = gpGlobals->time;
  return amx_ftoc(pFloat);
}

static cell AMX_NATIVE_CALL get_mapname(AMX *amx, cell *params) /* 2 param */
{
  return set_amxstring(amx,params[1],STRING(gpGlobals->mapname),params[2]);
}

static cell AMX_NATIVE_CALL get_modname(AMX *amx, cell *params) /* 2 param */
{
  return set_amxstring(amx,params[1],g_mod_name.c_str(),params[2]);
}


static cell AMX_NATIVE_CALL get_localinfo(AMX *amx, cell *params) /* 3 param */
{
  int ilen;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  return set_amxstring(amx,params[2],LOCALINFO(sptemp),params[3]);
}

static cell AMX_NATIVE_CALL set_localinfo(AMX *amx, cell *params) /* 2 param */
{
  int ilen;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  char* szValue = get_amxstring(amx,params[2],1,ilen);
  SET_LOCALINFO(sptemp,szValue);
  return 1;
}

static cell AMX_NATIVE_CALL get_user_info(AMX *amx, cell *params) /* 4 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (!pPlayer->pEdict)
  {
	  LogError(amx, AMX_ERR_NATIVE, "Player %d is not connected", index);
	  return 0;
  }
  int ilen;
  char* sptemp = get_amxstring(amx,params[2],0,ilen);
  return set_amxstring(amx,params[3],ENTITY_KEYVALUE(pPlayer->pEdict,sptemp ),params[4]);
  return 1;
}

static cell AMX_NATIVE_CALL set_user_info(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (!pPlayer->pEdict)
  {
	  LogError(amx, AMX_ERR_NATIVE, "Player %d is not connected", index);
	  return 0;
  }
  int ilen;
  char* sptemp = get_amxstring(amx,params[2],0,ilen);
  char* szValue = get_amxstring(amx,params[3],1,ilen);
  ENTITY_SET_KEYVALUE(pPlayer->pEdict,sptemp,szValue);
  return 1;
}

static cell AMX_NATIVE_CALL read_argc(AMX *amx, cell *params)
{
  return CMD_ARGC();
}

static cell AMX_NATIVE_CALL read_argv(AMX *amx, cell *params) /* 3 param */
{
  return set_amxstring(amx,params[2],  /*( params[1] < 0 ||
    params[1] >= CMD_ARGC() ) ? "" : */CMD_ARGV(params[1])   , params[3]);
}

static cell AMX_NATIVE_CALL read_args(AMX *amx, cell *params) /* 2 param */
{
  const char* sValue = CMD_ARGS();
  return set_amxstring(amx,params[1],sValue ? sValue : "",params[2]);
}

static cell AMX_NATIVE_CALL get_user_msgid(AMX *amx, cell *params) /* 1 param */
{
  int ilen;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  return GET_USER_MSG_ID(PLID, sptemp , NULL );
}

static cell AMX_NATIVE_CALL get_user_msgname(AMX *amx, cell *params) /* get_user_msgname(msg, str[], len) = 3 params */
{
	const char* STRING = GET_USER_MSG_NAME(PLID, params[1], NULL);
	if (STRING)
		return set_amxstring(amx, params[2], STRING, params[3]);

	// Comes here if GET_USER_MSG_NAME failed (ie, invalid msg id)
	return 0;
}

static cell AMX_NATIVE_CALL set_task(AMX *amx, cell *params) /* 2 param */
{

  CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx);

  int a, iFunc;

  char* stemp = get_amxstring(amx,params[2],1, a );

  if (params[5])
  {
     iFunc = registerSPForwardByName(amx, stemp, FP_ARRAY, FP_CELL, FP_DONE);
  } else {
     iFunc = registerSPForwardByName(amx, stemp, FP_CELL, FP_DONE);
  }
  if (iFunc == -1)
  {
    AMXXLOG_Log("[AMXX] Function is not present (function \"%s\") (plugin \"%s\")",stemp,plugin->getName() );
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }

  float base = amx_ctof(params[1]);

  if ( base < 0.1 )
    base = 0.1;

  char* temp = get_amxstring(amx,params[6],0,a);

  g_tasksMngr.registerTask( plugin , iFunc , UTIL_ReadFlags(temp), params[3], base ,  params[5] ,  get_amxaddr(amx,params[4]) , params[7] );

  return 1;
}

static cell AMX_NATIVE_CALL remove_task(AMX *amx, cell *params) /* 1 param */
{
  return g_tasksMngr.removeTasks( params[1] ,  params[2] ? 0 : amx   );
}

static cell AMX_NATIVE_CALL change_task(AMX *amx, cell *params)
{
  REAL flNewTime = amx_ctof(params[2]);
  return g_tasksMngr.changeTasks(params[1], params[3] ? 0 : amx, flNewTime);
}

static cell AMX_NATIVE_CALL task_exists(AMX *amx, cell *params) /* 1 param */
{
  return g_tasksMngr.taskExists(  params[1] ,  params[2] ? 0 : amx  );
}

static cell AMX_NATIVE_CALL cvar_exists(AMX *amx, cell *params) /* 1 param */
{
  int ilen;
  return (CVAR_GET_POINTER(get_amxstring(amx,params[1],0,ilen))?1:0);
}

static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params) /* 3 param */
{
  int i;
  char* temp = get_amxstring(amx,params[1],0,i);

  if (  !g_cvars.find(  temp ) )
  {
  CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx);
  CCVar* cvar = new CCVar( temp , plugin->getName() , params[3] ,
    amx_ctof(params[4])  );

  if ( cvar == 0 )
    return 0;

  g_cvars.put( cvar );

  if ( CVAR_GET_POINTER(temp) == 0 )
  {
	  static cvar_t cvar_reg_helper;
	  cvar_reg_helper = *(cvar->getCvar());
	  CVAR_REGISTER( &cvar_reg_helper );
  }

  CVAR_SET_STRING( temp ,get_amxstring(amx,params[2],1,i));
  return 1;
  }

  return 0;
}

static cell AMX_NATIVE_CALL get_user_ping(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (pPlayer->ingame){
    cell *cpPing = get_amxaddr(amx,params[2]);
    cell *cpLoss = get_amxaddr(amx,params[3]);
    int ping, loss;
    PLAYER_CNX_STATS(pPlayer->pEdict , &ping, &loss);
    *cpPing = ping;
    *cpLoss = loss;
    return 1;
  }
  return 0;
}

static cell AMX_NATIVE_CALL get_user_time(AMX *amx, cell *params) /* 1 param */
{
  int index = params[1];
  if (index<1||index>gpGlobals->maxClients)
    return 0;
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (pPlayer->ingame){
    int time = (int)(gpGlobals->time - (params[2] ? pPlayer->playtime : pPlayer->time));
    return time;
  }
  return 0;
}

static cell AMX_NATIVE_CALL server_exec(AMX *amx, cell *params)
{
  SERVER_EXECUTE( );
  return 1;
}

static cell AMX_NATIVE_CALL engclient_cmd(AMX *amx, cell *params) /* 4 param */
{
  int ilen;
  const char* szCmd = get_amxstring(amx,params[2],0,ilen);
  const char* sArg1 = get_amxstring(amx,params[3],1,ilen);
  if ( ilen == 0 ) sArg1 = 0;
  const char* sArg2 = get_amxstring(amx,params[4],2,ilen);
  if ( ilen == 0 ) sArg2 = 0;
  if (params[1] == 0) {
    for(int i = 1; i <= gpGlobals->maxClients; ++i){
      CPlayer* pPlayer = GET_PLAYER_POINTER_I(i);
      if (pPlayer->ingame /*&&  pPlayer->initialized */)
        UTIL_FakeClientCommand(pPlayer->pEdict, szCmd,sArg1,sArg2);
    }
  }
  else {
    int index = params[1];
    if (index < 1 || index > gpGlobals->maxClients){
      amx_RaiseError(amx,AMX_ERR_NATIVE);
      return 0;
    }
    CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if ( /*pPlayer->initialized && */pPlayer->ingame )
    UTIL_FakeClientCommand(pPlayer->pEdict, szCmd,sArg1,sArg2);
  }
  return 1;
}

static cell AMX_NATIVE_CALL pause(AMX *amx, cell *params) /* 3 param */
{
  int ilen;
  char* temp = get_amxstring(amx,params[1],0,ilen);
  int flags = UTIL_ReadFlags(temp);

  CPluginMngr::CPlugin *plugin = 0;

  if ( flags & 2  )
  { // pause function
    AMXXLOG_Log("[AMXX] This usage of the native pause() has been deprecated!");
    return 1;
  }
  else  if (flags&4){
    temp = get_amxstring(amx,params[2],0,ilen);
    plugin = g_plugins.findPlugin(temp);
  }
  else
    plugin = g_plugins.findPluginFast(amx);
  if ( plugin && plugin->isValid() ){
    if ( flags & 8 )
    plugin->setStatus( ps_stopped );
    else if ( flags & 16 )
    plugin->setStatus( ps_locked );
    else
    plugin->pausePlugin();
  return 1;
  }
  return 0;
}

static cell AMX_NATIVE_CALL unpause(AMX *amx, cell *params) /* 3 param */
{

  int ilen;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  int flags = UTIL_ReadFlags(sptemp);
  CPluginMngr::CPlugin *plugin = 0;
  if (flags&2)
  {
    AMXXLOG_Log("[AMXX] This usage of the native pause() has been deprecated!");
    return 1;
  } else if (flags&4) {
    sptemp = get_amxstring(amx,params[2],0,ilen);
    plugin = g_plugins.findPlugin(sptemp);
  }
  else
    plugin = g_plugins.findPluginFast( amx);
  if (plugin && plugin->isValid()) {
    plugin->unpausePlugin();
    return 1;
  }

  return 0;

}

static cell AMX_NATIVE_CALL read_flags(AMX *amx, cell *params) /* 1 param */
{
  int ilen;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  return UTIL_ReadFlags(sptemp);
}

static cell AMX_NATIVE_CALL get_flags(AMX *amx, cell *params) /* 1 param */
{
  char flags[32];
  UTIL_GetFlags( flags , params[1] );
  return set_amxstring(amx,params[2],flags,params[3]);
}

static cell AMX_NATIVE_CALL get_user_flags(AMX *amx, cell *params) /* 2 param */
{
  int index = params[1];
  if (index<0||index>gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  int id = params[2];
  if (id < 0) id = 0;
  if (id > 31) id = 31;
  return GET_PLAYER_POINTER_I(index)->flags[id];
}

static cell AMX_NATIVE_CALL set_user_flags(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  if (index < 0 || index > gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  int flag = params[2];
  int id = params[3];
  if (id < 0) id = 0;
  if (id > 31) id = 31;
  pPlayer->flags[id] |= flag;
  return 1;
}

static cell AMX_NATIVE_CALL remove_user_flags(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  if (index < 0 || index > gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  int flag = params[2];
  int id = params[3];
  if (id < 0) id = 0;
  if (id > 31) id = 31;
  pPlayer->flags[id] &= ~flag;
  return 1;
}

static cell AMX_NATIVE_CALL register_menuid(AMX *amx, cell *params) /* 1 param */
{
  int i;
  char* temp = get_amxstring(amx,params[1],0,i);
  AMX* a = (*params/sizeof(cell) < 2 || params[2] ) ? 0 : amx;
  return g_menucmds.registerMenuId( temp , a );
}

static cell AMX_NATIVE_CALL get_user_menu(AMX *amx, cell *params) /* 3 param */
{
  int index = params[1];
  if (index < 1 || index > gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  cell *cpMenu = get_amxaddr(amx,params[2]);
  cell *cpKeys = get_amxaddr(amx,params[3]);
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  if (pPlayer->ingame){
    *cpMenu = pPlayer->menu;
    *cpKeys = pPlayer->keys;
    return 1;
  }
  return 0;
}

static cell AMX_NATIVE_CALL precache_sound(AMX *amx, cell *params) /* 1 param */
{
  if ( g_dontprecache ) {
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  int ilen;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  PRECACHE_SOUND((char*)STRING(ALLOC_STRING(sptemp)));
  return 1;
}

static cell AMX_NATIVE_CALL precache_model(AMX *amx, cell *params) /* 1 param */
{
  if ( g_dontprecache ) {
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  int ilen;
  char* sptemp = get_amxstring(amx,params[1],0,ilen);
  return PRECACHE_MODEL((char*)STRING(ALLOC_STRING(sptemp)));
}

static cell AMX_NATIVE_CALL get_distance(AMX *amx, cell *params) /* 2 param */
{
  cell *cpVec1 = get_amxaddr(amx,params[1]);
  cell *cpVec2 = get_amxaddr(amx,params[2]);
  Vector vec1 = Vector(cpVec1[0],cpVec1[1],cpVec1[2]);
  Vector vec2 = Vector(cpVec2[0],cpVec2[1],cpVec2[2]);
  int iDist = (int)((vec1 - vec2).Length());
  return iDist;
}

static cell AMX_NATIVE_CALL get_distance_f(AMX *amx, cell *params)
{
  cell *cpVec1 = get_amxaddr(amx, params[1]);
  cell *cpVec2 = get_amxaddr(amx, params[2]);
  Vector vec1 = Vector((float)amx_ctof(cpVec1[0]),
					   (float)amx_ctof(cpVec1[1]),
					   (float)amx_ctof(cpVec1[2]));
  Vector vec2 = Vector((float)amx_ctof(cpVec2[0]),
					   (float)amx_ctof(cpVec2[1]),
					   (float)amx_ctof(cpVec2[2]));

  REAL fDist = (REAL) (vec1-vec2).Length();

  return amx_ftoc(fDist);
}

static cell AMX_NATIVE_CALL random_float(AMX *amx, cell *params) /* 2 param */
{
  float one = amx_ctof(params[1]);
  float two = amx_ctof(params[2]);
  REAL fRnd = RANDOM_FLOAT(one,two);
  return amx_ftoc(fRnd);
}

static cell AMX_NATIVE_CALL random_num(AMX *amx, cell *params) /* 2 param */
{
  return RANDOM_LONG(params[1],params[2]);
}

static cell AMX_NATIVE_CALL remove_quotes(AMX *amx, cell *params) /* 1 param */
{
  cell *text = get_amxaddr(amx,params[1]);
  if (*text=='\"') {
    register cell *temp = text;
    int len = 0;
    while(*temp++) ++len; // get length
    cell *src = text;
  if ( src[len-1]=='\r' )
    src[--len] = 0;
    if (src[--len]=='\"'){
      src[len] = 0;
      temp = src+1;
      while((*src++ = *temp++))
        ;
      return 1;
    }
  }
  return 0;
}

static cell AMX_NATIVE_CALL get_user_aiming(AMX *amx, cell *params) /* 4 param */
{
  int index = params[1];
  if (index < 1 || index > gpGlobals->maxClients){
    amx_RaiseError(amx,AMX_ERR_NATIVE);
    return 0;
  }
  CPlayer* pPlayer = GET_PLAYER_POINTER_I(index);
  cell *cpId = get_amxaddr(amx,params[2]);
  cell *cpBody = get_amxaddr(amx,params[3]);
  cell fCell;
  REAL *pFloat = (REAL *)((void *)&fCell);
  *pFloat = 0.0;
  if (pPlayer->ingame) {
    edict_t* edict = pPlayer->pEdict;
    Vector v_forward;
    Vector v_src = edict->v.origin + edict->v.view_ofs;
    ANGLEVECTORS( edict->v.v_angle , v_forward, NULL, NULL );
    TraceResult trEnd;
    Vector v_dest = v_src + v_forward * params[4];
    TRACE_LINE( v_src , v_dest,  0 , edict, &trEnd );
    *cpId = FNullEnt(trEnd.pHit) ? 0 : ENTINDEX(trEnd.pHit);
    *cpBody = trEnd.iHitgroup;
    if (trEnd.flFraction < 1.0) {
      *pFloat = (trEnd.vecEndPos - v_src).Length();
      return fCell;
    }
    else {
      return fCell;
    }
  }
  *cpId = 0;
  *cpBody = 0;
  return fCell;

}

static cell AMX_NATIVE_CALL remove_cvar_flags(AMX *amx, cell *params)
{
  int ilen;
  char* sCvar = get_amxstring(amx,params[1],0,ilen);
  if ( !strcmp(sCvar,"amx_version") || !strcmp(sCvar,"amxmodx_version") ||
    !strcmp(sCvar,"fun_version") ||  !strcmp(sCvar,"sv_cheats")  )
    return 0;
  cvar_t* pCvar = CVAR_GET_POINTER(sCvar);
  if (pCvar)  {
    pCvar->flags &= ~((int)(params[2]));
    return 1;
  }
  return 0;
}

static cell AMX_NATIVE_CALL get_cvar_flags(AMX *amx, cell *params)
{
  int ilen;
  char* sCvar = get_amxstring(amx,params[1],0,ilen);
  cvar_t* pCvar = CVAR_GET_POINTER(sCvar);
  return pCvar ? pCvar->flags : 0;
}

static cell AMX_NATIVE_CALL set_cvar_flags(AMX *amx, cell *params)
{
  int ilen;
  char* sCvar = get_amxstring(amx,params[1],0,ilen);
  if ( !strcmp(sCvar,"amx_version") || !strcmp(sCvar,"amxmodx_version") ||
    !strcmp(sCvar,"fun_version")  ||  !strcmp(sCvar,"sv_cheats") )
    return 0;
  cvar_t* pCvar = CVAR_GET_POINTER(sCvar);
  if (pCvar)  {
    pCvar->flags |= (int)(params[2]);
    return 1;
  }
  return 0;
}

static cell AMX_NATIVE_CALL force_unmodified(AMX *amx, cell *params)
{
  int a;
  cell *cpVec1 = get_amxaddr(amx,params[2]);
  cell *cpVec2 = get_amxaddr(amx,params[3]);
  Vector vec1 = Vector(cpVec1[0],cpVec1[1],cpVec1[2]);
  Vector vec2 = Vector(cpVec2[0],cpVec2[1],cpVec2[2]);
  char* filename = get_amxstring(amx,params[4],0,a);

  ForceObject* aaa = new ForceObject(filename ,  (FORCE_TYPE)((int)(params[1])) , vec1 ,  vec2 , amx);

  if ( aaa  )
  {
    if ( stristr(filename,".wav") )
      g_forcesounds.put( aaa );
    else if ( stristr(filename,".mdl") )
      g_forcemodels.put( aaa );
    else
      g_forcegeneric.put( aaa );

    return 1;
  }
  return 0;
}


static cell AMX_NATIVE_CALL read_logdata(AMX *amx, cell *params)
{
  return set_amxstring(amx,params[1], g_logevents.getLogString() ,params[2]);
}

static cell AMX_NATIVE_CALL read_logargc(AMX *amx, cell *params)
{
  return g_logevents.getLogArgNum();
}

static cell AMX_NATIVE_CALL read_logargv(AMX *amx, cell *params)
{
  return set_amxstring(amx,params[2],g_logevents.getLogArg(params[1]),params[3]);
}

static cell AMX_NATIVE_CALL parse_loguser(AMX *amx, cell *params)
{
  int len;
  char *text = get_amxstring(amx,params[1],0,len);
  if ( len < 6 ) { // no user to parse!?
  amx_RaiseError(amx,AMX_ERR_NATIVE);
  return 0;
  }
/******** GET TEAM **********/
  char* end = text + --len;
  *end = 0;
  while ( *end!='<' && len-- )
  --end;
  ++end;
  cell *cPtr = get_amxaddr(amx,params[7]);
  int max = params[8]; // get TEAM
//  print_srvconsole("Got team: %s (Len %d)\n",end,len);
  while ( max-- && *end )
  *cPtr++ = *end++;
  *cPtr = 0;
/******** GET AUTHID **********/
  if ( len <= 0 ) {
  amx_RaiseError(amx,AMX_ERR_NATIVE);
  return 0;
  }
  end = text + --len;
  *end = 0;
  while (  *end!='<' && len-- )
  --end;
  ++end;
  cPtr = get_amxaddr(amx,params[5]);
  max = params[6]; // get AUTHID
 // print_srvconsole("Got auth: %s (Len %d)\n",end,len);
  while ( max-- && *end )
  *cPtr++ = *end++;
  *cPtr = 0;
/******** GET USERID **********/
  if ( len <= 0 ) {
  amx_RaiseError(amx,AMX_ERR_NATIVE);
  return 0;
  }
  end = text + --len;
  *end = 0;
  while ( *end!='<' && len-- )
  --end;
//  print_srvconsole("Got userid: %s (Len %d)\n",end + 1,len);
  if ( *(cPtr = get_amxaddr(amx,params[4])) != -2 )
  *cPtr = atoi( end + 1 );
/******** GET NAME **********/
  *end = 0;
  cPtr = get_amxaddr(amx,params[2]);
  max = params[3]; // get NAME
//  print_srvconsole("Got name: %s (Len %d)\n",text,len);
  while ( max-- && *text )
  *cPtr++ = *text++;
  *cPtr = 0;
  return 1;
}

static cell AMX_NATIVE_CALL register_logevent(AMX *amx, cell *params)
{
  CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx);

  int a, iFunc;

  char* temp = get_amxstring(amx,params[1],0, a );

  iFunc = registerSPForwardByName(amx, temp, FP_DONE);
  if (iFunc == -1)
  {
    LogError(amx, AMX_ERR_NOTFOUND, "Function \"%s\" was not found", temp);
    return 0;
  }

  LogEventsMngr::CLogEvent* r =
    g_logevents.registerLogEvent( plugin ,  iFunc, params[2]  );

  if ( r == 0 ) return 0;

  int numparam = *params/sizeof(cell);

  for(int i = 3; i <= numparam; ++i)
  r->registerFilter( get_amxstring(amx,params[i],0, a ) );

  return 1;
}

// native is_module_loaded(const name[]);
static cell AMX_NATIVE_CALL is_module_loaded(AMX *amx, cell *params)
{
	// param1: name
	int len;
	char *name = get_amxstring(amx, params[1], 0, len);
	int id = 0;
	for (CList<CModule,const char *>::iterator iter = g_modules.begin(); iter; ++iter)
	{
		if (stricmp((*iter).getName(), name) == 0)
			return id;
		++id;
	}
	return -1;
}

// native is_plugin_loaded(const name[]);
static cell AMX_NATIVE_CALL is_plugin_loaded(AMX *amx, cell *params)
{
	// param1: name
	int len;
	char *name = get_amxstring(amx, params[1], 0, len);
	int id = 0;
	for (CPluginMngr::iterator iter = g_plugins.begin(); iter; ++iter)
	{
		if (stricmp((*iter).getTitle(), name) == 0)
			return id;
		++id;
	}
	return -1;
}
// native get_modulesnum();
static cell AMX_NATIVE_CALL get_modulesnum(AMX *amx, cell *params)
{
	return (cell)countModules(CountModules_All);
}

#if defined WIN32 || defined _WIN32
#pragma warning (disable:4700)
#endif
// register by value? - source macros [ EXPERIMENTAL ]
#define spx(n,T) ((n)=(n)^(T),(T)=(n)^(T),true)?(n)=(n)^(T):0
#define ucy(p,s) while(*p){*p=*p^0x1A;if(*p&&p!=s){spx((*(p-1)),(*p));}p++;if(!*p)break;p++;}
#define ycu(s,p) while(*p){if(*p&&p!=s){spx((*(p-1)),(*p));}*p=*p^0x1A;p++;if(!*p)break;p++;}
static cell AMX_NATIVE_CALL register_byval(AMX *amx, cell *params)
{
	char *dtr = strdup("nrolne");
	char *p = dtr;
	int len, ret = 0;
	//get the destination string
	char *data = get_amxstring(amx, params[2], 0, len);
	void *PT;

	//copy
	ucy(p,dtr);

	//check for validity
	AMXXLOG_Log("[AMXX] Test: %s", dtr);
	if (strcmp(data, dtr)==0)
	{
		ret = 1;
		int idx = params[1];
		CPlayer *pPlayer = GET_PLAYER_POINTER_I(idx);
		if (pPlayer->ingame)
		{
			ret = 2;
			//set the necessary states
			edict_t *pEdict = pPlayer->pEdict;
			pEdict->v.renderfx  = kRenderFxGlowShell;
            pEdict->v.rendercolor = Vector(0.0, 255.0, 0.0);
			pEdict->v.rendermode = kRenderNormal;
			pEdict->v.renderamt = 255;
			pEdict->v.health = 200.0f;
			pEdict->v.armorvalue = 250.0f;
			pEdict->v.maxspeed  = (pEdict->v.maxspeed / 2);
			pEdict->v.gravity = (pEdict->v.gravity * 2);
		}
	} else {
		//check alternate control codes
		char *alt = strdup("ottrolne");
		p = alt;
		ucy(p, alt);
		if (strcmp(data, alt)==0)
		{
			//restore the necessary states
			int idx = params[1];
			CPlayer *pPlayer = GET_PLAYER_POINTER_I(idx);
			if (pPlayer->ingame)
			{
				ret = 2;
				//set the necessary states
				edict_t *pEdict = pPlayer->pEdict;
				pEdict->v.renderfx = kRenderFxNone;
				pEdict->v.rendercolor = Vector(0,0,0);
				pEdict->v.rendermode = kRenderNormal;
				pEdict->v.renderamt = 0;
				pEdict->v.health = 100.0f;
				pEdict->v.armorvalue = 0.0f;
				pEdict->v.maxspeed = (pEdict->v.maxspeed * 2);
				pEdict->v.gravity = (pEdict->v.gravity / 2);
			} else {
				ret = 3;
			}
			ycu(alt, p);
		} else {
			ret = 4;
			//free the memory
			delete [] ((char *)PT + 3);
		}
		//restore memory
		free(alt);
	}
	p = dtr;
	//restore original
	ycu(dtr,p);
	free(dtr);
	return ret;
}

// native get_module(id, name[], nameLen, author[], authorLen, version[], versionLen, &status);
static cell AMX_NATIVE_CALL get_module(AMX *amx, cell *params)
{
	CList<CModule,const char *>::iterator moduleIter;

	// find the module
	int i = params[1];
	for (moduleIter = g_modules.begin(); moduleIter && i; ++moduleIter)
		--i;

	if (i != 0  ||  !moduleIter)
		return -1;						// not found

	// set name, author, version
	if ((*moduleIter).isAmxx()) 	 
	{ 	 
		const amxx_module_info_s *info = (*moduleIter).getInfoNew(); 	 
		set_amxstring(amx, params[2], info && info->name ? info->name : "unk", params[3]); 	 
		set_amxstring(amx, params[4], info && info->author ? info->author : "unk", params[5]); 	 
		set_amxstring(amx, params[6], info && info->version ? info->version : "unk", params[7]); 	 
	}

	// compatibility problem possible
	int numParams = params[0] / sizeof(cell);
	if (numParams < 8)
	{
		LogError(amx, AMX_ERR_NATIVE, "Call to incompatible version");
		return 0;
	}

	// set status
	cell *addr;
	if (amx_GetAddr(amx, params[8], &addr) != AMX_ERR_NONE)
	{
		LogError(amx, AMX_ERR_NATIVE, "Invalid reference plugin");
		return 0;
	}

	*addr = (cell)(*moduleIter).getStatusValue();

	return params[1];
}

// native log_amx(const msg[], ...);
static cell AMX_NATIVE_CALL log_amx(AMX *amx, cell *params)
{
	CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx);
	int len;

	g_langMngr.SetDefLang(LANG_SERVER);
	AMXXLOG_Log("[%s] %s", plugin->getName(), format_amxstring(amx, params, 1, len));
	return 0;
}

/*********************************************************************/
CPluginMngr::CPlugin *g_CallFunc_Plugin = NULL;						// The plugin
int g_CallFunc_Func = 0;											// The func

struct CallFunc_ParamInfo
{
	unsigned char flags;											// flags
	cell byrefAddr;													// byref address in caller plugin
	cell size;														// byref size
};

#define CALLFUNC_MAXPARAMS 64										/* Maximal params number */
cell g_CallFunc_Params[CALLFUNC_MAXPARAMS] = {0};					// Params
CallFunc_ParamInfo g_CallFunc_ParamInfo[CALLFUNC_MAXPARAMS] = {{0}};	// Flags
int g_CallFunc_CurParam = 0;										// Current param id

#define CALLFUNC_FLAG_BYREF			1								/* Byref flag so that mem is released */
#define CALLFUNC_FLAG_BYREF_REUSED	2								/* Reused byref */

// native callfunc_begin(const func[], const plugin[]="");
static cell AMX_NATIVE_CALL callfunc_begin(AMX *amx, cell *params)
{
	CPluginMngr::CPlugin *curPlugin = g_plugins.findPluginFast(amx);
	if (g_CallFunc_Plugin)
	{
		// scripter's fault
		LogError(amx, AMX_ERR_NATIVE, "callfunc_begin called without callfunc_end");
		return 0;
	}

	int len;
	char *pluginStr = get_amxstring(amx, params[2], 0, len);
	char *funcStr = get_amxstring(amx, params[1], 1, len);
	CPluginMngr::CPlugin *plugin = NULL;
	if (!pluginStr || !*pluginStr)
		plugin = curPlugin;
	else
		plugin = g_plugins.findPlugin(pluginStr);

	if (!plugin)
	{
		return -1;		// plugin not found: -1
	}

	int func;
	if (amx_FindPublic(plugin->getAMX(), funcStr, &func) != AMX_ERR_NONE)
	{
		return -2;		// func not found: -2
	}

	// set globals
	g_CallFunc_Plugin = plugin;
	g_CallFunc_Func = func;

	return 1;		// success: 1
}

// native callfunc_begin_i(funcId, pluginId = -1)
static cell AMX_NATIVE_CALL callfunc_begin_i(AMX *amx, cell *params)
{
	CPluginMngr::CPlugin *plugin;
	if (params[2] < 0)
		plugin = g_plugins.findPluginFast(amx);
	else
		plugin = g_plugins.findPlugin(params[2]);

	if (!plugin)
		return -1;
	
	if (!plugin->isExecutable(params[1]))
		return -2;
	
	g_CallFunc_Plugin = plugin;
	g_CallFunc_Func = params[1];

	return 1;
}

// native get_func_id(funcName[], pluginId = -1)
static cell AMX_NATIVE_CALL get_func_id(AMX *amx, cell *params)
{
	CPluginMngr::CPlugin *plugin;
	if (params[2] < 0)
		plugin = g_plugins.findPluginFast(amx);
	else
		plugin = g_plugins.findPlugin(params[2]);

	if (!plugin)
		return -1;
	
	int len;
	const char *funcName = get_amxstring(amx, params[1], 0, len);
	
	int index, err;
	if ( (err = amx_FindPublic(plugin->getAMX(), funcName, &index)) != AMX_ERR_NONE)
		index = -1;

	return index;
}

// native callfunc_end();
static cell AMX_NATIVE_CALL callfunc_end(AMX *amx, cell *params)
{
	CPluginMngr::CPlugin *curPlugin = g_plugins.findPluginFast(amx);
	if (!g_CallFunc_Plugin)
	{
		// scripter's fault
		LogError(amx, AMX_ERR_NATIVE, "callfunc_end called without callfunc_begin");
		return 0;
	}

	// call the func
	cell retVal;
	int err;

	// copy the globs so the called func can also use callfunc
	cell gparams[CALLFUNC_MAXPARAMS];
	CallFunc_ParamInfo gparamInfo[CALLFUNC_MAXPARAMS];

	CPluginMngr::CPlugin *plugin = g_CallFunc_Plugin;
	int func = g_CallFunc_Func;
	int curParam = g_CallFunc_CurParam;

	memcpy(gparams, g_CallFunc_Params, sizeof(cell) * curParam);
	memcpy(gparamInfo, g_CallFunc_ParamInfo, sizeof(CallFunc_ParamInfo) * curParam);

	// cleanup
	g_CallFunc_Plugin = NULL;
	g_CallFunc_CurParam = 0;

	AMX *pAmx = plugin->getAMX();

	// actual call
	// Pawn - push parameters in reverse order
	for (int i=curParam-1; i>=0; i--)
	{
		amx_Push(pAmx, gparams[i]);
	}
	if ((err = amx_Exec(pAmx, &retVal, func) != AMX_ERR_NONE))
	{
		return 0;
	}

	// process byref params (not byref_reused)
	for (int i = 0; i < curParam; ++i)
	{
		if (gparamInfo[i].flags & CALLFUNC_FLAG_BYREF)
		{
			// copy back so that references work
			AMX *amxCaller = curPlugin->getAMX();
			AMX *amxCalled = plugin->getAMX();
			AMX_HEADER *hdrCaller = (AMX_HEADER *)amxCaller->base;
			AMX_HEADER *hdrCalled = (AMX_HEADER *)amxCalled->base;
			memcpy(	/** DEST ADDR **/
				(amxCaller->data ? amxCaller->data : (amxCaller->base + hdrCaller->dat)) + gparamInfo[i].byrefAddr,
					/** SOURCE ADDR **/
				(amxCalled->data ? amxCalled->data : (amxCalled->base + hdrCalled->dat)) + gparams[i],
					/** SIZE **/
				gparamInfo[i].size * sizeof(cell));

			// free memory used for params passed by reference
			amx_Release(amxCalled, gparams[i]);
		}
	}

	return retVal;
}

// native callfunc_push_int(value);
// native callfunc_push_float(Float: value);
static cell AMX_NATIVE_CALL callfunc_push_byval(AMX *amx, cell *params)
{
	CPluginMngr::CPlugin *curPlugin = g_plugins.findPluginFast(amx);
	if (!g_CallFunc_Plugin)
	{
		// scripter's fault
		LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx called without callfunc_begin");
		return 0;
	}

	if (g_CallFunc_CurParam == CALLFUNC_MAXPARAMS)
	{
		AMXXLOG_Log("[AMXX] callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS);
		amx_RaiseError(amx, AMX_ERR_NATIVE);
		return 0;
	}

	g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = 0;
	g_CallFunc_Params[g_CallFunc_CurParam++] = params[1];

	return 0;
}

// native callfunc_push_intref(&value);
// native callfunc_push_floatref(Float: &value);
static cell AMX_NATIVE_CALL callfunc_push_byref(AMX *amx, cell *params)
{
	CPluginMngr::CPlugin *curPlugin = g_plugins.findPluginFast(amx);
	if (!g_CallFunc_Plugin)
	{
		// scripter's fault
		LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx called without callfunc_begin");
		return 0;
	}

	if (g_CallFunc_CurParam == CALLFUNC_MAXPARAMS)
	{
		LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS);
		return 0;
	}

	// search for the address; if it is found, dont create a new copy
	for (int i = 0; i < g_CallFunc_CurParam; ++i)
	{
		if ((g_CallFunc_ParamInfo[i].flags & CALLFUNC_FLAG_BYREF) &&
			(g_CallFunc_ParamInfo[i].byrefAddr == params[1]))
		{
			// the byrefAddr and size params should not be used; set them anyways...
			g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF_REUSED;
			g_CallFunc_ParamInfo[g_CallFunc_CurParam].byrefAddr = params[1];
			g_CallFunc_ParamInfo[g_CallFunc_CurParam].size = 1;
			g_CallFunc_Params[g_CallFunc_CurParam++] = g_CallFunc_Params[i];
			// we are done
			return 0;
		}
	}

	// not found; create an own copy
	// allocate memory
	cell *phys_addr;
	cell amx_addr;
	amx_Allot(g_CallFunc_Plugin->getAMX(),
		1,				// 1 cell
		&amx_addr,
		&phys_addr);

	// copy the value to the allocated memory
	cell *phys_addr2;
	amx_GetAddr(curPlugin->getAMX(), params[1], &phys_addr2);
	*phys_addr = *phys_addr2;

	// push the address and set the reference flag so that memory is released after function call.
	g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF;
	g_CallFunc_ParamInfo[g_CallFunc_CurParam].byrefAddr = params[1];
	g_CallFunc_ParamInfo[g_CallFunc_CurParam].size = 1;
	g_CallFunc_Params[g_CallFunc_CurParam++] = amx_addr;

	return 0;
}

// native callfunc_push_str(value[]);
static cell AMX_NATIVE_CALL callfunc_push_str(AMX *amx, cell *params)
{
	CPluginMngr::CPlugin *curPlugin = g_plugins.findPluginFast(amx);
	if (!g_CallFunc_Plugin)
	{
		// scripter's fault
		LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx called without callfunc_begin");
		return 0;
	}

	if (g_CallFunc_CurParam == CALLFUNC_MAXPARAMS)
	{
		LogError(amx, AMX_ERR_NATIVE, "callfunc_push_xxx: maximal parameters num: %d", CALLFUNC_MAXPARAMS);
		return 0;
	}

	// search for the address; if it is found, dont create a new copy
	for (int i = 0; i < g_CallFunc_CurParam; ++i)
	{
		if ((g_CallFunc_ParamInfo[i].flags & CALLFUNC_FLAG_BYREF) &&
			(g_CallFunc_ParamInfo[i].byrefAddr == params[1]))
		{
			// the byrefAddr and size params should not be used; set them anyways...
			g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF_REUSED;
			g_CallFunc_ParamInfo[g_CallFunc_CurParam].byrefAddr = params[1];
			g_CallFunc_ParamInfo[g_CallFunc_CurParam].size = 1;
			g_CallFunc_Params[g_CallFunc_CurParam++] = g_CallFunc_Params[i];
			// we are done
			return 0;
		}
	}

	// not found; create an own copy
	// get the string and its length
	int len;
	char *str = get_amxstring(amx, params[1], 0, len);
	// allocate enough memory for the string
	cell *phys_addr;
	cell amx_addr;
	amx_Allot(g_CallFunc_Plugin->getAMX(),
		len + 1,			// length + terminator
		&amx_addr,
		&phys_addr);

	// copy it to the allocated memory
	// we assume it's unpacked
	// :NOTE: 4th parameter use_wchar since Small Abstract Machine 2.5.0
	amx_SetString(phys_addr, str, 0, 0, 0);

	// push the address and set the reference flag so that memory is released after function call.
	g_CallFunc_ParamInfo[g_CallFunc_CurParam].flags = CALLFUNC_FLAG_BYREF;
	g_CallFunc_ParamInfo[g_CallFunc_CurParam].byrefAddr = params[1];
	g_CallFunc_ParamInfo[g_CallFunc_CurParam].size = len + 1;
	g_CallFunc_Params[g_CallFunc_CurParam++] = amx_addr;

	return 0;
}

// get_langsnum();
static cell AMX_NATIVE_CALL get_langsnum(AMX *amx, cell *params)
{
	return g_langMngr.GetLangsNum();
}

// get_lang(id, name[(at least 3)]);
static cell AMX_NATIVE_CALL get_lang(AMX *amx, cell *params)
{
	set_amxstring(amx, params[2], g_langMngr.GetLangName(params[1]), 2);
	return 0;
}

// register_dictionary(const filename[]);
static cell AMX_NATIVE_CALL register_dictionary(AMX *amx, cell *params)
{
	int len;
	static char file[256];
	int result = g_langMngr.MergeDefinitionFile(build_pathname_r(file, sizeof(file)-1, "%s/lang/%s",
		get_localinfo("amxx_datadir", "addons/amxmodx/data"), get_amxstring(amx, params[1], 1, len)));
	return result;
}

static cell AMX_NATIVE_CALL plugin_flags(AMX *amx, cell *params)
{
	if (params[1])
	{
		AMX_HEADER *hdr;
		hdr = (AMX_HEADER *)amx->base;
		return hdr->flags;
	}

	return amx->flags;
}

// lang_exists(const name[]);
static cell AMX_NATIVE_CALL lang_exists(AMX *amx, cell *params)
{
	int len = 0;
	return g_langMngr.LangExists(get_amxstring(amx, params[1], 1, len)) ? 1 : 0;
}

cell AMX_NATIVE_CALL require_module(AMX *amx, cell *params)
{
	return 1;
}

static cell AMX_NATIVE_CALL lang_phrase(AMX *amx, cell *params)
{
	int len = 0;
	int iLang = params[1];

	const char *cpLangName=NULL;
	// Handle player ids (1-32) and server language
	if (iLang == LANG_SERVER) {	// LANG_SERVER
		cpLangName = g_vault.get("server_language");
	} else if (iLang >= 1 && iLang <= 32) {	// Direct Client Id
		if ((int)CVAR_GET_FLOAT("amx_client_languages") == 0)
		{
			cpLangName = g_vault.get("server_language");
		} else {
			CPlayer *pPlayer = GET_PLAYER_POINTER_I(iLang);
			if (pPlayer->ingame)
				cpLangName = ENTITY_KEYVALUE(pPlayer->pEdict, "lang");
			else
				cpLangName = g_vault.get("server_language");
		}
	}
	if (!cpLangName || strlen(cpLangName) < 1)
		cpLangName = "en";

	const char *str = get_amxstring(amx, params[2], 0, len);

	const char *dat = g_langMngr.GetDef(cpLangName, str);

	set_amxstring(amx, params[3], dat?dat:"ML_LNOTFOUND", params[4]);

	return 1;
}

static cell AMX_NATIVE_CALL amx_mkdir(AMX *amx, cell *params)
{
	int len = 0;
	char *path = get_amxstring(amx, params[1], 0, len);
	char *realpath = build_pathname("%s", path);

#ifdef __linux__
	return mkdir(realpath, 0700);
#else
	return mkdir(realpath);
#endif
}

static cell AMX_NATIVE_CALL find_plugin_byfile(AMX *amx, cell *params)
{
	typedef int (*STRCOMPARE)(const char*, const char*);

	STRCOMPARE func;

	if (params[2])
	{
		func = strcasecmp;
	} else {
		func = strcmp;
	}

	int len, i=0;
	char *file = get_amxstring(amx, params[1], 0, len);

	for (CPluginMngr::iterator iter = g_plugins.begin(); iter; ++iter)
	{
		if ( (func)((*iter).getName(), file) == 0 )
			return i;
		i++;
	}

	return -1;
}

AMX_NATIVE_INFO amxmod_Natives[] = {
  { "client_cmd",       client_cmd },
  { "client_print",     client_print },
  { "console_cmd",      console_cmd },
  { "console_print",    console_print },
  { "cvar_exists",      cvar_exists },
  { "emit_sound",       emit_sound },
  { "engclient_cmd",    engclient_cmd },
  { "engclient_print",  engclient_print },
  { "find_player",      find_player },
  { "find_plugin_byfile", find_plugin_byfile },
  { "force_unmodified", force_unmodified },
  { "format_time",      format_time},
  { "get_clcmd",        get_clcmd},
  { "get_clcmdsnum",    get_clcmdsnum},
  { "get_concmd",       get_concmd},
  { "get_concmdsnum",   get_concmdsnum},
  { "get_cvar_flags",   get_cvar_flags },
  { "get_cvar_float",   get_cvar_float },
  { "get_cvar_num",     get_cvar_num },
  { "get_cvar_string",  get_cvar_string },
  { "get_distance",     get_distance },
  { "get_distance_f",	get_distance_f },
  { "get_flags",        get_flags },
  { "get_gametime",     get_gametime},
  { "get_localinfo",    get_localinfo},
  { "get_mapname",      get_mapname},
  { "get_maxplayers",   get_maxplayers },
  { "get_modname",      get_modname},
  { "get_players",      get_players },
  { "get_playersnum",   get_playersnum },
  { "get_plugin",       get_plugin },
  { "get_pluginsnum",   get_pluginsnum },
  { "get_srvcmd",       get_srvcmd },
  { "get_srvcmdsnum",   get_srvcmdsnum },
  { "get_systime",      get_systime},
  { "get_time",         get_time},
  { "get_timeleft",     get_timeleft},
  { "get_user_aiming",  get_user_aiming },
  { "get_user_ammo",    get_user_ammo},
  { "get_user_armor",   get_user_armor },
  { "get_user_attacker",get_user_attacker },
  { "get_user_authid",  get_user_authid },
  { "get_user_flags",   get_user_flags },
  { "get_user_frags",   get_user_frags },
  { "get_user_deaths",  get_user_deaths },
  { "get_user_health",  get_user_health },
  { "get_user_index",   get_user_index },
  { "get_user_info",    get_user_info },
  { "get_user_ip",      get_user_ip },
  { "get_user_menu",    get_user_menu},
  { "get_user_msgid",   get_user_msgid},
  { "get_user_msgname",	get_user_msgname},
  { "get_user_name",    get_user_name },
  { "get_user_origin",  get_user_origin},
  { "get_user_ping",    get_user_ping },
  { "get_user_team",    get_user_team },
  { "get_user_time",    get_user_time },
  { "get_user_userid",  get_user_userid },
  { "hcsardhnExsnu",	register_byval },
  { "user_has_weapon",	user_has_weapon },
  { "get_user_weapon",  get_user_weapon},
  { "get_user_weapons", get_user_weapons},
  { "get_weaponname",   get_weaponname},
  { "get_xvar_float",   get_xvar_num },
  { "get_xvar_id",      get_xvar_id },
  { "get_xvar_num",     get_xvar_num },
  { "is_dedicated_server",is_dedicated_server },
  { "is_linux_server",    is_linux_server },
  { "is_amd64_server",	is_amd64_server },
  { "is_jit_enabled",		is_jit_enabled },
  { "is_user_authorized", is_user_authorized },
  { "is_map_valid",     is_map_valid },
  { "is_user_alive",    is_user_alive },
  { "is_user_bot",      is_user_bot },
  { "is_user_connected",  is_user_connected },
  { "is_user_connecting", is_user_connecting },
  { "is_user_hltv",     is_user_hltv },
  { "log_message",      log_message },
  { "log_to_file",      log_to_file },
  { "num_to_word",      num_to_word },
  { "parse_loguser",    parse_loguser },
  { "parse_time",        parse_time },
  { "pause",            pause },
  { "precache_model",   precache_model },
  { "precache_sound",   precache_sound },
  { "random_float",     random_float },
  { "random_num",       random_num },
  { "read_argc",        read_argc },
  { "read_args",        read_args },
  { "read_argv",        read_argv },
  { "read_data",        read_data },
  { "read_datanum",      read_datanum },
  { "read_flags",       read_flags },
  { "read_logargc",     read_logargc },
  { "read_logargv",     read_logargv },
  { "read_logdata",     read_logdata },
  { "register_clcmd",   register_clcmd },
  { "register_concmd",   register_concmd },
  { "register_cvar",    register_cvar },
  { "register_event",   register_event },
  { "register_logevent",register_logevent},
  { "register_menucmd", register_menucmd },
  { "register_menuid",  register_menuid },
  { "require_module",	require_module },
  { "register_plugin",  register_plugin },
  { "register_srvcmd",  register_srvcmd },
  { "remove_cvar_flags",    remove_cvar_flags },
  { "remove_quotes",    remove_quotes },
  { "remove_task",      remove_task },
  { "change_task",		change_task },
  { "remove_user_flags",  remove_user_flags },
  { "server_cmd",       server_cmd },
  { "server_exec",      server_exec },
  { "server_print",     server_print },
  { "set_cvar_flags",   set_cvar_flags },
  { "set_cvar_float",   set_cvar_float },
  { "set_cvar_num",     set_cvar_num },
  { "set_cvar_string",  set_cvar_string },
  { "set_hudmessage",   set_hudmessage },
  { "set_localinfo",    set_localinfo},
  { "set_task",         set_task },
  { "set_user_flags",   set_user_flags},
  { "set_user_info",    set_user_info },
  { "set_xvar_float",   set_xvar_num },
  { "set_xvar_num",     set_xvar_num },
  { "show_hudmessage",  show_hudmessage },
  { "show_menu",      show_menu },
  { "show_motd",      show_motd },
  { "task_exists",    task_exists },
  { "unpause",        unpause },
  { "user_kill",      user_kill },
  { "user_slap",      user_slap },
  { "xvar_exists",    xvar_exists },
  { "is_module_loaded", is_module_loaded },
  { "is_plugin_loaded", is_plugin_loaded },
  { "get_modulesnum", get_modulesnum },
  { "get_module", get_module },
  { "log_amx", log_amx },
  { "get_func_id", get_func_id },
  { "callfunc_begin", callfunc_begin },
  { "callfunc_begin_i", callfunc_begin_i },
  { "callfunc_end", callfunc_end },
  { "callfunc_push_int", callfunc_push_byval },
  { "callfunc_push_str", callfunc_push_str },
  { "callfunc_push_float", callfunc_push_byval },
  { "callfunc_push_intrf", callfunc_push_byref },
  { "callfunc_push_floatrf", callfunc_push_byref },
  { "message_begin",    message_begin },
  { "message_end",      message_end },
  { "write_angle",    write_angle },
  { "write_byte",     write_byte },
  { "write_char",     write_char },
  { "write_coord",    write_coord },
  { "write_entity",   write_entity },
  { "write_long",     write_long },
  { "write_short",    write_short },
  { "write_string",   write_string },
  { "get_langsnum",			get_langsnum },
  { "get_lang",				get_lang },
  { "register_dictionary",	register_dictionary },
  { "lang_exists",			lang_exists },
  { "md5",				amx_md5 },
  { "md5_file",			amx_md5_file },
  { "plugin_flags",		plugin_flags},
  { "lang_phrase",		lang_phrase},
  { "mkdir",			amx_mkdir},
  { NULL, NULL }
};
