/*********************************************************
 *      Bugblatter Rate Management Extension - V3.3      *
 *********************************************************
 *                                                       *
 * This plug-in is linux & win32 friendly.               *
 *                                                       *
 * Version 3.3:                                          *
 *                                                       *
 *  - Updated to compile on Admin Mod V2.50.56           *
 *                                                       *
 * Version 3.2:                                          *
 *                                                       *
 *  - Updated for language plugin version 3.3            *
 *                                                       *
 * Version 3.1:                                          *
 *                                                       *
 *  - No changes                                         *
 *                                                       *
 * Version 2.6:                                          *
 *                                                       *
 *  -  Added colour and timing settings for all          *
 *     messageex class on 2.51.xx alpha builds.          *
 *  -  Copes with plugin_info firing before              *
 *     plugin_connect                                    *
 *                                                       *
 * Version 2.5:                                          *
 *  -  Move prominent error messages in log              *
 *                                                       *
 * Version 2.4:                                          *
 *  -  Updated for adminmod 2.50.50                      *
 *  -  Does not return PLUGIN_FAILRE during init         *
 *  -  Works around bug in calling admin_command bb,,,   *
 *     from in a .cfg file saved in DOS format           *
 *                                                       *
 * Version 2.3:                                          *
 *  -  Checks values of server.cfg vars during init      *
 *                                                       *
 * Version 2.2:                                          *
 *  - No Changes                                         *
 *                                                       *
 * Version 2.1:                                          *
 *  - Multilingual                                       *
 *  - Updated for adminmod 2.50.37                       *
 *                                                       *
 * Version 2.0:                                          *
 *  - Playercount() bug from 1.7 was still lurking in    *
 *    some situations.  Added a rate change in           *
 *    plugin_info to correct it                          *
 *                                                       *
 * Version 1.9:                                          *
 *                                                       *
 *  - No longer counts bots as players when computing    *
 *    rate and doesn't exec commands on them             *
 *  - Report can be turned on and off now                *
 *                                                       *
 * Version 1.8:                                          *
 *                                                       *
 *  - sv_minrate and sv_maxrate are now restored if you  *
 *    switch from server or full mode to client mode as  *
 *    well as off.                                       *
 *                                                       *
 *  - mode is now specified as full/client/server/off    *
 *    rather than numeric values                         *
 *                                                       *
 *  - all commands / vault settings and corresponding    *
 *    global variables/ functions have been renamed to   *
 *    fit new conventions.                               *
 *                                                       *
 *  - bbrate_reset and bbrate_report added               *
 *                                                       *
 * Version 1.7:                                          *
 *                                                       *
 *  - Fixed bug in that playercount() was sometimes      *
 *    returning one too low during connect() and         *
 *    always one too high during disconnect().           *
 *                                                       *
 *  - Logs rate information each time it is changed      *
 *                                                       *
 * Version 1.6:                                          *
 *  - Adjusts cl_rate as well as rate                    *
 *  - New bb_lan feature to dynamically set local users  *
 *                                                       *
 * Version 1.5:                                          *
 *  - Fixed setting of sv_minrate/sv_maxrate and         *
 *    improved player counting. Thanks to ymboc for      *
 *    these fixes.                                       *
 *                                                       *
 *  - Returns sv_minrate and sv_maxrate to their         *
 *    original values and disables the plugin if you     *
 *    set bb_bandwidthmode to 0 (also adapted from code  *
 *    by ymboc).                                         *
 *                                                       *
 *  - Registers the right version number ;)              *
 *                                                       *
 * Version 1.4:                                          *
 *                                                       *
 *  - Copes with sv_maxrate and sv_minrate being missing *
 *    from server.cfg.                                   *
 *                                                       *
 * Version 1.3:                                          *
 *                                                       *
 *  - Removed bb_maxrate and bb_minrate. Plugin now uses *
 *    settings of sv_maxrate and sv_minrate in your      *
 *    server.cfg file.                                   *
 *                                                       *
 *  - Plugin now adjusts sv_maxrate and sv_minrate when  *
 *    changing users' rates to ensure they don't cheat   *
 *    and change their rate back to something high.      *
 *                                                       *
 * Version 1.0 - Initial Release                         *
 *                                                       *
 *********************************************************/
 
#include <core>
#include <console>
#include <string>
#include <admin>
#include <adminlib>
#include <plugin>
#include "settings"
#include "ip"
#include "clientio"
#include "language"
#include "connections"
 
new g_Version[]="3.3";
 
/* Initialisation function */
 
#define DEFAULT_BANDWIDTH 16384
#define MAX_BANDWIDTH   1048576
#define MIN_BANDWIDTH   2048
 
#define DEFAULT_MODE 3
#define MAX_MODE 3
#define MIN_MODE 0
 
#define DEFAULT_LOCAL_USERS 1
#define MAX_LOCAL_USERS 32
#define MIN_LOCAL_USERS 0
 
#define DEFAULT_IP 0
#define MIN_IP -2147483648
#define MAX_IP 2147483647
 
#define DEFAULT_REPORT 1
#define MIN_REPORT 0
#define MAX_REPORT 1
 
#define DEFAULT_MAX_RATE 6144
#define DEFAULT_MIN_RATE 2048
 
#define SHIFT8 256
#define SHIFT16 65536
#define SHIFT24 16777216
 
 
 
new g_MSG_REPORT_PROMPT[]="Bugblatter Rate Management Configuration:|Configuration du management du rafraichissement Bugblatter:|Bugblatter Rate-Management Konfiguration:";
new g_MSG_RPT_DISABLED[]=" - Rate management is disabled. (bbrate_mode)| - Le management du rafraichissement est desactive. (bbrate_mode)| - Rate-Management ist deaktiviert (bbrate_mode)";
new g_MSG_RPT_SERVER[]=" - Rate management is performed server-side only. (bbrate_mode)| - Le management du rafraichissement est active du cote serveur seulement. (bbrate_mode)| - Rate-Management wird nur auf Server-Seite ausgefuehrt (bbrate_mode)";
new g_MSG_RPT_CLIENT[]=" - Rate management is performed client-side only. (bbrate_mode)| - Le management du rafraichissement est active du cote client seulement. (bbrate_mode)| - Rate-Management wird nur auf Client-Seite ausgefuehrt (bbrate_mode)";
new g_MSG_RPT_BOTH[]=" - Rate management is performed on both the client and server. (bbrate_mode)| - Le management du rafraichissement est active a la fois pour le serveur et les clients. (bbrate_mode)| - Rate-Management wird auf Client- und Server-Seite ausgefuehrt (bbrate_mode)";
 
new g_MSG_RPT_AVAILABLE[]=" - Available bandwidth is set to %1i / %2iK. (bbrate_bandwidth)| - La bande passante disponible est reglee a %1i / %2iK. (bbrate_bandwidth)| - Verfuegbare Bandbreite ist auf %1i / %2iK gesetzt (bbrate_bandwidth)";
new g_MSG_RPT_MAX[]=" - Maximum rate is %1i. (sv_maxrate in server.cfg)| - Le rafraichissement maximum est %1i. (sv_maxrate dans server.cfg)| - Maximale Rate ist %i. (sv_maxrate in server.cfg)";
new g_MSG_RPT_MIN[]=" - Minimum rate is %1i. (sv_minrate in server.cfg)| - Le rafraichissement minimum est %1i. (sv_minrate dans server.cfg)| - Minimale Rate ist %i. (sv_minrate in server.cfg)";
new g_MSG_RPT_LOCAL[]=" - Fixed places for local users is set to %1i. (bbrate_localusers)| - Le nombre de places fixe pour les utilisateurs locaux est reglee a %1i. (bbrate_localusers)| - Festgelegte Plaetze fuer lokale User ist auf %1i gesetzt";
new g_MSG_RPT_IP[]=" - IP address for local subnet is %1s. (bbrate_lan)| - L'adresse IP du subnet local est %1s. (bbrate_lan)| - IP-Adresse des lokalen Subnets ist %1s (bbrate_lan)";
new g_MSG_RPT_MASK[]=" - Network mask for local subnet is %1s. (bbrate_lan)| - Le masque de sous-reseau du subnet local est %1s. (bbrate_lan)| - Netzwerkmaske des lokalen Subnets ist %1s (bbrate_lan)";
 
new g_MSG_STATUS_PROMPT[]="Current status:|Status actuel:|Momentaner Status:";
new g_MSG_STATUS_INTERNET[]="Number of Internet players = %1i|Nombre de joueurs d'internet = %1i|Anzahl der Internet-Spieler = %1i";
new g_MSG_STATUS_LAN[]="Number of LAN players  = %1i (NOTE: Includes bbrate_localusers count)|Nombre de joueurs en LAN = %1i (NOTE: Inclus le decompte bbrate_localusers)|Anzahl der LAN-Spieler = %1i (Beinhaltet bbrate_localusers)";
new g_MSG_STATUS_BOTS[]="Number of Bots = %1i|Nobre de Bots = %1i|Anzahl an Bots = %1i";
new g_MSG_STATUS_RATE[]="Computed rate = %1i / %2iK|Rafraichissement de l'ordinateur = %1i / %2iK|Berechnete Rate = %1i / %i2K";
 
/* Config variables */
new g_Bandwidth=DEFAULT_BANDWIDTH;
new g_MaxRate=DEFAULT_MAX_RATE;
new g_MinRate=DEFAULT_MIN_RATE;
new g_LocalUsers=DEFAULT_LOCAL_USERS;
new g_Mode=DEFAULT_MODE;
new g_LocalIP=0;
new g_LocalNetMask=0;
new g_Report=DEFAULT_REPORT;
 
/* Status */
new g_UserCount=0;
new g_UserLocal=0;
new g_Bots=0;
new g_Rate=0;
new g_ResetMaxRate=0;
new g_ResetMinRate=0;
new g_Local[MAX_PLAYERS+1];
new g_Registered=0;
 
 
 
 
forward RegisterPlugin();
forward BBRateBandwidth(HLCommand,HLData,HLUserName,UserIndex);
forward BBRateMode(HLCommand,HLData,HLUserName,UserIndex);
forward BBRateLocalUsers(HLCommand,HLData,HLUserName,UserIndex);
forward BBRateLan(HLCommand,HLData,HLUserName,UserIndex);
forward BBRateReport(HLCommand,HLData,HLUserName,UserIndex);
forward BBRateReset(HLCommand,HLData,HLUserName,UserIndex);
forward SetRate(Offset,Force);
forward CurrentLocalUsers();
forward ShowConfig(Force,UserIndex);
 
 
 
 
 
public plugin_init() {
  plugin_registerinfo("Bugblatter's Rate Management Plugin","Optimises server bandwidth usage and prevents spikes",g_Version);
 
  /* Check server is configured properly */
  new fOK = checkAllowClientExec();
  fOK = checkVaultOK() && fOK;
  fOK = checkMinRate() && fOK;
  fOK = checkMaxRate() && fOK;
  if (fOK == 0) {
    return PLUGIN_CONTINUE;
  }
 
  /* No need to abort if this one fails */
  checkLanguage();
 
  /* Read saved settings from vault */
  readvaultnum("bbrate_localusers",g_LocalUsers, DEFAULT_LOCAL_USERS,MIN_LOCAL_USERS,MAX_LOCAL_USERS);
  readvaultnum("bbrate_bandwidth",g_Bandwidth, DEFAULT_BANDWIDTH,MIN_BANDWIDTH,MAX_BANDWIDTH);
  readvaultnum("bbrate_mode",g_Mode, DEFAULT_MODE,MIN_MODE,MAX_MODE);
  readvaultnum("bbrate_report",g_Report,DEFAULT_REPORT,MIN_REPORT,MAX_REPORT);
 
  new Buffer[16]="";
  get_vaultdata("bbrate_localip",Buffer,16);
  strtoip(Buffer,g_LocalIP);
  get_vaultdata("bbrate_localnetmask",Buffer,16);
  strtoip(Buffer,g_LocalNetMask);
 
  g_MaxRate = getvar("sv_maxrate");
  if (g_MaxRate == 0) {
    g_MaxRate = 6144;
    configError("sv_maxrate must be set in server.cfg for plugin_blatt_rate to work properly.");
    return PLUGIN_CONTINUE;
  }
  else {
    g_ResetMaxRate = 1;
  }
 
  g_MinRate = getvar("sv_minrate");
  if (g_MinRate == 0) {
    g_MinRate = 2048;
    configError("sv_minrate must be set in server.cfg for plugin_blatt_rate to work properly.");
    return PLUGIN_CONTINUE;
  }
  else {
    g_ResetMinRate = 1;
  }
 
  new i=0;
  for(i=0;i<=MAX_PLAYERS;i++) {
    g_Local[i]=0;
  }
 
  language_init();
  RegisterPlugin();
  return PLUGIN_CONTINUE;
}
 
RegisterPlugin() {
  /* Register commands with adminmod */
  plugin_registercmd("bbrate_bandwidth","BBRateBandwidth",ACCESS_CONFIG,
                     "bbrate_bandwidth <rate> | <kbps>K: Sets internet connection bandwidth in rate, or Kbps");
  plugin_registercmd("bbrate_localusers","BBRateLocalUsers",ACCESS_CONFIG,
                     "bbrate_localusers <n>: Sets number of users connecting from the LAN");
  plugin_registercmd("bbrate_mode","BBRateMode",ACCESS_CONFIG,
           "bbrate_mode < ^"off^" | ^"server^" | ^"client^" | ^"full^">: Turns client and server rate managmenet on/off");
  plugin_registercmd("bbrate_lan","BBRateLan",ACCESS_CONFIG,
                     "bbrate_lan <ipaddress> <netmask>: Defines the LAN subnet to enable dynamic counting of local users");
  plugin_registercmd("bbrate_report","BBRateReport",ACCESS_CONFIG,
                     "bbrate_report [ ^"on^" | ^"off^" ]: Shows the rate management config, and enables/disable report after every command");
  plugin_registercmd("bbrate_reset","BBRateReset",ACCESS_CONFIG,
                     "bbrate_reset: Restores the rate management configuration to the default settings");
  g_Registered=1;
}
 
/* User conneciton handlers */
 
public plugin_connect(HLUserName, HLIP, UserIndex) {
  if (g_Registered ==0) {
    return PLUGIN_FAILURE;
  }
 
  PlayerConnected(UserIndex);
 
  new Data[MAX_DATA_LENGTH];
  safe_convert(HLIP,Data,MAX_DATA_LENGTH);
 
  g_Local[UserIndex]=0;
  new IP;
  if (strtoip(Data,IP)==0) {
    /* Must be a bot joining, although that's not supposed to cause
     * a plugin_connect event.  Ignore it anyway */
    return PLUGIN_CONTINUE;
  }
 
  if (g_LocalIP != 0) {
    if ((g_LocalIP & g_LocalNetMask) == (IP & g_LocalNetMask)) {
      g_Local[UserIndex] = 1;
    }
    else {
      g_Local[UserIndex] = 0;
    }
  }
 
  SetRate(0,0);
  return PLUGIN_CONTINUE;
}
 
public plugin_info(HLOldName, HLNewName, UserIndex) {
  if (g_Registered ==0) {
    return PLUGIN_FAILURE;
  }
  if (IsPlayerConnected(UserIndex)==0) {
    return PLUGIN_CONTINUE;
  }
  SetRate(0,0);
  return PLUGIN_CONTINUE;
}
 
public plugin_disconnect(HLUserName, UserIndex) {
  if (g_Registered ==0) {
    return PLUGIN_FAILURE;
  }
  PlayerDisconnected(UserIndex);
 
  new UserName[MAX_NAME_LENGTH];
  new WONID;
  safe_convert(HLUserName,UserName,MAX_NAME_LENGTH);
 
  g_Local[UserIndex]=0;
 
  if (get_userWONID(UserName,WONID)) {
    if (WONID != 0) {
      /* -1 because the disconnecting user is still included in the count */
      SetRate(-1,0);
    }
  }
 
  return PLUGIN_CONTINUE;
}
 
 
/* Admin command handlers */
 
public BBRateBandwidth(HLCommand,HLData,HLUserName,UserIndex) {
  new Data[MAX_DATA_LENGTH];
  safe_convert(HLData,Data,MAX_DATA_LENGTH);
  g_UserCount=realplayercount(g_Bots);
 
  /* Check for data being supplied in Kbps */
  new len = strlen(Data);
  if ( len > 0) {
    if ((Data[len-1] == 'K') || (Data[len-1] == 'k')) {
      if (readHLnum(HLData,g_Bandwidth,DEFAULT_BANDWIDTH/128,MIN_BANDWIDTH/128,MAX_BANDWIDTH/128)) {
        g_Bandwidth = g_Bandwidth * 128;
        writevaultnum("bbrate_bandwidth",g_Bandwidth);
        SetRate(0,1);
      }
    }
    else {
      if (readHLnum(HLData,g_Bandwidth,DEFAULT_BANDWIDTH,MIN_BANDWIDTH,MAX_BANDWIDTH)) {
        writevaultnum("bbrate_bandwidth",g_Bandwidth);
        SetRate(0,1);
      }
    }
  }
  ShowConfig(0,UserIndex);
  return PLUGIN_HANDLED;
}
 
 
public BBRateMode(HLCommand,HLData,HLUserName,UserIndex) {
  g_UserCount=realplayercount(g_Bots);
 
  new Data[MAX_DATA_LENGTH];
  safe_convert(HLData,Data,MAX_DATA_LENGTH);
 
  if (streq(Data,"off")) {
    g_Mode = 0;
  } else if (streq(Data,"server")) {
    g_Mode = 1;
  } else if (streq(Data,"client")) {
    g_Mode = 2;
  } else if (streq(Data,"full")) {
    g_Mode = 3;
  } else {
    selfmessage("Usage: bbrate_mode off | client | server | full");
    return PLUGIN_HANDLED;
  }
 
 
  writevaultnum("bbrate_mode",g_Mode);
  SetRate(0,1);
 
  new RateCmd[MAX_TEXT_LENGTH];
  if ((g_Mode == 0) || (g_Mode == 2)) {
    if (g_ResetMaxRate) {
      snprintf(RateCmd,MAX_TEXT_LENGTH,"sv_maxrate %i",g_MaxRate);
      exec(RateCmd);
    }
 
    if (g_ResetMinRate) {
      snprintf(RateCmd,MAX_TEXT_LENGTH,"sv_minrate %i",g_MinRate);
      exec(RateCmd);
    }
  }
  ShowConfig(0,UserIndex);
  return PLUGIN_HANDLED;
}
 
public BBRateLocalUsers(HLCommand,HLData,HLUserName,UserIndex) {
  g_UserCount=realplayercount(g_Bots);
  if (readHLnum(HLData,g_LocalUsers,DEFAULT_LOCAL_USERS,MIN_LOCAL_USERS,MAX_LOCAL_USERS)) {
    writevaultnum("bbrate_localusers",g_LocalUsers);
    SetRate(0,1);
  }
  ShowConfig(0,UserIndex);
  return PLUGIN_HANDLED;
}
 
public BBRateLan(HLCommand,HLData,HLUserName,UserIndex) {
  g_UserCount=realplayercount(g_Bots);
  new Data[MAX_DATA_LENGTH];
  safe_convert(HLData,Data,MAX_DATA_LENGTH);
 
  new strIP[MAX_DATA_LENGTH];
  new strMask[MAX_DATA_LENGTH];
  if (strsplit(Data," ",strIP,MAX_DATA_LENGTH,strMask,MAX_DATA_LENGTH) == 2) {
    if (strtoip(strIP,g_LocalIP) && strtoip(strMask,g_LocalNetMask)) {
      set_vaultdata("bbrate_localip",strIP);
      set_vaultdata("bbrate_localnetmask",strMask);
      ShowConfig(0,UserIndex);
      return PLUGIN_HANDLED;
    }
  }
 
  selfmessage("usage: bbrate_lan <ipaddress> <subnetmask>");
  return PLUGIN_HANDLED;
}
 
public BBRateReport(HLCommand,HLData,HLUserName,UserIndex) {
  if (readHLonoff(HLData,g_Report,DEFAULT_REPORT,MIN_REPORT,MAX_REPORT)) {
    writevaultnum("bbrate_report",g_Report);
    ShowConfig(0,UserIndex);
  }
  else {
    ShowConfig(1,UserIndex);
  }
  return PLUGIN_HANDLED;
}
 
 
 
public BBRateReset(HLCommand,HLData,HLUserName,UserIndex) {
  g_UserCount=realplayercount(g_Bots);
 
  g_Bandwidth = DEFAULT_BANDWIDTH;
  writevaultnum("bbrate_bandwidth",g_Bandwidth);
  g_Mode = DEFAULT_MODE;
  writevaultnum("bbrate_mode",g_Mode);
  g_LocalUsers=DEFAULT_LOCAL_USERS;
  writevaultnum("bbrate_localusers",g_LocalUsers);
  g_LocalIP=0;
  g_LocalNetMask=0;
  set_vaultdata("bbrate_localip","0.0.0.0");
  set_vaultdata("bbrate_localnetmask","0.0.0.0");
  SetRate(0,1);
  ShowConfig(0,UserIndex);
  return PLUGIN_HANDLED;
}
 
 
/* Does the real work */
 
SetRate(Offset,Force) {
  new RateCmd[MAX_TEXT_LENGTH];
 
  new i = realplayercount(g_Bots)+Offset;
  if ((i == g_UserCount) && (Force==0)) {
    /*No need to change rate - number of users hasn't changed */
    return 0;
  }
  g_UserCount = i;
 
  g_UserLocal = g_LocalUsers + CurrentLocalUsers();
  new RemoteUsers = max(0,g_UserCount - g_UserLocal);
 
  if (RemoteUsers < 1) { RemoteUsers = 1; }
  g_Rate = g_Bandwidth / RemoteUsers;
 
  if (g_Rate>g_MaxRate) { g_Rate = g_MaxRate; }
  if (g_Rate<g_MinRate) { g_Rate = g_MinRate; }
 
  if ((g_Mode & 1) > 0) {
    snprintf(RateCmd,MAX_TEXT_LENGTH,"sv_maxrate %i",g_Rate);
    exec(RateCmd);
    snprintf(RateCmd,MAX_TEXT_LENGTH,"sv_minrate %i",g_Rate);
    exec(RateCmd);
  }
 
  if ((g_Mode & 2) > 0) {
    snprintf(RateCmd,MAX_TEXT_LENGTH,"rate %i",g_Rate);
    safe_execall(RateCmd);
    snprintf(RateCmd,MAX_TEXT_LENGTH,"cl_rate %i",g_Rate);
    safe_execall(RateCmd);
  }
 
  new Msg[MAX_TEXT_LENGTH];
  snprintf(Msg,MAX_TEXT_LENGTH,"Rate change: %i users, %i local users, %i bots, computed rate %i",g_UserCount,g_UserLocal,g_Bots,g_Rate);
  log(Msg);
  return 0;
}
 
CurrentLocalUsers() {
  new i;
  new count=0;
  for(i=0;i<=MAX_PLAYERS;i++) {
      count = count + g_Local[i];
  }
  return count;
}
 
ShowConfig(Force,UserIndex) {
  if ((Force==0) && (g_Report==0)) {
    return PLUGIN_HANDLED;
  }
  language_say(UserIndex,g_MSG_REPORT_PROMPT,print_type:print_console);
  if (g_Mode == 0) {
    language_say(UserIndex,g_MSG_RPT_DISABLED,print_type:print_console);
  } else if (g_Mode == 1) {
    language_say(UserIndex,g_MSG_RPT_SERVER,print_type:print_console);
  } else if (g_Mode == 2) {
    language_say(UserIndex,g_MSG_RPT_CLIENT,print_type:print_console);
  } else if (g_Mode == 3) {
    language_say(UserIndex,g_MSG_RPT_BOTH,print_type:print_console);
  }
 
  language_sayf(UserIndex,g_MSG_RPT_AVAILABLE,print_type:print_console,0,0,0,0,g_Bandwidth,g_Bandwidth/128);
 
  language_sayf(UserIndex,g_MSG_RPT_MAX,print_type:print_console,0,0,0,0,g_MaxRate);
  language_sayf(UserIndex,g_MSG_RPT_MIN,print_type:print_console,0,0,0,0,g_MinRate);
  language_sayf(UserIndex,g_MSG_RPT_LOCAL,print_type:print_console,0,0,0,0,g_LocalUsers);
 
  new data[20];
  iptostr(g_LocalIP,data);
  language_sayf(UserIndex,g_MSG_RPT_IP,print_type:print_console,0,0,0,0,data);
 
  iptostr(g_LocalNetMask,data);
  language_sayf(UserIndex,g_MSG_RPT_MASK,print_type:print_console,0,0,0,0,data);
 
  language_say(UserIndex,g_MSG_STATUS_PROMPT,print_type:print_console);
  language_sayf(UserIndex,g_MSG_STATUS_INTERNET,print_type:print_console,0,0,0,0,max(0,g_UserCount-g_UserLocal));
  language_sayf(UserIndex,g_MSG_STATUS_LAN,print_type:print_console,0,0,0,0,g_UserLocal);
  language_sayf(UserIndex,g_MSG_STATUS_BOTS,print_type:print_console,0,0,0,0,g_Bots);
  language_sayf(UserIndex,g_MSG_STATUS_RATE,print_type:print_console,0,0,0,0,g_Rate,g_Rate/128);
 
  return 0;
}