hwm_change_fraction

Change fraction/talent/build from any page in one click

As of 2018-11-26. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name          hwm_change_fraction
// @namespace     ужеЛежу
// @author        ужеЛежу
// @description   Change fraction/talent/build from any page in one click
// @version       4.0.9
// @encoding      utf-8
// @include       https://www.heroeswm.ru/*
// @include       https://www.lordswm.com/*
// @include       http://178.248.235.15/*
// @exclude       /^https{0,1}:\/\/(www\.(heroeswm\.ru|lordswm\.com)|178\.248\.235\.15)\/(login|war|cgame|frames|chat|chatonline|ch_box|chat_line|ticker|chatpost)\.php*/
// @exclude       https://www.heroeswm.ru/radio_files/*
// @exclude       https://www.heroeswm.ru/ticker.html*
// @exclude       https://www.lordswm.com/radio_files/*
// @exclude       https://www.lordswm.com/ticker.html*
// @exclude       http://178.248.235.15/radio_files/*
// @exclude       http://178.248.235.15/ticker.html*
// @exclude       */rightcol.php*
// @exclude       */ch_box.php*
// @exclude       */chat*
// @exclude       */ticker.html*
// @exclude       */frames*
// @exclude       */brd.php*
// @grant         GM_deleteValue
// @grant         GM_getValue
// @grant         GM_listValues
// @grant         GM_setValue
// ==/UserScript==

// CheckT:
// исправление @exclude; небольшой рефакторинг; var charArrowDown; проверка наличия SpanFractions
// замена localStorage на GM_getValue/GM_setValue
// previous name: [hwm]_change_fraction

(function(){
  var host = location.host;
  var url_host = 'https://' + host;

  var gm_prefix = "ctf#";   //префикс всех хранимых данных

  if(isLoggedOff())
    return;

  var currentPlayerId = getPlayerId();

  var loadingGif = " <img width=15 src='https://dcdn2.heroeswm.ru/i/loading.gif'>";
  var crossSpan = "<span style='cursor:pointer;background:#d33;color:white;padding:0 4 2 4;border-radius:3px;box-shadow:2px 2px 3px black;'><b>x</b></span>";
  var stateListOpen = 0;
  var divListFractions = false;
  var divListTalents = false;
  var currentFractionId = 0;
  var meFractionId = 0;

  // vars for change fraction/build
  var classId = 0;
  var talentUrl = false;
  var armyParams = false;
  var artsId = -1;

  var TYPE_FRACTION = 0;
  var TYPE_TALENT = 1;
  var TYPE_BUILD = 2;

  if(convertOptions())
    return;

  var useType = gm_get['useType'];
  if (!useType){
    useType = TYPE_FRACTION;
    gm_set['useType']=TYPE_FRACTION;
  }
  var colorBase = "#FFD871";
  var backgroundBase = "#6B6C6A";
  var buildArmy = -1;
  var buildTalent = -1;
  var buildArts = -1;
  var savedBuildId = -1;

  var fractions = createFractions();
  var mobNames = createMobNames();

  var talents = [];
  var arts = ['<i>Снять всё</i>'];
  var builds = [];

  if(findSpanFractionsPlace()){
    loadTalents();
    initListFractions();
    initListTalents();
  }

  return; // only functions below

  function $(id) {
    return document.getElementById(id);
  }

  function $$(val, begin, end) {
    var id = val.indexOf(begin);
    var temp = val.substr(id + begin.length);
    return temp.substr(0, temp.indexOf(end));
  }

  function xy(obj) {
      var x = 0;
      var y = 0;
      while (obj) {
          x += obj.offsetLeft;
          y += obj.offsetTop;
          obj = obj.offsetParent;
      }
      return {x: x, y: y};
  }

  function createXMLHttpReq(){
    var objXMLHttpReq;

    if (window.XMLHttpRequest){
      objXMLHttpReq = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
      // IE
      objXMLHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
    } else {
      alert('Can\'t create XMLHttpRequest!');
    }
    return objXMLHttpReq;
  }

  function send(method, url, params, afterSend) {
    var xmlHttp = createXMLHttpReq();
    xmlHttp.open(method, url, true);
    if (method == "POST")
      xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xmlHttp.overrideMimeType('text/plain; charset=windows-1251');
    xmlHttp.onreadystatechange = function(){afterSend(xmlHttp);};
    xmlHttp.send(params);
  }

  function afterSend(xmlHttp) {
    if (xmlHttp.readyState == 4) {
      if (xmlHttp.status == 200) {
        if (classId > -1) {
          send("POST", url_host + "/castle.php", "classid=" + classId, afterSend);
          classId = -1;
        } else if (talentUrl) {
          send("GET", talentUrl, null, afterSend);
          talentUrl = false;
        } else if (armyParams) {
          send("POST", url_host + "/army_apply.php", armyParams, afterSend);
          armyParams = false;
        } else if (artsId > -1) {
          var artsUri;
          if (artsId == 0)
            artsUri = "all_off=100";
          else
            artsUri = "all_on=" + artsId;
          send("GET", url_host + "/inventory.php?" + artsUri, null, afterSend);
          artsId = -1;
        } else {
          location.href = url_host + "/home.php";
        }
      }
    }
  }

  function editSpan(id) {
      return "<span id=editBuild_" + id + " style='cursor:pointer;border:1px solid #888;border-radius:3px;box-shadow:2px 2px 3px black;padding:0 2 1 2;'><img style='vertical-align:middle;' width=12 src='https://dcdn.heroeswm.ru/i/2repair_ico.gif'></span>";
  }

 function findSpanFractionsPlace() {
    var charArrowDown=String.fromCharCode(9660); //""
    var divs = document.getElementsByTagName("div");
    var m_tr;
    var m_td = false;
    for (var id_div in divs) {
      if (divs[id_div].id == "breadcrumbs" && divs[id_div].innerHTML.indexOf(charArrowDown) > -1) {
        m_tr = divs[id_div].parentNode.parentNode;
        m_td = m_tr.insertCell(-1);
        m_td.innerHTML = " | <span id=spanFractions></span>";
      }
    }

    if (!m_td) {
        var tables = document.getElementsByTagName("table");
        for (var id_table in tables) {
            var table = tables[id_table];
            if (table.innerHTML && table.innerHTML.indexOf('height="6px"') > -1) {
                table.innerHTML = "<tr><td><span id=spanFractions></span></td></tr>";
                break;
            }
        }
    }
    var spanFractions = $('spanFractions');

    if (!spanFractions || spanFractions == null) {
        var centers = document.getElementsByTagName("center");
        for (var id_center in centers) {
            var center = centers[id_center].innerHTML;
            if (center && center.indexOf("center>") == -1 && center.indexOf("<a ") > -1) {
                centers[id_center].innerHTML = center + " | <span id=spanFractions></span>";
                break;
            }
        }
    }

    spanFractions = $('spanFractions');
    if (!spanFractions || spanFractions == null)
      return false;

    spanFractions.innerHTML = "<a class=pi href='castle.php'>Фракции <font style='font-size:8px;'>"+charArrowDown+"</font></a>";
    spanFractions.addEventListener(
        "mouseenter",
        function () {
            if (stateListOpen == 0) {
                divListFractions.style.visibility = "visible";
                stateListOpen = 1;
            }
        }
    );
    spanFractions.addEventListener(
        "mouseleave",
        function () {
            stateListOpen = 2;
            setTimeout(hiddenListFractions, 100);
        }
    );
    return true;
  }

  function initListFractions() {
      divListFractions = document.createElement('div');
      document.body.appendChild(divListFractions);
      divListFractions.style.left = xy(spanFractions).x + "px";
      divListFractions.style.top = (xy(spanFractions).y + spanFractions.parentNode.clientHeight - 1) + "px";
      divListFractions.style.position = "absolute";
      divListFractions.style.background = backgroundBase;
      divListFractions.style.visibility = "hidden";
      divListFractions.style.border = "1px solid #5D413A";
      divListFractions.style.zIndex = 20;

      var innerInfo = "<table>";
      for (var fraction_id in fractions) {
          var fractionId = (fraction_id % 10) * 100 + Math.floor(fraction_id / 10);
  //        alert(fractionId + ":" + currentFractionId);
          var addStyle = fractionId == currentFractionId ? "border:1px dashed #ddd9cd;font-weight:bold" : "";
          innerInfo += "<tr style='color:" + colorBase + ";cursor:pointer'" +
              " id=frac_" + fraction_id + ">" +
              "<td style='background-color:#F5F3EA'><img src='https://dcdn.heroeswm.ru/i/f/r" + fractionId + ".png'></td>" +
              "<td id=td_frac_" + fraction_id + " style='color:" + colorBase + ";" + addStyle + "'>" + fractions[fraction_id] + "</td></tr>";
      }
      // use talents/builds
      innerInfo += "<tr><td colspan=2><table class=wb width=100%>" +
          "<tr><td class=wblight rowspan=3 width=50% align=center>Использовать:</td>" +
          "<td class=" + (useType == 0 ? "wblight" : "wbwhite") + "><input name=radio type=radio id=radio_0 " + (useType == 0 ? "checked=checked" : "") + "><label for=radio_0>Фракции</label></td></tr>" +
          "<tr><td class=" + (useType == 1 ? "wblight" : "wbwhite") + "><input name=radio type=radio id=radio_1 " + (useType == 1 ? "checked=checked" : "") + "><label for=radio_1>Навыки</label></td></tr>" +
          "<tr><td class=" + (useType == 2 ? "wblight" : "wbwhite") + "><input name=radio type=radio id=radio_2 " + (useType == 2 ? "checked=checked" : "") + "><label for=radio_2>Билды</label></td></tr>" +
          "<tr><td class=wbwhite colspan=2 align=center><input id=buildManager type=submit value='Билд-менеджер' " + (useType != 2 ? "disabled" : "") + "></td></tr>" +
          "</table></td></tr>";
      innerInfo += "</table>";
      divListFractions.innerHTML = innerInfo;
      for (var radioId = 0; radioId < 3; radioId++) {
          $('radio_' + radioId).onclick = function () {
              useType = this.id.split('_')[1];
              gm_set('useType', useType);
              $('buildManager').disabled = useType != TYPE_BUILD;
              $('radio_' + useType).parentNode.className = "wblight";
              $('radio_' + (useType+1)%3).parentNode.className = "wbwhite";
              $('radio_' + (useType+2)%3).parentNode.className = "wbwhite";
              loadTalents();
              initListTalents();
          };
      }
      $('buildManager').onclick = function () {
          buildArmy = -1;
          buildTalent = -1;
          buildArts = -1;
          var divPopup = document.createElement('div');
          divPopup.style.width = "100%";
          divPopup.style.minHeight = "100%";
          divPopup.style.position = "fixed";
          divPopup.style.top = "0px";
          divPopup.style.backgroundColor = "rgba(0,0,0,0.5)";
          divPopup.style.zIndex = 22;
          divPopup.addEventListener(
              "mouseup",
              function(e) {
                  var target = e.target || e.srcElement;
                  if (target == divPopup) {
                      document.body.removeChild(divPopup);
                      hiddenListFractions();
                  }
              }
          );
          document.body.appendChild(divPopup);

          var divBuildManager = document.createElement('div');
          divBuildManager.align = "center";
          divBuildManager.style.top = "0px";
          divBuildManager.style.margin = "50px auto 0px auto";
          divBuildManager.style.backgroundColor = backgroundBase;
          divBuildManager.style.width = "620px";
          divBuildManager.style.boxShadow = "10px 10px 10px #000";
          divBuildManager.style.zIndex = 23;
          divPopup.appendChild(divBuildManager);
          if (currentFractionId > 0)
              generateBuildContent(divBuildManager, divPopup, currentFractionId);
          else {
              var alertMessage = 'Невозможно определить текущую фракцию! Попробуйте создать навык, чтобы он отображался в "Быстрых ссылках"';
              var pattern = /\/i\/f\/r(\d+)\.png/;
              if (location.href == url_host + "/home.php") {
                  var match = document.body.innerHTML.match(pattern);
                  if (match) {
                      currentFractionId = match[1];
                      generateBuildContent(divBuildManager, divPopup, currentFractionId);
                  } else
                      alert(alertMessage);
              } else {
                  send("GET", url_host + "/home.php", null,
                      function() {
                          if (xmlHttp.readyState == 4) {
                              if (xmlHttp.status == 200) {
                                  var match = xmlHttp.responseText.match(pattern);
                                  if (match) {
                                      currentFractionId = match[1];
                                      generateBuildContent(divBuildManager, divPopup, currentFractionId);
                                  } else
                                      alert(alertMessage);
                              }
                          }
                      }
                  );
              }
          }

      };

      for (fraction_id in fractions) {
          $('frac_' + fraction_id).onclick = function () {
              var val = this.id.split("_")[1];
              var fraction = Math.floor(val / 10);
              classId = val % 10;
              $('td_frac_' + val).innerHTML += loadingGif;
              send("POST", url_host + "/castle.php", "fract=" + fraction, afterSend);
          };
      }

      divListFractions.addEventListener(
          "mouseenter",
          function () {
              stateListOpen = 1;
          }
      );

      divListFractions.addEventListener(
          "mouseleave",
          function (e) {
              stateListOpen = 2;
              if (!e) e = event;
              var x = e.clientX;
              var y = e.clientY;
              if (x < xy(divListFractions).x ||
                  x >= xy(divListFractions).x + divListFractions.clientWidth ||
                  y < xy(divListFractions).y ||
                  y >= xy(divListFractions).y + divListFractions.clientHeight)
                  setTimeout(hiddenListFractions, 100);
          }
      );
  }

  function initFractionsListeners() {
      for (var fractionId in fractions) {
          $('frac_' + fractionId).addEventListener(
              "mouseenter",
              function () {
                  var val = this.id.split("_")[1];
                  var fractionId = (val % 10) * 100 + Math.floor(val / 10);
                  var t, innerInfo;
                  meFractionId = fractionId;
                  if (useType == TYPE_TALENT) {
                      if (talents[fractionId]) {
                          innerInfo = "<table width=100%>";
                          for (var talentId in talents[fractionId]) {
                              t = talent(fractionId, talentId);
                              if (t != -1) {
                                  innerInfo += "<tr><td style='cursor:pointer;color:" + colorBase + "' " +
                                      "id=talent_" + talentId + " title='" + t[0] + "'>  " + t[1] + "</td></tr>";
                              }
                          }
                          divListTalents.innerHTML = innerInfo + "</table>";
                          divListTalents.style.visibility = "visible";
                          divListTalents.style.top = xy(this).y;
                          divListTalents.style.left = xy(this).x - divListTalents.clientWidth - 1;
                          // listeners
                          for (talentId in talents[fractionId]) {
                              if (!talents[fractionId][talentId])
                                  continue;
                              $('talent_' + talentId).addEventListener(
                                  "mouseenter",
                                  function () {
                                      this.style.background = "#757575";
                                      this.style.color = "white";
                                  }
                              );
                              $('talent_' + talentId).addEventListener(
                                  "mouseleave",
                                  function () {
                                      this.style.background = backgroundBase;
                                      this.style.color = colorBase;
                                  }
                              );
                              $('talent_' + talentId).onclick = function () {
                                  talentUrl = this.title;
                                  var val = this.title.match(/prace=(\d+)&/)[1];
                                  var fraction = val % 100;
                                  classId = Math.floor(val / 100);
                                  this.innerHTML += loadingGif;
                                  send("POST", url_host + "/castle.php", "fract=" + fraction, afterSend);
                              };
                          }
                      } else {
                          divListTalents.style.visibility = "hidden";
                      }
                  } else if (useType == TYPE_BUILD) {
                      val = this.id.split("_")[1];
                      fractionId = (val % 10) * 100 + Math.floor(val / 10);
                      if (builds[fractionId]) {
                          innerInfo = "<table width=100%>";
                          for (var buildId in builds[fractionId]) {
                              var b = builds[fractionId][buildId].split('|');
                              var buildName = b[0];
                              t = talent(fractionId, b[2]);
                              var a = b[3] == -1 ? "<без артов>" : arts[b[3]];
                              t = t == -1 ? "<без навыка>" : t[1];
                              b = b[1] == -1 ? "<без армии>" : b[1];
                              var title = b + " | " + t + " | " + a;
                              innerInfo += "<tr><td style='cursor:pointer;color:" + colorBase + "' " +
                                  "id=talent_" + buildId + " title='" + title + "'> " + buildName + "</td></tr>";
                          }
                          divListTalents.innerHTML = innerInfo + "</table>";
                          divListTalents.style.visibility = "visible";
                          divListTalents.style.top = xy(this).y;
                          divListTalents.style.left = xy(this).x - divListTalents.clientWidth - 1;
                          // listeners
                          for (buildId in builds[fractionId]) {
                              $('talent_' + buildId).addEventListener(
                                  "mouseenter",
                                  function () {
                                      this.style.background = "#757575";
                                      this.style.color = "white";
                                  }
                              );
                              $('talent_' + buildId).addEventListener(
                                  "mouseleave",
                                  function () {
                                      this.style.background = backgroundBase;
                                      this.style.color = colorBase;
                                  }
                              );
                              $('talent_' + buildId).onclick = function () {
                                  var buildId = this.id.split("_")[1];
                                  var b = builds[meFractionId][buildId].split('|');
                                  talentUrl = talent(meFractionId, b[2])[0];
                                  var fraction = meFractionId % 100;
                                  classId = Math.floor(meFractionId / 100);
                                  var a = b[1].split('+');
                                  armyParams = "";
                                  for (var i in a)
                                      armyParams += "&countv" + (i*1 + 1) + "=" + a[i];
                                  armyParams = armyParams.substr(1);
                                  artsId = b[3];
                                  this.innerHTML += loadingGif;
                                  send("POST", url_host + "/castle.php", "fract=" + fraction, afterSend);
                              };
                          }
                      } else {
                          divListTalents.style.visibility = "hidden";
                      }

                  }
                  this.style.background = "#757575";
                  $('td_' + this.id).style.color = "white";
              }
          );
          $('frac_' + fractionId).addEventListener(
              "mouseleave",
              function () {
                  this.style.background = backgroundBase;
                  $('td_' + this.id).style.color = colorBase;
              }
          );
      }
  }

  function initListTalents() {
      if (useType == TYPE_TALENT || useType == TYPE_BUILD) {
          if (!divListTalents) {
              divListTalents = document.createElement('div');
              document.body.appendChild(divListTalents);
              divListTalents.style.position = "absolute";
              divListTalents.style.background = backgroundBase;
              divListTalents.style.zIndex = 21;
              divListTalents.style.border = "1px solid #5D413A";
              divListTalents.style.visibility = "hidden";
              divListTalents.style.width = "150";
              divListTalents.addEventListener(
                  "mouseenter",
                  function () {
                      stateListOpen = 3;
                  }
              );
              divListTalents.addEventListener(
                  "mouseleave",
                  function (e) {
                      stateListOpen = 2;
                      if (!e) e = event;
                      var x = e.clientX;
                      var y = e.clientY;
                      if (x >= xy(divListFractions).x + divListFractions.clientWidth ||
                          y >= xy(divListFractions).y + divListFractions.clientHeight ||
                          x < xy(divListFractions).x)
                          hiddenListFractions();
                  }
              );
          }
          if (!currentPlayerId) {
              divListFractions.style.color = "red";
              divListFractions.style.background = "white";
              divListFractions.innerHTML = "Невозможно определить ID персонажа!<br>Перейдите на другую страницу!";
          } else {
              initFractionsListeners();
          }
      } else {
          talents = [];
          if (divListTalents)
              divListTalents.style.visibility = "hidden";
          initFractionsListeners();
      }
  }

  function loadTalents() {
      var skillwheels = document.getElementsByTagName("a");
      var prace = 0;
      var load = false;
      for (var id_a in skillwheels) {
          var href = skillwheels[id_a].href;
          if (href && href.indexOf("skillwheel.php?setuserperk=") > -1) {
              prace = href.split("prace=")[1];
              prace = prace.substr(0, prace.indexOf('&'));
              var buildid = href.split("buildid=")[1];
              if (!talents[prace]) {
                  talents[prace] = [];
                  load = true;
              }
              if (load)
                  talents[prace][buildid] = href + "|" + skillwheels[id_a].innerHTML;
          }
      }
      currentFractionId = prace;
      if (prace > 0)
          gm_set(currentPlayerId + '#race#' + prace, talents[prace]);
      var keys = GM_listValues();
      for (var localKey in keys) {
          if (localKey.indexOf('cf#' + currentPlayerId + '#race#') == 0)
              talents[localKey.split("#")[3]] = GM_getValue(localKey).split(",");
      }
      loadArts();
      loadBuilds();
  }

  function loadArts() {
    for (var i = 0; i < 11; i++) {
      var art = gm_get(currentPlayerId + '#arts#' + i);
      if (art)
        arts[i] = art;
    }
  }

  function loadBuilds() {
    var keys = GM_listValues();
    for (var localKey in keys) {
        if (localKey.indexOf('cf#' + currentPlayerId + '#build#') == 0)
            builds[localKey.split("#")[3]] = GM_getValue(localKey).split(",");
    }
  }

  function saveBuild() {
      if (!builds[currentFractionId])
          builds[currentFractionId] = [];
      var buildId = savedBuildId > -1 ? savedBuildId : builds[currentFractionId].length;
      savedBuildId = -1;
      builds[currentFractionId][buildId] =
          $('buildName').value + '|' + buildArmy + '|' + buildTalent + '|' + buildArts;
      gm_set(currentPlayerId + '#build#' + currentFractionId, builds[currentFractionId]);
      fillBuilds(currentFractionId);
  }

  function deleteBuild(buildId) {
      builds[currentFractionId].splice(buildId, 1);
      if (builds[currentFractionId].length > 0)
          gm_set(currentPlayerId + '#build#' + currentFractionId, builds[currentFractionId]);
      else
          gm_del(currentPlayerId + '#build#' + currentFractionId);
      fillBuilds(currentFractionId);
  }

  function hiddenListFractions() {
      if (stateListOpen == 2) {
          divListFractions.style.visibility = "hidden";
          if (divListTalents)
              divListTalents.style.visibility = "hidden";
          stateListOpen = 0;
      }
  }

  function generateBuildContent(div, divPopup, fractionId) {
      var contentAll = "<table class=wb width=670 cellpadding=0 cellspacing=0 style='height:100%;background:#FFF'>" +
          "<tr class=wblight><td align=center style='padding:4;' colspan=2>" +
          "<table width=100%><tr align=center>" +
          "<td><b>Текущая фракция:</b> <img width=15 height=15 border=0 align=absmiddle src='https://dcdn.heroeswm.ru/i/r" + fractionId + ".gif'></td>" +
          "<td width=25 id=crossClose>" + crossSpan + "</td>" +
          "</tr></table></td></tr>";

      // all builds
      contentAll += "<tr><td style='padding:4;' rowspan=2 width=250 valign=top>" +
          "<table class=wb style='height:100%' width=100% cellpadding=0 cellspacing=0 id=listBuilds>" +
          "<tr><td class=wblight style='padding:4;height:5;' colspan=4><b>Сохранённые билды:</b></td></tr>" +
          "<tr><td class=wbwhite style='padding:4;' valign=top>" +
          "<span style='color:red'><b>Нет билдов!</b></span>" +
          "</td></tr>" +
          "</table>" +
          "</td>";


      // army
      contentAll += "" +
          "<td style='padding:4;'><table class=wb width=100% cellpadding=0 cellspacing=0>" +
          "<tr><td class=wblight style='padding:4;' colspan=7><b>Наберите армию:</b></td></tr>" +
          "<tr>";
      var contentValues = "<tr align=center>";
      for (var mobId in mobNames[fractionId]) {
          contentAll += "<td class=wblight><img src='https://dcdn2.heroeswm.ru/i/mon_pic_png/2x" + mobNames[fractionId][mobId] + "ani.png' width=60 height=50 border=0></td>";
          contentValues += "<td class=wbwhite style='padding:4;'><input type=text size=1 maxlength=3 style='border:1px solid #777' id=countArmy_" + mobId  + "></td>";
      }
      contentAll += "</tr>" + contentValues + "</tr>";
      contentAll += "</table></td></tr>";

      // talents & inventory
      contentAll += "<tr>" +
          "<td style='padding:4;'><table class=wb width=100% cellpadding=0 cellspacing=0>" +
          "<tr>" +
          "<td class=wblight style='padding:4;'><b>Выберите навык:</b></td>" +
          "<td class=wblight style='padding:4;'><b>Выберите комплект артов:</b></td>" +
          "</tr>" +
          "<tr><td class=wbwhite style='padding:4;'>";
      if (talents[fractionId]) {
          for (var talentId in talents[fractionId]) {
              if (talents[fractionId][talentId]) {
                  var del = talents[fractionId][talentId].indexOf("|");
                  var skillHref = talents[fractionId][talentId].substr(0, del);
                  var skillName = talents[fractionId][talentId].substr(del + 1);
                  contentAll += "<input type=radio name=radioTalent id=radioTalent_" + talentId + " title='" +
                      skillName + "'><label for=radioTalent_" + talentId + ">" + skillName + "</label><br>";
              }
          }
      } else {
          contentAll += "<span><b style='color:red'>Нет навыков!</b></span>";
      }
      contentAll += "</td>" +
          "<td class=wbwhite style='padding:4;'>" +
          "<span id=setArts><b style='color:red'>Нет комплектов!</b></span>" +
          "<br><input type=submit id=updateArts value='Обновить комплекты'>" +
          "</td></tr>";
      contentAll += "</table></td></tr>";

      contentAll +=
          "<tr align=center>" +
          "<td style='padding:4;'>" +
          "<table class=wb style='height:100%' width=100% cellpadding=0 cellspacing=0 style='background:#FFF'>" +
          "<tr><td class=wblight style='padding:4;height:5;' colspan=4><b>Экспорт/импорт билдов:</b></td></tr>" +
          "<tr align=center><td class=wbwhite><input type=submit id=exportBuilds value='Экспорт в гвд-блокнотъ ->'>" +
          "<br><br><input type=submit id=importBuilds value='<- Импорт из гвд-блокнота'></td></tr>" +
          "</table>" +
          "</td>";
      // build
      contentAll +=
          //"<tr align=center>" +
          "<td style='padding:4;' colspan=1><table class=wb width=100% cellpadding=0 cellspacing=0 style='background:#FFF'>" +
          "<tr class=wblight><td style='padding:4;' colspan=2><span id=buildCap style='color:red'><b>Билд:</b></span></td></tr>" +
          "<tr class=wbwhite><td style='padding:4;' colspan=2 align=center><table width=80%>" +
          "<tr><td style='padding:2;' width=25%>Имя:</td><td><input type=text maxlength=32 size=16 style='border:1px solid #777' id=buildName></td></tr>" +
          "<tr><td style='padding:2;'>Армия:</td><td id=buildArmy><i>без армии</i></td></tr>" +
          "<tr><td style='padding:2;'>Навык:</td><td id=buildTalent><i>без навыка</i></td></tr>" +
          "<tr><td style='padding:2;'>Арты:</td><td id=buildArts><i>без артов</i></td></tr>" +
          "</table></td></tr>" +
          "<tr class=wbwhite align=center>" +
          "<td style='padding:4;'width=50%><input type=submit id=saveBuild disabled value='Сохранить билд'></td>" +
          "<td style='padding:4;'width=50%><input type=submit id=cancelBuild value='Очистить форму'></td>" +
          "</table></td></tr>";
      // end
      contentAll += "</table>";
      div.innerHTML = contentAll;
      fillSetArts();
      fillBuilds(fractionId);

      // listeners
      $('crossClose').onclick = function() {
          document.body.removeChild(divPopup);
          hiddenListFractions();
      };
      var radioTalents = document.getElementsByName('radioTalent');
      for (var i in radioTalents) {
          if (radioTalents[i].id) {
              radioTalents[i].onclick = function() {
                  var talentId = this.id.split('_')[1];
                  $('buildTalent').innerHTML = "<b>" + this.title + "</b>";
                  buildTalent = talentId;
                  checkBuild();
              }
          }
      }
      for (var j = 0; j < 7; i++) {
          $('countArmy_' + j).onkeypress = function(e) {
              if (this.value == '0') this.value = '';
              e = e || event;
              if (e.ctrlKey || e.altKey || e.metaKey) return;
              var chr = getChar(e);
              if (chr == null) return;
              if (chr < '0' || chr > '9') {
                  return false;
              }
          }
          $('countArmy_' + i).onkeyup = function(e) {
              generateBuildArmy();
              $('buildArmy').innerHTML = "<b>" + buildArmy + "</b>";
              checkBuild();
          }
      }
      $('updateArts').onclick = function() {
          $('setArts').innerHTML += loadingGif;
          send("GET", url_host + "/inventory.php", null,
              function() {
                  if (xmlHttp.readyState == 4) {
                      if (xmlHttp.status == 200) {
                          var text = xmlHttp.responseText.split("<b>1.</b>");
                          if (text.length > 1) {
                              arts = ["<i>Снять всё</i>"];
                              var s = text[1].split("?all_on=");
                              for (var i = 1; i < s.length; i++) {
                                  var setId = s[i].split("&")[0];
                                  var setName = s[i].match(/>(.*)<\/a>/)[1];
                                  arts[setId] = setName;
                                  gm_set(currentPlayerId + '#arts#' + setId, setName);
                              }
                              fillSetArts();
                          } else {
                              $('setArts').innerHTML = "<b style='color:red'>Недоступна страница<br> инвентаря, попробуйте<br> позже!</b>";
                          }
                      }
                  }
              }
          );
      };
      $('buildName').onkeyup = function() {
          checkBuild();
      };
      $('saveBuild').onclick = function() {
          saveBuild();
      };
      $('cancelBuild').onclick = function() {
          clearForm();
      };
      $('exportBuilds').onclick = function() {
          exportBuilds();
      };
      $('importBuilds').onclick = function() {
          importBuilds();
      };
  }

  function getChar(event) {
      var which = event.which;    // other
      if (which == null) which = event.keyCode;   // IE
      if (which != 0) {
          if (which < 32) return null;
          return String.fromCharCode(which);
      }
      return null;
  }

  function generateBuildArmy() {
      buildArmy = "";
      for (var i = 0; i < 7; i++) {
          var intValue = parseInt($('countArmy_' + i).value);
          if (!intValue) intValue = 0;
          buildArmy += intValue;
          if (i < 6) buildArmy += '+';
      }
  }

  function fillSetArts() {
      var innerText = "";
      if (arts.length == 0) return;
      for (var i in arts) {
          if (i > 0) innerText += "<br>";
          innerText += "<input type=radio name=radioArts id=radioArts_" + i + ">" +
              "<label for=radioArts_" + i + ">" + (i > 0 ? (i + ". ") : "") +
              arts[i] + "</label>";
      }
      $('setArts').innerHTML = innerText;
      // listeners
      var radioArts = document.getElementsByName('radioArts');
      for (var j in radioArts) {
          if (radioArts[j].id) {
              radioArts[j].onclick = function() {
                  var setId = this.id.split('_')[1];
                  $('buildArts').innerHTML = "<b>" + setId + ". " + arts[setId] + "</b>";
                  buildArts = setId;
                  checkBuild();
              }
          }
      }
  }

  function fillBuilds(fractionId) {
      var innerText = "<tr><td class=wblight style='padding:4;height:5;' colspan=4><b>Сохранённые билды:</b></td></tr>";
      //alert(builds[fractionId] + ": " + builds[fractionId].length);
      if (!builds[fractionId] || builds[fractionId].length == 0) {
          innerText += "<tr><td class=wbwhite style='padding:4;' valign=top>" +
              "<span style='color:red'><b>Нет билдов!</b></span>" +
              "</td></tr>";
      } else {
          for (var buildId in builds[fractionId]) {
              var b = builds[fractionId][buildId].split('|');
              var buildName = b[0];
              var t = talent(fractionId, b[2]);
              var a = b[3] == -1 ? "<без артов>" : arts[b[3]];
              t = t == -1 ? "<без навыка>" : t[1];
              b = b[1] == -1 ? "<без армии>" : b[1];
              var title = b + " | " + t + " | " + a;
              innerText += "<tr class=wbwhite>" +
                  "<td width=10  style='padding:4;height:5;'>" + (buildId*1 + 1) + ".</td>" +
                  "<td title='" + title + "'><b>" + buildName + "</b></td>" +
                  "<td align=center width=25 title='Редактировать билд'>" + editSpan(buildId) + "</td>" +
                  "<td align=center width=25 title='Удалить билд' id=deleteBuild_" + buildId + ">" + crossSpan + "</td>" +
                  "</tr>";
          }
          innerText += "<tr class=wblight><td colspan=4>&nbsp;</td></tr>";
      }
      $('listBuilds').innerHTML = innerText;
      // listeners
      for (var i in builds[fractionId]) {
          $('deleteBuild_' + i).onclick = function() {
              var buildId = this.id.split('_')[1];
              if (confirm("Вы действительно хотите удалить этот билд?"))
                  deleteBuild(buildId);
          };
          $('editBuild_' + i).onclick = function() {
              var buildId = this.id.split('_')[1];
              loadBuild(buildId);
          }
      }
  }

  function checkBuild() {
      if ($('buildName').value != "") {
          $('saveBuild').disabled = false;
          $('buildCap').style.color = "green";
      } else {
          $('saveBuild').disabled = true;
          $('buildCap').style.color = "red";
      }
  }

  function talent(fractionId, talentId) {
      var talent = talents[fractionId][talentId];
      if (talent) {
          var i = talent.indexOf("|");
          return [talent.substr(0, i), talent.substr(i + 1)];
      } else {
          return -1;
      }
  }

  function loadBuild(buildId) {
      savedBuildId = buildId;
      var fractionId = currentFractionId;
      fillBuilds(fractionId);
      var b = builds[fractionId][buildId].split('|');
      var buildName = b[0];
      var t = talent(fractionId, b[2]);
      if (t == -1) {
          buildTalent = -1;
          t = "<i>без навыка</i>";
      } else {
          buildTalent = t[0].split("buildid=")[1];
          $('radioTalent_' + buildTalent).checked = true;
          t = "<b>" + t[1] + "</b>";
      }
      var a;
      if (b[3] == -1) {
          buildArts = -1;
          a = "<i>без артов</i>";
      } else {
          buildArts = b[3];
          $('radioArts_' + buildArts).checked = true;
          a = "<b>" + arts[b[3]] + "</b>";
      }
      if (b[1] == -1) {
          buildArmy = -1;
          b = "<i>без армии</i>";
          for (var i = 0; i < 7; i++)
              $('countArmy_' + i).value = "";
      } else {
          buildArmy = b[1];
          var army = b[1].split('+');
          for (var j in army)
              $('countArmy_' + j).value = army[i];
          b = "<b>" + b[1] + "</b>";
      }
      $('editBuild_' + buildId).style.border = "1px solid #F00";
      $('editBuild_' + buildId).style.background = "#FCC";
      $('buildName').value = buildName;
      $('buildArmy').innerHTML = b;
      $('buildTalent').innerHTML = t;
      $('buildArts').innerHTML = a;
      checkBuild();
  }

  function clearForm() {
      fillBuilds(currentFractionId);
      $('radioArts_' + buildArts).checked = false;
      $('radioTalent_' + buildTalent).checked = false;
      savedBuildId = -1;
      buildArmy = -1;
      buildArts = -1;
      buildTalent = -1;
      for (var i = 0; i < 7; i++)
          $('countArmy_' + i).value = "";
      $('buildName').value = "";
      $('buildArmy').innerHTML = "<i>без армии</i>";
      $('buildTalent').innerHTML = "<i>без навыка</i>";
      $('buildArts').innerHTML = "<i>без артов</i>";
      checkBuild();
  }

  function exportBuilds() {
      send("GET", url_host + "/sms.php?notebook=1", null,
          function() {
              if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                  var maxLength = 2990;
                  var html = document.createElement('html');
                  html.innerHTML = xmlHttp.responseText;
                  var noteText = html.getElementsByTagName('textarea')[0].innerHTML;
                  var exportContent = "\n[exb]";
                  for (var fractionId in builds)
                      exportContent += fractionId + ";" + builds[fractionId] + "^";
                  exportContent += "[/exb]";
                  var endNoteText = noteText.split("[/exb]")[1] || "";
                  noteText = noteText.split("\n[exb]")[0] + endNoteText;
                  var dLength = maxLength - noteText.length - exportContent.length;
                  if (dLength < 0) {
                      alert("Ошибка! Не хватает " + -dLength + " символа(ов) для хранения в блокноте! (макс. = " + maxLength + ")");
                  } else {
                      if (confirm("Вы действительно хотите сохранить билды в гвд-блокнот?\n(данные в блокноте могут измениться)")) {
                          var content = urlEncode(noteText + exportContent);
                          send("POST", url_host + "/sms.php", "action=savenotebook&data=" + content,
                              function() {
                                  if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                                      alert("Билды сохранены в блокнот!");
                                  }
                              }
                          );
                      }
                  }
              }
          }
      );
  }

  function importBuilds() {
      if (confirm("Вы действительно хотите импортировать билды?\n(текущие билды могут измениться/удалиться)")) {
          send("GET", url_host + "/sms.php?notebook=1", null,
              function () {
                  if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                      var html = document.createElement('html');
                      html.innerHTML = xmlHttp.responseText;
                      var noteText = html.getElementsByTagName('textarea')[0].innerHTML;
                      var importContent = $$(noteText, "\n[exb]", "[/exb]");
                      var blds = importContent.split("^");
                      var x = "";
                      for (var i = 0; i < blds.length - 1; i++) {
                          var c = blds[i].split(";");
                          builds[c[0]] = c[1].split(",");
                          gm_set(currentPlayerId + '#build#' + c[0], builds[c[0]]);
                      }
                      alert("Билды импортированы!");
                      fillBuilds(currentFractionId);
                  }
              }
          );
      }
  }

  function urlEncode(s) {
      var r = "";
      for (var i = 0; i < s.length; i++) {
          var c = s.charCodeAt(i);
          if (c > 127) {
              if (c > 1024) {
                  if (c == 1025)
                      c = 1016;
                  else if (c == 1105)
                      c = 1032;
                  r += "%" + (c - 848).toString(16);
              }
          } else {
              if (c == 43)
                  r += "%2b";
              else
                  r += s.charAt(i);
          }
      }
      return r;
  }

  function convertOptions(){
    if(!GM_load_bool_from_num( gm_prefix+"converted")){
      var debug='';
      GM_save_num_from_bool( gm_prefix+"converted", true);
      for (var localKey in localStorage) {
        if (localKey.indexOf('cf#') == 0)
          debug += convert_option(localKey);
      }
      document.body.innerHTML = debug;
      return true;
    } else {
      return false;
    }
  }

  function convert_option(key){
    var val = localStorage[key];
    if(val)
      gm_set(key.substring(3), val);
    localStorage[key] = null;
    delete localStorage[key];
    return '['+key+':'+val+'] -> ['+gm_prefix+key.substring(3)+':'+val+']<br/>';
  }

  function isLoggedOff(){
    return location.pathname == '/';
  }

  function getI(xpath,elem){return document.evaluate(xpath,(elem?elem:document),null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);}

  function getPlayerId(){
    var hunter_ref = getI("//a[contains(@href, 'pl_hunter_stat')]");
      //min 2 для home; min 1 для остальных - если включены выпадающие вкладки
      //min 1 для home; min 0 для остальных - если отключены выпадающие вкладки
    if ( !hunter_ref || hunter_ref.snapshotLength == 0 || (hunter_ref.snapshotLength == 1 && location.pathname == '/home.php') ) {
        //отключены вкладки или разлогин
      var ids=/pl_id=(\d+)/.exec(document.cookie);
      return ids ? ids[1] : 'unknown';
    } else {
      return hunter_ref.snapshotItem(0).href.split('?id=')[1];
    }
  }

  function createMobNames(){
    var mobNames = [];
    mobNames[1] = ['conscript','marksman','swordman'/*squire*/,'impergriffin','inquisitor','paladin','archangel'];
    mobNames[101] = ['brute','crossbowman'/*crossman*/,'vindicator','battlegriffon','zealot','champion','seraph2'];
    mobNames[2] = ['sceletonarcher'/*skeletonarcher*/,'plaguezombie','spectre','vampirelord','archlich','wraith','spectraldragon'];
    mobNames[102] = ['sceletonwar','rotzombie','poltergeist','vampireprince','masterlich','banshee','ghostdragon'];
    mobNames[3] = ['mastergremlin','obsgargoly','steelgolem','archmage','djinn_sultan','rakshasa_raja','titan'];
    mobNames[103] = ['saboteurgremlin', 'elgargoly','magneticgolem','battlemage','djinn_vizier','rakshasa_kshatra', 'stormtitan'];
    mobNames[4] = ['sprite', 'bladedancer'/*wardancer*/,'hunterelf'/*masterhunter*/,'ddeld'/*druideld*/,'silverunicorn','ancienent','emeralddragon'];
    mobNames[104] = ['dryad_'/*dryad*/,'winddancer'/*wdancer*/,'arcaneelf','ddhigh','pristineunicorn','savageent','crystaldragon'];
    mobNames[5] = ['hobgoblin','hobwolfrider'/*wolfraider*/,'orcchief','ogremagi','thunderbird','cyclopking','abehemoth'/*ancientbehemoth*/];
    mobNames[105] = ['goblinarcher','boarrider','orcrubak','ogrebrutal','firebird_'/*firebird*/,'cyclopod_'/*cyclopod*/,'dbehemoth'];
    mobNames[205] = ['goblinmag','boarrider','orcshaman','ogremagi','darkbird','cyclopod_'/*cyclopod*/,'dbehemoth'];
    mobNames[6] = ['assasin'/*assassin*/,'fury','minotaurguard_'/*minotaurguard*/,'grimrider','deephydra','matriarch','blackdragon'];
    mobNames[106] = ['stalker','bloodsister','taskmaster','briskrider','foulhydra','mistress','reddragon'];
    mobNames[7] = ['familiar','fdemon'/*hornedoverseer*/,'cerberus','succubusm'/*succubusmis*/,'stallion','pitlord_'/*pitlord*/,'archdevil'];
    mobNames[107] = ['vermin','jdemon','firehound'/*hotdog*/,'seducer','hellstallion'/*hellkon*/,'pitspawn'/*pity*/,'archdemon'];
    mobNames[8] = ['shieldguard','skirmesher','blackbearrider','berserker','runepatriarch','thunderlord','magmadragon'];
    mobNames[9] = ['trapper','ncentaur','mauler','sdaughter','executioner','foulwyvern','untamedcyc'];
    return mobNames;
  }

  function createFractions(){
    var fractions = [];
    fractions[10] = "Рыцарь";
    fractions[11] = "Рыцарь света";
    fractions[20] = "Некромант";
    fractions[21] = "Некромант - повелитель смерти";
    fractions[30] = "Маг";
    fractions[31] = "Маг-разрушитель";
    fractions[40] = "Эльф";
    fractions[41] = "Эльф-заклинатель";
    fractions[50] = "Варвар";
    fractions[51] = "Варвар крови";
    fractions[52] = "Варвар-шаман";
    fractions[60] = "Темный эльф";
    fractions[61] = "Темный эльф-укротитель";
    fractions[70] = "Демон";
    fractions[71] = "Демон тьмы";
    fractions[80] = "Гном";
    fractions[90] = "Степной варвар";
    return fractions;
  }

  function initGm(){
    if (!this.GM_getValue || (this.GM_getValue.toString && this.GM_getValue.toString().indexOf("not supported")>-1)) {
      this.GM_getValue=function (key,def) {
        return localStorage[key] || def;
      };
      this.GM_setValue=function (key,value) {
        return localStorage[key]=value;
      };
      this.GM_deleteValue=function (key) {
        return delete localStorage[key];
      };
    }
    if (!this.GM_listValues || (this.GM_listValues.toString && this.GM_listValues.toString().indexOf("not supported")>-1)) {
      this.GM_listValues=function () {
        var keys=[];
        for (var key in localStorage){
          keys.push(key);
        }
        return keys;
      }
    }
  }

  // 1 -> true; otherwise false
  function GM_load_bool_from_num(key){
    var val = Number(GM_getValue(key, 0));
    return isNaN(val) ? false : val==1;
  }

  // true -> 1; otherwise 0
  function GM_save_num_from_bool(key, val){
    GM_setValue(key, val ? 1 : 0);
  }

  function gm_get(key){
    return GM_getValue(gm_prefix+key);
  }

  function gm_set(key, val){
    return GM_setValue(gm_prefix+key, val);
  }

  function gm_del(key){
    return GM_deleteValue(gm_prefix+key);
  }

  function gm_list(){
    var keys = GM_listValues();
    var filtered = [];
    for ( var i = 0, len = keys.length; i < len; i++ ) {
      var key = keys[i];
      if(key.indexOf(gm_prefix) == 0)
        filtered.push(key);
    }
    return filtered;
  }

})();