/*********************************************************
 *          Bugblatter Language Extension - V3.4         *
 *********************************************************
 *                                                       *
 * This plug-in is linux & win32 friendly. NOTE: Version *
 * 2.50.31 or later of adminmod is required.             *
 *                                                       *
 * Version history                                       *
 *                                                       *
 * Version 3.4:                                          *
 *                                                       *
 *  - Removed warnings compiling on Admin Mod 2.50.56    *
 *                                                       *
 * Version 3.3:                                          *
 *                                                       *
 *  -  Fixed bug that broke the plugin on 32 player      *
 *     servers if the 32nd slot was used. NOTE: This     *
 *     fix means new versions of all plugins that use    *
 *     plugin_blatt_language. If you have used it in     *
 *     your own plugin, you simply need to recompile     *
 *     with the updated language.inc.                    *
 *                                                       *
 *  -  Validates that chosen language is withing range.  *
 *     When another plugin pops up a menu at the same    *
 *     time as this one it is possible for this plugin   *
 *     to read the wrong results.                        *
 *                                                       *
 *  -  Contains workaround for bugs in playerinfo when   *
 *     a player reconnects in a previously used slot     *
 *     that prevented the menu appearing and used the    *
 *     players team as their choice of language.         *
 *                                                       *
 *  -  Fixed bug where plugin was not reading back mode  *
 *     and report settings after a map change            *
 *                                                       *
 * Version 3.2:                                          *
 *                                                       *
 *  -  Fixes to the german transalation strings for real *
 *     this time :) Last time I put the comment in that  *
 *     there were fixes, but somehow forgo to copy any   *
 *     of the actual new strings. /me makes Homer noises *
 *                                                       *
 * Version 3.1:                                          *
 *                                                       *
 *  -  Fixes to the german transalation strings          *
 *                                                       *
 * Version 2.6:                                          *
 *                                                       *
 *  -  Added colour and timing settings for all          *
 *     messageex class on 2.51.xx alpha builds.          *
 *  -  Handles the menu being cancelled better           *
 *  -  Support setinfo lang "<language>" setting         *
 *                                                       *
 * Version 2.5:                                          *
 *                                                       *
 *  -  Bugfix to default language selection              *
 *  -  Removed menu display timing, and plugin no        *
 *     no longer uses logd for this.                     *
 *                                                       *
 * Version 2.4:                                          *
 *                                                       *
 *  -  Updated for adminmod 2.50.50                      *
 *  -  Doesn't return plugin failure during init         *
 *  -  Works around bug in calling admin_command bb,,,   *
 *     from in a .cfg file saved in DOS format           *
 *  -  Default language command added                    *
 *                                                       *
 * Version 2.3:                                          *
 *                                                       *
 *  -  Checks values of server.cfg vars during init      *
 *                                                       *
 * Version 2.2:                                          *
 *                                                       *
 *  - Logd detected messages aren't logged anymore       *
 *                                                       *
 * Version 2.1:                                          *
 *                                                       *
 *  - Initial release.                                   *
 *                                                       *
 *********************************************************/
 
#include <core>
#include <console>
#include <string>
#include <admin>
#include <adminlib>
#include "settings"
#include "clientio"
#include "language"
#include "connections"
 
 
new g_Version[] = "3.4";
 
/* NOTE: This plugin does not contain any settings that should
 * be configured by changing the source */
 
#define DEFAULT_MODE 1;
#define MIN_MODE 0;
#define MAX_MODE 1;
 
#define DEFAULT_REPORT 1;
#define MIN_REPORT 0;
#define MAX_REPORT 1;
 
#define MAX_MENU_LENGTH 512;
#define RECHECK_TIME 15;
 
/* Current confgiuration */
new g_Mode = DEFAULT_MODE;
new g_Report = DEFAULT_REPORT;
new g_UserInMenu[MAX_PLAYERS];
 
/* Cached IDs from last map */
new g_AuthLanguage[MAX_PLAYERS];
new g_AuthID[MAX_PLAYERS][MAX_AUTHID_LENGTH];
new g_Registered=0;
new g_Timer=0;
 
new g_ConnectX[MAX_PLAYERS];
new g_ConnectY[MAX_PLAYERS];
new g_ConnectZ[MAX_PLAYERS];
 
new g_MSG_PROMPT[] = "Bugblatter multi-lingual configuration:| configuration multilingue Bugblatter:|Bugblatter mehrsprachige Konfiguration:";
new g_MSG_DISABLED[] = " - Language selection is currently disabled.(bblanguage_mode)| - Le choix de langue est actuellement neutralise.(bblanguage_mode)| - Sprachvorwahl ist z.Z. gesperrt (bblanguage_mode)";
new g_MSG_ENABLED[] = " - Language selection is currently enabled. (bblanguage_mode)| - Le choix de langue est actuellement permis.(bblanguage_mode)| - Sprachvorwahl ist z.Z. aktiv (bblanguage_mode)";
new g_MSG_DEFAULT[] = " - Default language option is %1i (bblanguage_default)|- L'option de lange par defaut est %1i (bblanguage_default)| - Voreingestellte Sprachoption ist %1i (bblanguage_default)";
new g_MSG_DEFAULTNEXTMAP[] = "Defaut language change will not take effect until the next map change|Le changement de langue par defaut ne prendra pas effet avant le prochain changement de map|Die Aenderung der voreingestellten Sprache ist bis zum naechsten Mapwechsel unwirksam";
 
forward BBLanguageMode(HLCommand,HLData,HLUserName,UserIndex);
forward BBLanguageReset(HLCommand,HLData,HLUserName,UserIndex);
forward BBLanguageReport(HLCommand,HLData,HLUserName,UserIndex);
forward BBLanguageDefault(HLCommand,HLData,HLUserName,UserIndex);
forward ShowConfig(Force,UserIndex);
forward check_languages();
forward display_menu(Index,Name[]);
forward menuselect(HLCommand,HLData,HLUserName,UserIndex);
forward menucancel(HLCommand,HLData,HLUserName,UserIndex);
forward writeauthcache();
forward readauthcache();
forward checkauthcache(AuthID[]);
 
 
 
 
/*
 *********************************************************
 *                  PLUGIN INITIALISATION                *
 *********************************************************
*/
 
 
public plugin_init() {
 
  plugin_registerinfo("Bugblatter's Multi-lingual Plugin","Allows other plugins to communicate with each player in their own language",g_Version);
 
  new fOK = checkVaultOK();
  if (fOK == 0) {
    return PLUGIN_CONTINUE;
  }
 
  readvaultnum("bblanguage_mode",g_Mode,DEFAULT_MODE,MIN_MODE,MAX_MODE);
  readvaultnum("bblanguage_report",g_Report,DEFAULT_REPORT,MIN_REPORT,MAX_REPORT);
  /* bblanguage_default is read inside language_init */
 
  readauthcache();
 
  /* Register callbacks with admin mod */
  language_init();
  plugin_registercmd("bblanguage_report","BBLanguageReport",ACCESS_ALL,
                     "bblanguage_report [ ^"on^" | ^"off^" ]: Shows the language config, and enables/disable report after every command");
  plugin_registercmd("bblanguage_reset","BBLanguageReset",ACCESS_CONFIG,
                     "bblanguage_reset: sets all language settings to defaults");
  plugin_registercmd("bblanguage_mode","BBLanguageMode",ACCESS_CONFIG,
         "bblanguage_mode < ^"on^" | ^"off^" >: Enables / Disables language selection menus");
  plugin_registercmd("bblanguage_default","BBLanguageDefault",ACCESS_CONFIG,
                     "bblanguage_default <number>: Sets default language for server");
 
  plugin_registercmd("say","HandleSay",ACCESS_ALL);
 
  plugin_registercmd("radio1","menucancel",ACCESS_ALL);
  plugin_registercmd("radio2","menucancel",ACCESS_ALL);
  plugin_registercmd("radio3","menucancel",ACCESS_ALL);
  plugin_registercmd("buy","menucancel",ACCESS_ALL);
  plugin_registercmd("buyequip","menucancel",ACCESS_ALL);
  plugin_registercmd("chooseteam","menucancel",ACCESS_ALL);
 
  plugin_registercmd("menuselect","menuselect",ACCESS_ALL);
  g_Registered=1;
 
  if (g_Mode==1) {
    g_Timer = set_timer("check_languages",15,1,"");
  }
 
  return PLUGIN_CONTINUE;
}
 
 
 
/*
 *********************************************************
 *        ADMINISTRATOR COMMAND HANDLER FUNCTIONS        *
 *********************************************************
*/
 
public BBLanguageDefault(HLCommand,HLData,HLUserName,UserIndex) {
  if (readHLnum(HLData,g_DefaultLanguage,DEFAULT_DEFAULT_LANGUAGE,MIN_DEFAULT_LANGUAGE,MAX_DEFAULT_LANGUAGE)) {
    writevaultnum("bblanguage_default",g_DefaultLanguage);
    language_say(UserIndex,g_MSG_DEFAULTNEXTMAP,print_type:print_console);
  }
  return ShowConfig(0,UserIndex);
}
 
public BBLanguageMode(HLCommand,HLData,HLUserName,UserIndex) {
  if (readHLonoff(HLData,g_Mode,DEFAULT_MODE,MIN_MODE,MAX_MODE)) {
  writevaultnum("bblanguage_mode",g_Mode);
  }
  return ShowConfig(0,UserIndex);
}
 
public BBLanguageReset(HLCommand,HLData,HLUserName,UserIndex) {
  g_Mode=DEFAULT_MODE;
  writevaultnum("bblanguage_mode",g_Mode);
  if (g_Timer!=0) {
    kill_timer(g_Timer);
    g_Timer=0;
  }
  if (g_Mode==1) {
    g_Timer = set_timer("check_languages",15,99999,"");
  }
  return ShowConfig(0,UserIndex);
}
 
public BBLanguageReport(HLCommand,HLData,HLUserName,UserIndex) {
  if (readHLonoff(HLData,g_Report,DEFAULT_REPORT,MIN_REPORT,MAX_REPORT)) {
    writevaultnum("bblanguage_report",g_Report);
    ShowConfig(0,UserIndex);
  }
  else {
    ShowConfig(1,UserIndex);
  }
  return PLUGIN_HANDLED;
}
 
public HandleSay(HLCommand,HLData,HLUserName,UserIndex) {
  new Data[MAX_DATA_LENGTH];
  new User[MAX_NAME_LENGTH];
  convert_string(HLData,Data,MAX_DATA_LENGTH);
  convert_string(HLUserName,User,MAX_DATA_LENGTH);
  strstripquotes(Data);
 
  if (streq(Data,"language")) {
    display_menu(UserIndex,User);
    return PLUGIN_HANDLED;
  }
  return PLUGIN_CONTINUE;
}
 
ShowConfig(Force,UserIndex) {
  if ((Force==0) && (g_Report==0)) {
    return PLUGIN_HANDLED;
  }
 
  language_say(UserIndex,g_MSG_PROMPT,print_type:print_console);
  if (g_Mode ==0) {
    language_say(UserIndex,g_MSG_DISABLED,print_type:print_console);
  }
  else if (g_Mode == 1) {
    language_say(UserIndex,g_MSG_ENABLED,print_type:print_console);
  }
 
  language_sayf(UserIndex,g_MSG_DEFAULT,print_type:print_console,0,0,0,0,g_DefaultLanguage);
 
  /* TODO: Report on player's languages */
  return PLUGIN_HANDLED;
}
 
/*
 *********************************************************
 *         MENU SELECTION ON CONNECT FUNCTIONS           *
 *********************************************************
*/
 
public plugin_connect(HLUserName, HLIP, UserIndex) {
  if (g_Registered ==0) {
    return PLUGIN_FAILURE;
  }
 
  new Name[MAX_NAME_LENGTH];
  safe_convert(HLUserName, Name, MAX_NAME_LENGTH);
  get_userorigin(Name,g_ConnectX[UserIndex],g_ConnectY[UserIndex],g_ConnectZ[UserIndex]);
 
  g_UserInMenu[UserIndex]=0;
  g_Languages[UserIndex-1]=64;
  return PLUGIN_CONTINUE;
}
 
public plugin_disconnect(HLUserName, UserIndex) {
  if (g_Registered ==0) {
    return PLUGIN_FAILURE;
  }
  set_timer("writeauthcache",3,1,"");
  return PLUGIN_CONTINUE;
}
 
 
 
 
 
public check_languages() {
  new c = maxplayercount();
  new Name[MAX_NAME_LENGTH];
  new dummy;
  new i;
  new wonid;
  new team;
  new dead;
  new AuthID[MAX_AUTHID_LENGTH];
  new x;
  new y;
  new z;
 
  new delay=15;
 
  for(i=1;i<=c;i++) {
    /* Check if language is known */
    if (g_Languages[i-1]!=64) { continue; }
 
    if (playerinfo(i,Name,MAX_NAME_LENGTH,dummy,wonid,team,dead,AuthID)) {
 
      /* Check player isn't a bot */
      if (!ishuman(AuthID)) { continue; }
 
      /* Check if language is known from client setinfo */
      g_Languages[i-1]=checkinfo(Name);
      if (g_Languages[i-1]!=64) {
        plugin_exec("language_update",g_Languages);
        continue;
      }
 
      /* Check if language is known from last map */
      g_Languages[i-1]=checkauthcache(AuthID);
      if (g_Languages[i-1]!=64) {
        plugin_exec("language_update",g_Languages);
        continue;
      }
 
      /* Check if player has picked a team and is not still at connection co-ordinates - i.e. has spawned. */
      get_userorigin(Name,x,y,z);
      if ((x!=g_ConnectX[i]) || (y!=g_ConnectY[i]) || (z!=g_ConnectZ[i])) {
        if ((team > 0) && (team < 5)) {
          /* Yes, display the menu */
          display_menu(i,Name);
        }
        else {
          /* Has spawned but hasn't chosen team. Switch to fast checking mode
           * so menu appears before they start buying */
          delay=2;
        }
      }
    }
  }
 
  g_Timer = set_timer("check_languages",delay,1,"");
}
 
display_menu(Index,Name[]) {
 
  new act_keys=7;
  new MenuText[MAX_MENU_LENGTH];
 
  snprintf(MenuText, MAX_MENU_LENGTH, "Choose your language:^n^n1. English^n2. Francais^n3. Deutsch^n");
  menu(Name,MenuText,act_keys);
 
  g_UserInMenu[Index]=1;
  return 0;
}
 
 
public menucancel(HLCommand,HLData,HLUserName,UserIndex) {
  if (g_UserInMenu[UserIndex]) {
    log("Menu cancelled");
    if (g_Timer==0) {
      g_Timer=set_timer("check_languages",RECHECK_TIME,5,"");
    }
    g_UserInMenu[UserIndex]=0;
  }
  return PLUGIN_CONTINUE;
}
 
public menuselect(HLCommand,HLData,HLUserName,UserIndex){
  if (g_Registered ==0) {
    return PLUGIN_FAILURE;
  }
 
 
  new Data[MAX_DATA_LENGTH];
  safe_convert(HLData,Data,MAX_DATA_LENGTH);
 
  new Name[MAX_DATA_LENGTH];
  safe_convert(HLUserName,Name,MAX_DATA_LENGTH);
 
  if (g_UserInMenu[UserIndex]==0) {
    return PLUGIN_CONTINUE;
  }
 
  g_UserInMenu[UserIndex]=0;
 
  new nLang = strtonum(Data);
  if ((nLang>0) && (nLang<4)) {
    g_Languages[UserIndex-1] = 64+nLang;
 
    new Msg[MAX_TEXT_LENGTH];
    snprintf(Msg,MAX_TEXT_LENGTH,"User %i %s has selected language %s",UserIndex,Name,Data);
    log(Msg);
 
 
    /* record for the next map */
    writeauthcache();
 
    /* tell other plugins that use language.inc about the change */
    plugin_exec("language_update",g_Languages);
  }
  else {
    plugin_message("WARNING: Language plugin recevied the result of another plugins menu.");
  }
 
  return PLUGIN_CONTINUE;
}
 
 
 
 
/*
 *********************************************************
 *                    SUPPORT FUNCTIONS                  *
 *********************************************************
*/
 
 
/*
 * Writes each players chosen language and WONID
 * to a cache file to all recovery on map change
 *
 */
public writeauthcache() {
 
  resetfile("languagecache.ini");
 
  new c = maxplayercount();
  new Name[MAX_NAME_LENGTH];
  new dummy;
  new i;
  new wonid;
  new team;
  new dead;
  new AuthID[MAX_AUTHID_LENGTH];
  new ln[MAX_TEXT_LENGTH];
 
  for(i=1;i<=c;i++) {
    if (playerinfo(i,Name,MAX_NAME_LENGTH,dummy,wonid,team,dead,AuthID)) {
      /* Don't want to record bots or lan players */
      if (wonid>0) {
        if (g_Languages[i-1]!=64) {
          snprintf(ln,MAX_TEXT_LENGTH,"%c%s",g_Languages[i-1],AuthID);
          writefile("languagecache.ini",ln);
        }
      }
    }
  }
 
}
 
/* Reads the woncache from the
 * last map into memory
 */
readauthcache() {
 
  new ReadCount=filesize("languagecache.ini",fsize_unit:lines)+1;
  if (ReadCount > MAX_PLAYERS) {
    ReadCount = MAX_PLAYERS;
  }
 
  new i;
  new buf[MAX_TEXT_LENGTH];
  for(i=0;i<ReadCount;i++) {
    readfile("languagecache.ini",buf,i,MAX_TEXT_LENGTH);
    if (strlen(buf)>1) {
      g_AuthLanguage[i]=buf[0];
      new j=1;
      while (buf[j]!=0) {
        buf[j-1]=buf[j];
        j++;
      }
      buf[j-1]=0;
      strcpy(g_AuthID[i],buf,MAX_AUTHID_LENGTH);
    }
  }
 
  return 1;
}
 
/* Searches the woncache for a player's language */
checkauthcache(AuthID[]) {
  new i=0;
 
  while (i<MAX_PLAYERS) {
    if (strcmp(g_AuthID[i],AuthID) == 0) {
      g_AuthID[i][0]=0; /* Only retrieve a cached value once */
      return g_AuthLanguage[i];
    }
    i++;
  }
  return 64;
}
 
checkinfo(Name[]) {
  new Info[20];
 
  if (get_userinfo(Name,"lang",Info,20)) {
    if (streq(Info,"english")) {
      return 65;
    }
    else if (streq(Info,"french") || streq(Info,"francais")) {
      return 66;
    }
    else if (streq(Info,"german") || streq(Info,"deutsch")) {
      return 67;
    }
  }
  return 64;
}