From f25498d4d07fd400068c182bc94d21cea138054f Mon Sep 17 00:00:00 2001 From: Sarjuuk Date: Thu, 22 Mar 2018 15:13:12 +0100 Subject: [PATCH] Profiler/Gearscore * implement gearscore calculation im sad and i hate myself --- includes/types/item.class.php | 39 ++++- includes/types/spell.class.php | 22 +-- includes/utilities.php | 216 ++++++++++++++++++++++++++ setup/tools/filegen/enchants.func.php | 23 ++- setup/tools/filegen/gems.func.php | 10 +- static/js/Summary.js | 4 +- static/js/basic.js | 20 ++- static/js/global.js | 34 +++- static/js/home.js | 4 +- static/js/locale_dede.js | 1 + static/js/locale_enus.js | 1 + static/js/locale_eses.js | 1 + static/js/locale_frfr.js | 1 + static/js/locale_ruru.js | 1 + 14 files changed, 342 insertions(+), 35 deletions(-) diff --git a/includes/types/item.class.php b/includes/types/item.class.php index 584cdd63..252f54fc 100644 --- a/includes/types/item.class.php +++ b/includes/types/item.class.php @@ -1110,7 +1110,7 @@ class ItemList extends BaseType return $x; } - private function getRandEnchantForItem($randId) + public function getRandEnchantForItem($randId) { // is it available for this item? .. does it even exist?! if (empty($this->enhanceR)) @@ -1245,7 +1245,7 @@ class ItemList extends BaseType foreach ($this->json as $item => $json) foreach ($json as $k => $v) - if (!$v && !in_array($k, ['classs', 'subclass', 'quality', 'side'])) + if (!$v && !in_array($k, ['classs', 'subclass', 'quality', 'side', 'gearscore'])) unset($this->json[$item][$k]); } @@ -1554,6 +1554,34 @@ class ItemList extends BaseType } } + public function getScoreTotal($class = 0, $spec = [], $mhItem = 0, $ohItem = 0) + { + if (!$class || !$spec) + return array_sum(array_column($this->json, 'gearscore')); + + $score = 0.0; + $mh = $oh = []; + + foreach ($this->json as $j) + { + if ($j['id'] == $mhItem) + $mh = $j; + else if ($j['id'] == $ohItem) + $oh = $j; + else if ($j['gearscore']) + { + if ($j['slot'] == INVTYPE_RELIC) + $score += 20; + + $score += round($j['gearscore']); + } + } + + $score += array_sum(Util::fixWeaponScores($class, $spec, $mh, $oh)); + + return $score; + } + private function initJsonStats() { $json = array( @@ -1622,9 +1650,14 @@ class ItemList extends BaseType if ($this->curTpl['armorDamageModifier'] > 0) $json['armor'] -= $this->curTpl['armorDamageModifier']; + if ($this->curTpl['class'] == ITEM_CLASS_ARMOR || $this->curTpl['class'] == ITEM_CLASS_WEAPON) + $json['gearscore'] = Util::getEquipmentScore($json['level'], $this->getField('quality'), $json['slot'], $json['nsockets']); + else if ($this->curTpl['class'] == ITEM_CLASS_GEM) + $json['gearscore'] = Util::getGemScore($json['level'], $this->getField('quality'), $this->getField('requiredSkill') == 755, $this->id); + // clear zero-values afterwards foreach ($json as $k => $v) - if (!$v && !in_array($k, ['classs', 'subclass', 'quality', 'side'])) + if (!$v && !in_array($k, ['classs', 'subclass', 'quality', 'side', 'gearscore'])) unset($json[$k]); Util::checkNumeric($json); diff --git a/includes/types/spell.class.php b/includes/types/spell.class.php index 51ea3b44..20821201 100644 --- a/includes/types/spell.class.php +++ b/includes/types/spell.class.php @@ -211,7 +211,7 @@ class SpellList extends BaseType } // full magic mask, also counts towards healing - if ($mv == 0x7E) + if ($mv == SPELL_MAGIC_SCHOOLS) { Util::arraySumByKey($stats, [ITEM_MOD_SPELL_POWER => $pts]); Util::arraySumByKey($stats, [ITEM_MOD_SPELL_DAMAGE_DONE => $pts]); @@ -250,8 +250,10 @@ class SpellList extends BaseType case 35: // ModPower - MiscVal:type see defined Powers only energy/mana in use if ($mv == POWER_HEALTH) Util::arraySumByKey($stats, [ITEM_MOD_HEALTH => $pts]); - if ($mv == POWER_ENERGY) + else if ($mv == POWER_ENERGY) Util::arraySumByKey($stats, [ITEM_MOD_ENERGY => $pts]); + else if ($mv == POWER_RAGE) + Util::arraySumByKey($stats, [ITEM_MOD_RAGE => $pts]); else if ($mv == POWER_MANA) Util::arraySumByKey($stats, [ITEM_MOD_MANA => $pts]); else if ($mv == POWER_RUNIC_POWER) @@ -625,24 +627,25 @@ class SpellList extends BaseType $add = $ref->getField('effect'.$effIdx.'DieSides'); $maxLvl = $ref->getField('maxLevel'); $baseLvl = $ref->getField('baseLevel'); - $scaling = $this->curTpl['attributes1'] & 0x200; // never a referenced spell, ALWAYS $this; SPELL_ATTR1_MELEE_COMBAT_SPELL: 0x200 - if ($scaling) + if ($rppl) { if ($level > $maxLvl && $maxLvl > 0) $level = $maxLvl; else if ($level < $baseLvl) $level = $baseLvl; - $level -= $ref->getField('spellLevel'); + if (!$ref->getField('atributes0') & 0x40) // SPELL_ATTR0_PASSIVE + $level -= $ref->getField('spellLevel'); + $base += (int)($level * $rppl); } return [ $add ? $base + 1 : $base, $base + $add, - $scaling ? '' : null, - $scaling ? '' : null + $rppl ? '' : null, + $rppl ? '' : null ]; } @@ -1025,7 +1028,6 @@ class SpellList extends BaseType $min *= $duration / $periode; $max *= $duration / $periode; - $equal = $min == $max; if (in_array($op, $signs) && is_numeric($oparg)) { @@ -1066,8 +1068,6 @@ class SpellList extends BaseType $mv = $srcSpell->getField('effect'.$effIdx.'MiscValue'); $aura = $srcSpell->getField('effect'.$effIdx.'AuraId'); - $equal = $min == $max; - if (in_array($op, $signs) && is_numeric($oparg)) { eval("\$min = $min $op $oparg;"); @@ -1138,6 +1138,8 @@ class SpellList extends BaseType // handle excessively precise floats if (is_float($result[0])) $result[0] = round($result[0], 2); + if (isset($result[1]) && is_float($result[1])) + $result[1] = round($result[1], 2); return $result; } diff --git a/includes/utilities.php b/includes/utilities.php index a9f333a1..7a64586e 100644 --- a/includes/utilities.php +++ b/includes/utilities.php @@ -20,6 +20,11 @@ class Util { const FILE_ACCESS = 0777; + const GEM_SCORE_BASE_WOTLK = 16; // rare quality wotlk gem score + const GEM_SCORE_BASE_BC = 8; // rare quality bc gem score + + private static $perfectGems = null; + public static $localeStrings = array( // zero-indexed 'enus', null, 'frfr', 'dede', null, null, 'eses', null, 'ruru' ); @@ -945,6 +950,217 @@ class Util return self::$realms; } + + /**************/ + /* Good Skill */ + /**************/ + + public static function getEquipmentScore($itemLevel, $quality, $slot, $nSockets = 0) + { + $score = $itemLevel; + + // quality mod + switch ($quality) + { + case ITEM_QUALITY_POOR: + $score = 0; // guessed as crap + break; + case ITEM_QUALITY_NORMAL: + $score = 0; // guessed as crap + break; + case ITEM_QUALITY_UNCOMMON: + $score /= 2.0; + break; + case ITEM_QUALITY_RARE: + $score /= 1.8; + break; + case ITEM_QUALITY_EPIC: + $score /= 1.2; + break; + case ITEM_QUALITY_LEGENDARY: + $score /= 1; + break; + case ITEM_QUALITY_HEIRLOOM: // actual calculation in javascript .. still uses this as some sort of factor..? + break; + case ITEM_QUALITY_ARTIFACT: + break; + } + + switch ($slot) + { + case INVTYPE_WEAPON: + case INVTYPE_WEAPONMAINHAND: + case INVTYPE_WEAPONOFFHAND: + $score *= 27/64; + break; + case INVTYPE_SHIELD: + case INVTYPE_HOLDABLE: + $score *= 9/16; + break; + case INVTYPE_HEAD: + case INVTYPE_CHEST: + case INVTYPE_LEGS: + case INVTYPE_2HWEAPON: + $score *= 1.0; + break; + case INVTYPE_SHOULDERS: + case INVTYPE_HANDS: + case INVTYPE_WAIST: + case INVTYPE_FEET: + $score *= 3/4; + break; + case INVTYPE_WRISTS: + case INVTYPE_NECK: + case INVTYPE_CLOAK: + case INVTYPE_FINGER: + case INVTYPE_TRINKET: + $score *= 9/16; + break; + case INVTYPE_THROWN: + case INVTYPE_RANGED: + case INVTYPE_RELIC: + $score *= 81/256; + break; + default: + $score *= 0.0; + } + + // subtract sockets + if ($nSockets) + { + // items by expantion overlap in this range. luckily highlevel raid items are exclusivly epic or better + if ($itemLevel > 164 || ($itemLevel > 134 && $quality < ITEM_QUALITY_EPIC)) + $score -= $nSockets * self::GEM_SCORE_BASE_WOTLK; + else + $score -= $nSockets * self::GEM_SCORE_BASE_BC; + } + + return round(max(0.0, $score), 4); + } + + public static function getGemScore($itemLevel, $quality, $profSpec = false, $itemId = 0) + { + // prepare score-lookup + if (empty(self::$perfectGems)) + self::$perfectGems = DB::World()->selectCol('SELECT perfectItemType FROM skill_perfect_item_template WHERE requiredSpecialization = ?d', 55534); + + // epic - WotLK - increased stats / profession specific (Dragon's Eyes) + if ($profSpec) + return 32.0; + // epic - WotLK - base stats + if ($itemLevel == 80 && $quality == ITEM_QUALITY_EPIC) + return 20.0; + // rare - WotLK [GEM BASELINE!] + if ($itemLevel == 80 && $quality == ITEM_QUALITY_RARE) + return 16.0; + // uncommon - WotLK - inreased stats + if ($itemId > 0 && in_array($itemId, self::$perfectGems)) + return 14.0; + // uncommon - WotLK - base stats + if ($itemLevel == 70 && $quality == ITEM_QUALITY_UNCOMMON) + return 12.0; + // epic - BC - vendored (PvP) + if ($itemLevel == 60 && $quality == ITEM_QUALITY_EPIC) + return 10.0; + // epic - BC - dropped / crafted + if ($itemLevel == 70 && $quality == ITEM_QUALITY_EPIC) + return 9.0; + // rare - BC - crafted + if ($itemLevel == 70 && $quality == ITEM_QUALITY_RARE) + return 8.0; + // rare - BC - vendored (pvp) + if ($itemLevel == 60 && $quality == ITEM_QUALITY_RARE) + return 7.0; + // uncommon - BC + if ($itemLevel == 60 && $quality == ITEM_QUALITY_UNCOMMON) + return 6.0; + // common - BC - vendored gems + if ($itemLevel == 55 && $quality == ITEM_QUALITY_COMMON) + return 4.0; + + // dafuq..? + return 0.0; + } + + public static function getEnchantmentScore($itemLevel, $quality, $profSpec = false, $idOverride = 0) + { + // some hardcoded values, that defy lookups (cheaper but not skillbound profession versions of spell threads, leg armor) + if (in_array($idOverride, [3327, 3328, 3872, 3873])) + return 20.0; + + if ($profSpec) + return 40.0; + + // other than the constraints (0 - 20 points; 40 for profession perks), everything in here is guesswork + $score = max(min($itemLevel, 80), 0); + + switch ($quality) + { + case ITEM_QUALITY_HEIRLOOM: // because i say so! + $score = 80.0; + break; + case ITEM_QUALITY_RARE: + $score /= 1.2; + break; + case ITEM_QUALITY_UNCOMMON: + $score /= 1.6; + break; + case ITEM_QUALITY_NORMAL: + $score /= 2.5; + break; + } + + return round(max(0.0, $score / 4), 4); + } + + public static function fixWeaponScores($class, $talents, $mainHand, $offHand) + { + $mh = 1; + $oh = 1; + + if ($mainHand) { // Main Hand Equipped + if ($offHand) { // Off Hand Equipped + if ($mainHand['slotbak'] == 21 || $mainHand['slotbak'] == 13) { // Main Hand, One Hand + if ($offHand['slotbak'] == 22 || $offHand['slotbak'] == 13) { // Off Hand, One Hand + if ($class == 6 || $class == 3 || $class == 4 || // Death Knight, Hunter, Rogue + ($class == 7 && $talents['spent'][1] > 30 && $talents['spec'] == 2) || // Enhancement Shaman Over 39 + ($class == 1 && $talents['spent'][1] < 51 && $talents['spec'] == 2)) // Fury Warrior Under 60 + { + $mh = 64 / 27; + $oh = 64 / 27; + } + } + else if ($offHand['slotbak'] == 23 || $offHand['slotbak'] == 14) { // Held in Off Hand, Shield + if ($class == 5 || $class == 9 || $class == 8 || // Priest, Warlock, Mage + ($class == 11 && ($talents['spec'] == 1 || $talents['spec'] == 3)) || // Balance Druid, Restoration Druid + ($class == 7 && ($talents['spec'] == 1 || $talents['spec'] == 3)) || // Elemental Shaman, Restoration Shaman + ($class == 2 && ($talents['spec'] == 1 || $talents['spec'] == 2)) || // Holy Paladin, Protection Paladin + ($class == 1 && $talents['spec'] == 3)) // Protection Warrior + { + $mh = 64 / 27; + $oh = 16 / 9; + } + } + } + } + else if ($mainHand['slotbak'] == 17) { // Two Handed + if ($class == 5 || $class == 9 || $class == 8 || // Priest, Warlock, Mage + $class == 11 || $class == 3 || $class == 6 || // Druid, Hunter, Death Knight + ($class == 7 && $talents['spent'][1] < 31 && $talents['spec'] == 2) || // Enhancement Shaman Under 40 + ($class == 2 && $talents['spec'] == 3) || // Retribution Paladin + ($class == 1 && $talents['spec'] == 1)) // Arms Warrior + { + $mh = 2; + $oh = 0; + } + } + } + + return array( + round($mainHand['gearscore'] * $mh), + round($offHand['gearscore'] * $oh) + ); + } } ?> diff --git a/setup/tools/filegen/enchants.func.php b/setup/tools/filegen/enchants.func.php index d47172fc..da058c8a 100644 --- a/setup/tools/filegen/enchants.func.php +++ b/setup/tools/filegen/enchants.func.php @@ -49,7 +49,7 @@ if (!CLI) jsonequip:{reqlevel:60,"exprtng":15}, temp:0, classes:0, - gearscore:20 // nope, i'm not doing this + gearscore:20 // fuck, i'm doing this.. }, */ @@ -91,6 +91,8 @@ if (!CLI) return false; } + $castItems = new ItemList(array(['spellId1', array_keys($enchantSpells)], ['src.typeId', null, '!'], CFG_SQL_LIMIT_NONE)); + foreach (CLISetup::$localeIds as $lId) { User::useLocale($lId); @@ -134,7 +136,6 @@ if (!CLI) } } - // defaults $ench = array( 'name' => [], // set by skill or item @@ -147,6 +148,7 @@ if (!CLI) 'jsonequip' => $enchantments->getStatGain(), 'temp' => 0, // always 0 'classes' => 0, // modified by item + 'gearscore' => 0 // set later ); if ($_ = $enchantments->getField('skillLine')) @@ -169,12 +171,21 @@ if (!CLI) // check if this spell can be cast via item -> Source:Item // do not reuse enchantment scrolls; do not use items without source - if (!isset($castItems[$esId])) - $castItems[$esId] = new ItemList([['spellId1', $esId], ['name_loc0', 'Scroll of Enchant%', '!'], ['src.typeId', null, '!']]); - - $cI = &$castItems[$esId]; // this construct is a bit .. unwieldy + $cI = &$castItems; // this construct is a bit .. unwieldy foreach ($cI->iterate() as $__) { + if ($cI->getField('spellId1') != $esId) + continue; + + $isScroll = substr($cI->getField('name_loc0'), 0, 17) == 'Scroll of Enchant'; + + if ($s = Util::getEnchantmentScore($cI->getField('itemLevel'), $isScroll ? -1 : $cI->getField('quality'), !!$enchantments->getField('skillLevel'), $eId)) + if ($s > $ench['gearscore']) + $ench['gearscore'] = $s; + + if ($isScroll) + continue; + $ench['name'][] = $cI->getField('name', true); $ench['source'][] = -$cI->id; $ench['icon'] = strTolower($cI->getField('iconString')); diff --git a/setup/tools/filegen/gems.func.php b/setup/tools/filegen/gems.func.php index d9a7f0fe..14ae8101 100644 --- a/setup/tools/filegen/gems.func.php +++ b/setup/tools/filegen/gems.func.php @@ -20,7 +20,7 @@ if (!CLI) jsonequip:{"arcres":3,"avgbuyout":242980,"firres":3,"frores":3,"holres":3,"natres":3,"shares":3}, colors:14, expansion:1 - gearscore:8 // as if..... + gearscore:8 // if only.. }, */ @@ -35,14 +35,15 @@ if (!CLI) i.quality, ic.name AS icon, i.gemEnchantmentId AS enchId, - i.gemColorMask AS colors + i.gemColorMask AS colors, + i.requiredSkill, + i.itemLevel FROM ?_items i JOIN ?_icons ic ON ic.id = i.iconId WHERE i.gemEnchantmentId <> 0 ORDER BY i.id DESC'); $success = true; - // check directory-structure foreach (Util::$localeStrings as $dir) if (!CLISetup::writeDir('datasets/'.$dir)) @@ -83,7 +84,8 @@ if (!CLI) 'enchantment' => $enchantments->getField('name', true), 'jsonequip' => $enchantments->getStatGain(), 'colors' => $pop['colors'], - 'expansion' => $pop['expansion'] + 'expansion' => $pop['expansion'], + 'gearscore' => Util::getGemScore($pop['itemLevel'], $pop['quality'], $pop['requiredSkill'] == 755, $pop['itemId']) ); } diff --git a/static/js/Summary.js b/static/js/Summary.js index f8e9ff59..e929b50c 100644 --- a/static/js/Summary.js +++ b/static/js/Summary.js @@ -155,7 +155,9 @@ function Summary(opt) { } } - this.initialize(); + // aowow - data=item-scaling load is delayed from basic.js but required for heirlooms + // this.initialize(); + setTimeout(this.initialize.bind(this), 250); } Summary.prototype = { diff --git a/static/js/basic.js b/static/js/basic.js index f8da5d6b..50f387fc 100644 --- a/static/js/basic.js +++ b/static/js/basic.js @@ -1331,7 +1331,7 @@ $WH.g_setJsonItemLevel = function (json, level) { json.dmgmin = json[damageType + "dmgmin"] = Math.floor(json.dps * json.speed * (1 - damageRange)); json.dmgmax = json[damageType + "dmgmax"] = Math.floor(json.dps * json.speed * (1 + damageRange)) - if (json.feratkpwr) { // yes thats custom.. + if (json.feratkpwr) { // aowow - yes thats custom.. json.feratkpwr = Math.max(0, Math.floor((json.dps - 54.8) * 14)); } } @@ -1340,6 +1340,24 @@ $WH.g_setJsonItemLevel = function (json, level) { if (splPwrColumn >= 0) { json.splpwr = json.bonuses[45] = $WH.g_convertScalingFactor(level, splPwrColumn); } + + // Update the gearscore (profiler usage) + if (json.gearscore != null) + { + if (json._gearscore == null) + json._gearscore = json.gearscore; + + var equivLevel = Math.min(80, level + 1); + + if(equivLevel >= 70) + n = ((equivLevel - 70) * 9.5) + 105; + else if(equivLevel >= 60) + n = ((equivLevel - 60) * 4.5) + 60; + else + n = equivLevel + 5; + + json.gearscore = (json._gearscore * n) / 1.8; + } }; $WH.g_setTooltipLevel = function(tooltip, level) { diff --git a/static/js/global.js b/static/js/global.js index 10dead23..b8660bea 100644 --- a/static/js/global.js +++ b/static/js/global.js @@ -15689,6 +15689,24 @@ Listview.templates = { }, hidden: 1 }, + { + id: 'gearscore', + name: LANG.gearscore, + tooltip: LANG.gearscore_real, + value: 'gearscore', + compute: function(profile, td) + { + var level = (profile.level ? profile.level : (profile.members !== undefined ? 80 : 0)); + + if (isNaN(profile.gearscore) || !level) + return; + + td.className = 'q' + pr_getGearScoreQuality(level, profile.gearscore, ($WH.in_array([2, 6, 7, 11], profile.classs) != -1)); + + return (profile.gearscore ? $WH.number_format(profile.gearscore) : 0); + }, + hidden: 1 + }, { id: 'achievementpoints', name: LANG.points, @@ -17487,14 +17505,14 @@ var Icon = { sizes: ['small', 'medium', 'large'], sizes2: [18, 36, 56], premiumOffsets: [[-56, -36], [-56, 0], [0, 0]], - premiumBorderClasses: ['-premium', '-gold', '', '-premiumred', '-red'], - STANDARD_BORDER: 2, - privilegeBorderClasses: { - uncommon: '-q2', - rare: '-q3', - epic: '-q4', - legendary: '-q5' - }, + premiumBorderClasses: ['-premium', '-gold', '', '-premiumred', '-red'], + STANDARD_BORDER: 2, + privilegeBorderClasses: { + uncommon: '-q2', + rare: '-q3', + epic: '-q4', + legendary: '-q5' + }, create: function(name, size, UNUSED, url, num, qty, noBorder, rel) { var icon = $WH.ce('div'), diff --git a/static/js/home.js b/static/js/home.js index 05017e14..ae6969c3 100644 --- a/static/js/home.js +++ b/static/js/home.js @@ -16,7 +16,7 @@ $(document).ready(function () { $('.home-featuredbox-links a').hover( function () { $(this).next('var').addClass('active') }, function () { $(this).next('var').removeClass('active') } - ).click(function () { g_trackEvent('Featured Box', 'Click', this.title) } - ).each( function () { g_trackEvent('Featured Box', 'Impression', this.title) } + ).click(function () { g_trackEvent('Featured Box', 'Click', this.title) } + ).each( function () { g_trackEvent('Featured Box', 'Impression', this.title) } ) }); diff --git a/static/js/locale_dede.js b/static/js/locale_dede.js index 2793d0ec..23311121 100644 --- a/static/js/locale_dede.js +++ b/static/js/locale_dede.js @@ -2454,6 +2454,7 @@ var LANG = { gender: "Geschlecht", gems: "Edelsteine", gearscore: "Ausrüstung", + gearscore_real: "Ausrüstungswertung", glyphtype: "Glyphenart", group: "Gruppe", guild: "Gilde", diff --git a/static/js/locale_enus.js b/static/js/locale_enus.js index 93cd9d45..fff1f954 100644 --- a/static/js/locale_enus.js +++ b/static/js/locale_enus.js @@ -2501,6 +2501,7 @@ var LANG = { gender: "Gender", gems: "Gems", gearscore: "Gear", + gearscore_real: "Gear score", glyphtype: "Glyph type", group: "Group", guild: "Guild", diff --git a/static/js/locale_eses.js b/static/js/locale_eses.js index 71a3c6d7..5c4840f3 100644 --- a/static/js/locale_eses.js +++ b/static/js/locale_eses.js @@ -2455,6 +2455,7 @@ var LANG = { gender: "Género", gems: "Gemas", gearscore: "Equipo", + gearscore_real: "Puntuación de equipo", glyphtype: "Tipo de glifo", group: "Grupo", guild: "Hermandad", diff --git a/static/js/locale_frfr.js b/static/js/locale_frfr.js index c919d564..ccfddc19 100644 --- a/static/js/locale_frfr.js +++ b/static/js/locale_frfr.js @@ -2444,6 +2444,7 @@ var LANG = { gender: "Genre", gems: "Gemmes", gearscore: "Équipement", + gearscore_real: "Score d'équipement", glyphtype: "Type de glyphe", group: "Groupe", guild: "Guilde", diff --git a/static/js/locale_ruru.js b/static/js/locale_ruru.js index 73c66100..592ef8f7 100644 --- a/static/js/locale_ruru.js +++ b/static/js/locale_ruru.js @@ -2444,6 +2444,7 @@ var LANG = { gender: "Пол", gems: "Самоцветы", gearscore: "Экипировка", + gearscore_real: "Очки экипировки", glyphtype: "Тип символа", group: "Группа", guild: "Гильдия",