diff --git a/includes/defines.php b/includes/defines.php index ecf37a72..acb47fb7 100644 --- a/includes/defines.php +++ b/includes/defines.php @@ -482,13 +482,13 @@ define('ITEM_CLASS_ARMOR', 4); define('ITEM_CLASS_REAGENT', 5); define('ITEM_CLASS_AMMUNITION', 6); define('ITEM_CLASS_TRADEGOOD', 7); -// define('ITEM_CLASS_GENERIC', 8); +define('ITEM_CLASS_GENERIC', 8); define('ITEM_CLASS_RECIPE', 9); define('ITEM_CLASS_MONEY', 10); define('ITEM_CLASS_QUIVER', 11); define('ITEM_CLASS_QUEST', 12); define('ITEM_CLASS_KEY', 13); -// define('ITEM_CLASS_PERMANENT', 14); +define('ITEM_CLASS_PERMANENT', 14); define('ITEM_CLASS_MISC', 15); define('ITEM_CLASS_GLYPH', 16); diff --git a/includes/genericPage.class.php b/includes/genericPage.class.php index fb2bfae0..fc86f062 100644 --- a/includes/genericPage.class.php +++ b/includes/genericPage.class.php @@ -16,9 +16,9 @@ trait DetailPage // mode, type, typeId, localeId, category, filter $key = [$this->mode, $this->type, $this->typeId, User::$localeId, '-1', '-1']; - // check for $this->enhancedTT from Item and apply - // foreach ($extra as $x) - // $key[] = (string)$x; + // item special: can modify tooltips + if (isset($this->enhancedTT)) + $key[] = md5(serialize($this->enhancedTT)); return implode('_', $key); } @@ -159,11 +159,12 @@ class GenericPage $this->saveCache(); } - $this->gPageInfo = array( // varies slightly for special pages like maps, user-dashboard or profiler - 'type' => $this->type, - 'typeId' => $this->typeId, - 'name' => $this->name - ); + if (isset($this->type) && isset($this->typeId)) + $this->gPageInfo = array( // varies slightly for special pages like maps, user-dashboard or profiler + 'type' => $this->type, + 'typeId' => $this->typeId, + 'name' => $this->name + ); if (method_exists($this, 'postCache')) // e.g. update dates for events and such $this->postCache(); @@ -258,12 +259,12 @@ class GenericPage private function addAnnouncements() // get announcements and notes for user { + if (!isset($this->announcements)) + $this->announcements = []; + // display occured notices if ($_ = Util::getNotes(false)) { - if (!isset($this->announcements)) - $this->announcements = []; - $this->announcements[] = array( 'id' => 0, 'mode' => 1, @@ -277,9 +278,6 @@ class GenericPage // fetch announcements if (preg_match('/^([a-z\-]+)=?.*$/i', $_SERVER['QUERY_STRING'], $match)) { - if (!isset($this->announcements)) - $this->announcements = []; - $ann = DB::Aowow()->Select('SELECT * FROM ?_announcements WHERE status = 1 AND (page = ? OR page = "*") AND (groupMask = 0 OR groupMask & ?d)', $match[1], User::$groups); foreach ($ann as $k => $v) { diff --git a/includes/kernel.php b/includes/kernel.php index 8e2b83ef..7489bacc 100644 --- a/includes/kernel.php +++ b/includes/kernel.php @@ -9,14 +9,16 @@ ini_set('serialize_precision', 4); require 'includes/defines.php'; require 'config/config.php'; require 'includes/genericPage.class.php'; -require 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using mysqli variant: https://bitbucket.org/brainreaver/dbsimple/src) -require 'includes/utilities.php'; -require 'includes/ajaxHandler.class.php'; +require 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using mysqli variant: https://bitbucket.org/brainreaver/dbsimple/src) +require 'includes/utilities.php'; // miscâ„¢ data 'n func +require 'includes/ajaxHandler.class.php'; // handles ajax and jsonp requests require 'includes/user.class.php'; -require 'includes/database.class.php'; -require 'includes/community.class.php'; +require 'includes/database.class.php'; // wrap DBSimple +require 'includes/community.class.php'; // handle comments, screenshots and videos +require 'includes/loot.class.php'; // build lv-tabs containing loot-information require 'localization/lang.class.php'; + // autoload List-classes, associated filters and pages spl_autoload_register(function ($class) { $class = str_replace('Filter', '', $class); diff --git a/includes/loot.class.php b/includes/loot.class.php index c1581275..47aa1e3f 100644 --- a/includes/loot.class.php +++ b/includes/loot.class.php @@ -20,11 +20,12 @@ if (!defined('AOWOW_REVISION')) class Loot { - public static $jsGlobals = []; - public static $extraCols = []; + public $jsGlobals = []; + public $extraCols = []; - private static $results = []; - private static $lootTemplates = array( + private $entry = 0; // depending on the lookup itemId oder templateId + private $results = []; + private $lootTemplates = array( LOOT_REFERENCE, // internal LOOT_ITEM, // item LOOT_DISENCHANT, // item @@ -39,20 +40,20 @@ class Loot LOOT_SPELL // spell ); - public static function &iterate() + public function &iterate() { - reset(self::$results); + reset($this->results); - while (list($k, $__) = each(self::$results)) - yield self::$results[$k]; + while (list($k, $__) = each($this->results)) + yield $this->results[$k]; } - public static function getResult() + public function getResult() { - return self::$results; + return $this->results; } - private static function createStack($l) // issue: TC always has an equal distribution between min/max + private function createStack($l) // issue: TC always has an equal distribution between min/max { if (empty($l['min']) || empty($l['max']) || $l['min'] <= $l['max']) return null; @@ -65,14 +66,22 @@ class Loot return json_encode($stack, JSON_NUMERIC_CHECK); } - private static function storeJSGlobals($data) + private function storeJSGlobals($data) { foreach ($data as $type => $jsData) + { foreach ($jsData as $k => $v) - self::$jsGlobals[$type][$k] = $v; + { + // was already set at some point with full data + if (isset($this->jsGlobals[$type][$k]) && is_array($this->jsGlobals[$type][$k])) + continue; + + $this->jsGlobals[$type][$k] = $v; + } + } } - private static function getByContainerRecursive($tableName, $lootId, &$handledRefs, $groupId = 0, $baseChance = 1.0) + private function getByContainerRecursive($tableName, $lootId, &$handledRefs, $groupId = 0, $baseChance = 1.0) { $loot = []; $rawItems = []; @@ -80,7 +89,7 @@ class Loot if (!$tableName || !$lootId) return null; - $rows = DB::Aowow()->select('SELECT * FROM ?# WHERE entry = ?d{ AND groupid = ?d}', $tableName, abs($lootId), $groupId ? $groupId : DBSIMPLE_SKIP); + $rows = DB::Aowow()->select('SELECT * FROM ?# WHERE entry = ?d{ AND groupid = ?d}', $tableName, abs($lootId), $groupId ?: DBSIMPLE_SKIP); if (!$rows) return null; @@ -164,7 +173,7 @@ class Loot } else // shouldn't have happened { - self::addNote(U_GROUP_EMPLOYEE, 'Loot::getByContainerRecursive: unhandled case in calculating chance for item '.$entry['item'].'!'); + Util::addNote(U_GROUP_EMPLOYEE, 'Loot::getByContainerRecursive: unhandled case in calculating chance for item '.$entry['item'].'!'); continue; } @@ -178,7 +187,7 @@ class Loot $sum = 0; else if ($sum > 100) { - self::addNote(U_GROUP_EMPLOYEE, 'Loot::getByContainerRecursive: entry '.$lootId.' / group '.$k.' has a total chance of '.number_format($sum, 2).'%. Some items cannot drop!'); + Util::addNote(U_GROUP_EMPLOYEE, 'Loot::getByContainerRecursive: entry '.$lootId.' / group '.$k.' has a total chance of '.number_format($sum, 2).'%. Some items cannot drop!'); $sum = 100; } @@ -190,11 +199,11 @@ class Loot return [$loot, array_unique($rawItems)]; } - public static function getByContainer($table, $entry) + public function getByContainer($table, $entry) { - $loot = null; + $this->entry = intVal($entry); - if (!$table || !$entry) + if (!in_array($table, $this->lootTemplates) || !$this->entry) return null; /* @@ -202,19 +211,19 @@ class Loot also - // if (is_array($entry) && in_array($table, [LOOT_CREATURE, LOOT_GAMEOBJECT]) + // if (is_array($this->entry) && in_array($table, [LOOT_CREATURE, LOOT_GAMEOBJECT]) // iterate over the 4 available difficulties and assign modes modes:{"mode":1,"1":{"count":4408,"outof":16013},"4":{"count":4408,"outof":22531}} */ $handledRefs = []; - $struct = self::getByContainerRecursive($table, $entry, $handledRefs); + $struct = self::getByContainerRecursive($table, $this->entry, $handledRefs); if (!$struct) return false; $items = new ItemList(array(['i.id', $struct[1]], CFG_SQL_LIMIT_NONE)); - self::$jsGlobals = $items->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED); + $this->jsGlobals = $items->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED); $foo = $items->getListviewData(); // assign listview LV rows to loot rows, not the other way round! The same item may be contained multiple times @@ -240,13 +249,13 @@ class Loot { if (!User::isInGroup(U_GROUP_STAFF)) { - if (!isset(self::$results[$loot['content']])) - self::$results[$loot['content']] = array_merge($foo[$loot['content']], $base, ['stack' => [$loot['min'], $loot['max']]]); + if (!isset($this->results[$loot['content']])) + $this->results[$loot['content']] = array_merge($foo[$loot['content']], $base, ['stack' => [$loot['min'], $loot['max']]]); else - self::$results[$loot['content']]['percent'] += $base['percent']; + $this->results[$loot['content']]['percent'] += $base['percent']; } else // in case of limited trash loot, check if $foo[] exists - self::$results[] = array_merge($foo[$loot['content']], $base, ['stack' => [$loot['min'], $loot['max']]]); + $this->results[] = array_merge($foo[$loot['content']], $base, ['stack' => [$loot['min'], $loot['max']]]); } else if (User::isInGroup(U_GROUP_STAFF)) // create dummy for ref-drop { @@ -256,16 +265,16 @@ class Loot 'icon' => 'trade_engineering', 'stack' => [$loot['multiplier'], $loot['multiplier']] ); - self::$results[] = array_merge($base, $data); + $this->results[] = array_merge($base, $data); - self::$jsGlobals[TYPE_ITEM][$loot['content']] = $data; + $this->jsGlobals[TYPE_ITEM][$loot['content']] = $data; } } // move excessive % to extra loot if (!User::isInGroup(U_GROUP_STAFF)) { - foreach (self::$results as &$_) + foreach ($this->results as &$_) { if ($_['percent'] <= 100) continue; @@ -286,7 +295,7 @@ class Loot $fields = ['mode', 'reference']; $base = []; $set = 0; - foreach (self::$results as $foo) + foreach ($this->results as $foo) { foreach ($fields as $idx => $field) { @@ -300,19 +309,21 @@ class Loot break; } - self::$extraCols[] = "Listview.funcBox.createSimpleCol('group', 'Group', '7%', 'group')"; + $this->extraCols[] = "Listview.funcBox.createSimpleCol('group', 'Group', '7%', 'group')"; foreach ($fields as $idx => $field) if ($set & (1 << $idx)) - self::$extraCols[] = "Listview.funcBox.createSimpleCol('".$field."', '".Util::ucFirst($field)."', '7%', '".$field."')"; + $this->extraCols[] = "Listview.funcBox.createSimpleCol('".$field."', '".Util::ucFirst($field)."', '7%', '".$field."')"; } return true; } - public static function getByItem($itemId, $maxResults = CFG_SQL_LIMIT_DEFAULT) + public function getByItem($entry, $maxResults = CFG_SQL_LIMIT_DEFAULT) { - if (!$itemId) - return []; + $this->entry = intVal($entry); + + if (!$this->entry) + return false; // [fileName, tabData, tabName, tabId, extraCols, hiddenCols, visibleCols] $tabsFinal = array( @@ -364,15 +375,15 @@ class Loot { // check for possible database inconsistencies if (!$ref['chance'] && !$ref['isGrouped']) - self::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: ungrouped Item/Ref '.$ref['item'].' has 0% chance assigned!'); + Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: ungrouped Item/Ref '.$ref['item'].' has 0% chance assigned!'); if ($ref['isGrouped'] && $ref['sumChance'] > 100) - self::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: group with Item/Ref '.$ref['item'].' has '.number_format($ref['sumChance'], 2).'% total chance! Some items cannot drop!'); + Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: group with Item/Ref '.$ref['item'].' has '.number_format($ref['sumChance'], 2).'% total chance! Some items cannot drop!'); if ($ref['isGrouped'] && $ref['sumChance'] == 100 && !$ref['chance']) - self::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: Item/Ref '.$ref['item'].' with adaptive chance cannot drop. Group already at 100%!'); + Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: Item/Ref '.$ref['item'].' with adaptive chance cannot drop. Group already at 100%!'); - $chance = abs($ref['chance'] ? $ref['chance'] : (100 - $ref['sumChance']) / $ref['nZeroItems']) / 100; + $chance = abs($ref['chance'] ?: (100 - $ref['sumChance']) / $ref['nZeroItems']) / 100; // apply inherited chanceMods if (isset($chanceMods[$ref['item']])) @@ -390,7 +401,7 @@ class Loot $data = array( 'percent' => $chance, 'stack' => [$ref['min'], $ref['max']], - 'count' => 1 // ..and one for the sort script + 'count' => 1 // ..and one for the sort script ); if ($_ = self::createStack($ref)) @@ -416,7 +427,7 @@ class Loot $newRefs = DB::Aowow()->select( sprintf($query, 'lt1.item = ?d AND lt1.mincountOrRef > 0'), LOOT_REFERENCE, LOOT_REFERENCE, - $itemId + $this->entry ); while ($newRefs) @@ -434,13 +445,13 @@ class Loot /* search the real loot-templates for the itemId and gathered refds */ - for ($i = 1; $i < count(self::$lootTemplates); $i++) + for ($i = 1; $i < count($this->lootTemplates); $i++) { $result = $calcChance(DB::Aowow()->select( sprintf($query, '{lt1.mincountOrRef IN (?a) OR }(lt1.mincountOrRef > 0 AND lt1.item = ?d)'), - self::$lootTemplates[$i], self::$lootTemplates[$i], + $this->lootTemplates[$i], $this->lootTemplates[$i], $refResults ? array_keys($refResults) : DBSIMPLE_SKIP, - $itemId + $this->entry )); // do not skip here if $result is empty. Additional loot for spells and quest is added separately @@ -457,7 +468,7 @@ class Loot // screws with GO-loot and skinnig-loot as these templates are shared for several tabs (fish, herb, ore) (herb, ore, leather) $ids = array_slice(array_keys($result), 0, $maxResults); - switch (self::$lootTemplates[$i]) + switch ($this->lootTemplates[$i]) { case LOOT_CREATURE: $field = 'lootId'; $tabId = 4; break; case LOOT_PICKPOCKET: $field = 'pickpocketLootId'; $tabId = 5; break; @@ -494,8 +505,8 @@ class Loot } break; case LOOT_MAIL: - $conditions = array(['rewardChoiceItemId1', $itemId], ['rewardChoiceItemId2', $itemId], ['rewardChoiceItemId3', $itemId], ['rewardChoiceItemId4', $itemId], ['rewardChoiceItemId5', $itemId], - ['rewardChoiceItemId6', $itemId], ['rewardItemId1', $itemId], ['rewardItemId2', $itemId], ['rewardItemId3', $itemId], ['rewardItemId4', $itemId], + $conditions = array(['rewardChoiceItemId1', $this->entry], ['rewardChoiceItemId2', $this->entry], ['rewardChoiceItemId3', $this->entry], ['rewardChoiceItemId4', $this->entry], ['rewardChoiceItemId5', $this->entry], + ['rewardChoiceItemId6', $this->entry], ['rewardItemId1', $this->entry], ['rewardItemId2', $this->entry], ['rewardItemId3', $this->entry], ['rewardItemId4', $this->entry], 'OR'); if ($ids) $conditions[] = ['rewardMailTemplateId', $ids]; @@ -517,7 +528,7 @@ class Loot break; case LOOT_SPELL: - $conditions = ['OR', ['effect1CreateItemId', $itemId], ['effect2CreateItemId', $itemId], ['effect3CreateItemId', $itemId]]; + $conditions = ['OR', ['effect1CreateItemId', $this->entry], ['effect2CreateItemId', $this->entry], ['effect3CreateItemId', $this->entry]]; if ($ids) $conditions[] = ['id', $ids]; @@ -573,7 +584,9 @@ class Loot } } - return $tabsFinal; + $this->results = $tabsFinal; + + return true; } } diff --git a/includes/types/basetype.class.php b/includes/types/basetype.class.php index 0681b91e..3c6b0ac2 100644 --- a/includes/types/basetype.class.php +++ b/includes/types/basetype.class.php @@ -233,16 +233,16 @@ abstract class BaseType $this->queryBase .= ' WHERE ('.implode($linking, $where).')'; // append grouping - if ($g = array_column($this->queryOpts, 'g')) - $this->queryBase .= ' GROUP BY '.implode(', ', array_filter($g)); + if ($g = array_filter(array_column($this->queryOpts, 'g'))) + $this->queryBase .= ' GROUP BY '.implode(', ', $g); // append post filtering - if ($h = array_column($this->queryOpts, 'h')) - $this->queryBase .= ' HAVING '.implode(' AND ', array_filter($h)); + if ($h = array_filter(array_column($this->queryOpts, 'h'))) + $this->queryBase .= ' HAVING '.implode(' AND ', $h); // append ordering - if ($o = array_column($this->queryOpts, 'o')) - $this->queryBase .= ' ORDER BY '.implode(', ', array_filter($o)); + if ($o = array_filter(array_column($this->queryOpts, 'o'))) + $this->queryBase .= ' ORDER BY '.implode(', ', $o); // apply limit if ($limit) diff --git a/includes/types/item.class.php b/includes/types/item.class.php index 8c06e8fd..745e5d1a 100644 --- a/includes/types/item.class.php +++ b/includes/types/item.class.php @@ -22,11 +22,11 @@ class ItemList extends BaseType private $vendors = []; private $jsGlobals = []; // getExtendedCost creates some and has no access to template - protected $queryBase = 'SELECT i.*, i.id AS ARRAY_KEY FROM ?_items i'; + protected $queryBase = 'SELECT i.*, `is`.*, i.id AS ARRAY_KEY FROM ?_items i'; protected $queryOpts = array( - 'is' => ['j' => '?_item_stats AS `is` ON `is`.`id` = `i`.`id`', 'o' => 'score DESC'], + 'is' => ['j' => ['?_item_stats AS `is` ON `is`.`id` = `i`.`id`', true]], 's' => ['j' => ['?_spell AS `s` ON s.effect1CreateItemId = i.id', true], 'g' => 'i.id'], - 'i' => ['o' => 'i.quality DESC, i.itemLevel DESC'] + 'i' => [['is'], 'o' => 'i.quality DESC, i.itemLevel DESC'] ); public function __construct($conditions = [], $miscData = null) @@ -230,12 +230,12 @@ class ItemList extends BaseType if ($addInfoMask & ITEMINFO_SUBITEMS) $this->initSubItems(); + if ($addInfoMask & ITEMINFO_JSON) + $this->extendJsonStats(); + $data = []; foreach ($this->iterate() as $__) { - if ($addInfoMask & ITEMINFO_JSON) - $this->extendJsonStats(); - foreach ($this->json[$this->id] as $k => $v) $data[$this->id][$k] = $v; @@ -246,7 +246,7 @@ class ItemList extends BaseType if ($addInfoMask & ITEMINFO_JSON) { foreach ($this->itemMods[$this->id] as $k => $v) - $data[$this->id][Util::$itemMods[$k]] = $v; + $data[$this->id][$k] = $v; if ($_ = intVal(($this->curTpl['minMoneyLoot'] + $this->curTpl['maxMoneyLoot']) / 2)) $data[$this->id]['avgmoney'] = $_; @@ -269,8 +269,7 @@ class ItemList extends BaseType { // just use the first results // todo (med): dont use first result; search for the right one - $cost = @reset($this->getExtendedCost($miscData)[$this->id]); - if ($cost) + if ($cost = @reset($this->getExtendedCost($miscData)[$this->id])) { $currency = []; $tokens = []; @@ -386,8 +385,8 @@ class ItemList extends BaseType { $extra[$id] = array( 'id' => $id, - 'tooltip' => Util::jsEscape($this->renderTooltip(null, true)), - 'spells' => '' + 'tooltip' => $this->renderTooltip(true), + 'spells' => new StdClass // placeholder for knownSpells ); } } @@ -404,7 +403,7 @@ class ItemList extends BaseType interactive (set to place javascript/anchors to manipulate level and ratings or link to filters (static tooltips vs popup tooltip)) subOf (tabled layout doesn't work if used as sub-tooltip in other item or spell tooltips; use line-break instead) */ - public function renderTooltip($enhance = [], $interactive = false, $subOf = 0) + public function renderTooltip($interactive = false, $subOf = 0, $enhance = []) { if ($this->error) return; @@ -421,30 +420,34 @@ class ItemList extends BaseType $_slot = $this->curTpl['slot']; $causesScaling = false; - if (!empty($enhance['rand'])) + if (!empty($enhance['r'])) { - $rndEnch = DB::Aowow()->selectRow('SELECT * FROM ?_itemrandomenchant WHERE Id = ?d', $enhance['rand']); - $_name .= ' '.Util::localizedString($rndEnch, 'name'); - $randEnchant = ''; - - for ($i = 1; $i < 6; $i++) + if ($rndEnch = DB::Aowow()->selectRow('SELECT * FROM ?_itemrandomenchant WHERE Id = ?d', $enhance['r'])) { - if ($rndEnch['enchantId'.$i] <= 0) - continue; + $_name .= ' '.Util::localizedString($rndEnch, 'name'); + $randEnchant = ''; - $enchant = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantment WHERE Id = ?d', $rndEnch['enchantId'.$i]); - if ($rndEnch['allocationPct'.$i] > 0) + for ($i = 1; $i < 6; $i++) { - $amount = intVal($rndEnch['allocationPct'.$i] * $this->generateEnchSuffixFactor()); - $randEnchant .= ''.str_replace('$i', $amount, Util::localizedString($enchant, 'text')).'
'; + if ($rndEnch['enchantId'.$i] <= 0) + continue; + + $enchant = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantment WHERE Id = ?d', $rndEnch['enchantId'.$i]); + if ($rndEnch['allocationPct'.$i] > 0) + { + $amount = intVal($rndEnch['allocationPct'.$i] * $this->generateEnchSuffixFactor()); + $randEnchant .= ''.str_replace('$i', $amount, Util::localizedString($enchant, 'text')).'
'; + } + else + $randEnchant .= ''.Util::localizedString($enchant, 'text').'
'; } - else - $randEnchant .= ''.Util::localizedString($enchant, 'text').'
'; } + else + unset($enhance['r']); } - if (isset($enhance['sock']) && !in_array($_slot, [INVTYPE_WRISTS, INVTYPE_WAIST, INVTYPE_HANDS])) - unset($enhance['sock']); + if (isset($enhance['s']) && !in_array($_slot, [INVTYPE_WRISTS, INVTYPE_WAIST, INVTYPE_HANDS])) + unset($enhance['s']); // IMPORTAT: DO NOT REMOVE THE HTML-COMMENTS! THEY ARE REQUIRED TO UPDATE THE TOOLTIP CLIENTSIDE $x = ''; @@ -500,12 +503,12 @@ class ItemList extends BaseType else if ($this->curTpl['itemLimitCategory']) { $limit = DB::Aowow()->selectRow("SELECT * FROM ?_itemlimitcategory WHERE id = ?", $this->curTpl['itemLimitCategory']); - $x .= '
'.($limit['isGem'] ? Lang::$item['uniqueEquipped'] : Lang::$item['unique']).Lang::$colon.Util::localizedString($limit, 'name').' ('.$limit['count'].')'; + $x .= '
'.($limit['isGem'] ? Lang::$item['uniqueEquipped'] : Lang::$item['unique']).Lang::$main['colon'].Util::localizedString($limit, 'name').' ('.$limit['count'].')'; } // max duration if ($dur = $this->curTpl['duration']) - $x .= "
".Lang::$game['duration'].Lang::$colon.Util::formatTime(abs($dur) * 1000).($this->curTpl['flagsCustom'] & 0x1 ? ' ('.Lang::$item['realTime'].')' : null); + $x .= "
".Lang::$game['duration'].Lang::$main['colon'].Util::formatTime(abs($dur) * 1000).($this->curTpl['flagsCustom'] & 0x1 ? ' ('.Lang::$item['realTime'].')' : null); // required holiday if ($hId = $this->curTpl['holidayId']) @@ -607,9 +610,9 @@ class ItemList extends BaseType } // Random Enchantment - if random enchantment is set, prepend stats from it - if ($this->curTpl['randomEnchant'] && !isset($enhance['rand'])) + if ($this->curTpl['randomEnchant'] && !isset($enhance['r'])) $x .= ''.Lang::$item['randEnchant'].'
'; - else if (isset($enhance['rand'])) + else if (isset($enhance['r'])) $x .= $randEnchant; // itemMods (display stats and save ratings for later use) @@ -634,41 +637,36 @@ class ItemList extends BaseType $x .= '+'.$this->curTpl[$rowName].' '.Lang::$game['resistances'][$j].'
'; // Enchantment - if (isset($enhance['ench'])) + if (isset($enhance['e'])) { - $enchText = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantment WHERE Id = ?', $enhance['ench']); - $x .= ''.Util::localizedString($enchText, 'text').'
'; + if ($enchText = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantment WHERE Id = ?', $enhance['e'])) + $x .= ''.Util::localizedString($enchText, 'text').'
'; + else + { + unset($enhance['e']); + $x .= ''; + } } else // enchantment placeholder $x .= ''; // Sockets w/ Gems - if (!empty($enhance['gems'])) + if (!empty($enhance['g'])) { - $gems = DB::Aowow()->select(' - SELECT - i.id AS ARRAY_KEY, - i.iconString, - ae.*, - i.gemColorMask AS colorMask - FROM - ?_items i - JOIN - ?_itemenchantment ae ON ae.id = i.gemEnchantmentId - WHERE - i.id IN (?a)', - $enhance['gems'] - ); + $gems = DB::Aowow()->select('SELECT i.id AS ARRAY_KEY, i.iconString, ae.*, i.gemColorMask AS colorMask FROM ?_items i JOIN ?_itemenchantment ae ON ae.id = i.gemEnchantmentId WHERE i.id IN (?a)', $enhance['g']); + foreach ($enhance['g'] as $k => $v) + if (!in_array(array_keys($gems), $v)) + unset($enhance['g'][$k]); } else - $enhance['gems'] = []; + $enhance['g'] = []; // zero fill empty sockets - $sockCount = $this->curTpl['socketColor1'] + $this->curTpl['socketColor2'] + $this->curTpl['socketColor3'] + (isset($enhance['sock']) ? 1 : 0); - while ($sockCount > count($enhance['gems'])) - $enhance['gems'][] = 0; + $sockCount = $this->curTpl['socketColor1'] + $this->curTpl['socketColor2'] + $this->curTpl['socketColor3'] + (isset($enhance['s']) ? 1 : 0); + while ($sockCount > count($enhance['g'])) + $enhance['g'][] = 0; - $enhance['gems'] = array_reverse($enhance['gems']); + $enhance['g'] = array_reverse($enhance['g']); $hasMatch = 1; // fill native sockets @@ -681,7 +679,7 @@ class ItemList extends BaseType if (($this->curTpl['socketColor'.$j] & (1 << $i))) $colorId = $i; - $pop = array_pop($enhance['gems']); + $pop = array_pop($enhance['g']); $col = $pop ? 1 : 0; $hasMatch &= $pop ? (($gems[$pop]['colorMask'] & (1 << $colorId)) ? 1 : 0) : 0; $icon = $pop ? sprintf(Util::$bgImagePath['tiny'], STATIC_URL, strtolower($gems[$pop]['iconString'])) : null; @@ -694,9 +692,9 @@ class ItemList extends BaseType } // fill extra socket - if (isset($enhance['sock'])) + if (isset($enhance['s'])) { - $pop = array_pop($enhance['gems']); + $pop = array_pop($enhance['g']); $col = $pop ? 1 : 0; $icon = $pop ? sprintf(Util::$bgImagePath['tiny'], STATIC_URL, strtolower($gems[$pop]['iconString'])) : null; $text = $pop ? Util::localizedString($gems[$pop], 'text') : Lang::$item['socket'][-1]; @@ -712,7 +710,7 @@ class ItemList extends BaseType if ($this->curTpl['socketBonus']) { $sbonus = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantment WHERE Id = ?d', $this->curTpl['socketBonus']); - $x .= ''.Lang::$item['socketBonus'].Lang::$colon.Util::localizedString($sbonus, 'text').'
'; + $x .= ''.Lang::$item['socketBonus'].Lang::$main['colon'].Util::localizedString($sbonus, 'text').'
'; } // durability @@ -721,12 +719,12 @@ class ItemList extends BaseType // required classes if ($classes = Lang::getClassString($this->curTpl['requiredClass'])) - $x .= Lang::$game['classes'].Lang::$colon.$classes.'
'; + $x .= Lang::$game['classes'].Lang::$main['colon'].$classes.'
'; // required races if ($races = Lang::getRaceString($this->curTpl['requiredRace'])) if ($races != Lang::$game['ra'][0]) // not "both", but display combinations like: troll, dwarf - $x .= Lang::$game['races'].Lang::$colon.$races.'
'; + $x .= Lang::$game['races'].Lang::$main['colon'].$races.'
'; // required honorRank (not used anymore) if ($rhr = $this->curTpl['requiredHonorRank']) @@ -920,7 +918,7 @@ class ItemList extends BaseType $craftItem = new ItemList(array(['i.id', (int)$craftSpell->curTpl['effect1CreateItemId']])); if (!$craftItem->error) { - if ($itemTT = $craftItem->renderTooltip(null, $interactive, $this->id)) + if ($itemTT = $craftItem->renderTooltip($interactive, $this->id)) $xCraft .= '

'.$itemTT.'
'; $reagentItems = []; @@ -970,7 +968,7 @@ class ItemList extends BaseType $x .= implode('
', $xMisc); if ($sp = $this->curTpl['sellPrice']) - $x .= '
'.Lang::$item['sellPrice'].Lang::$colon.Util::formatMoney($sp).'
'; + $x .= '
'.Lang::$item['sellPrice'].Lang::$main['colon'].Util::formatMoney($sp).'
'; if (!$subOf) $x .= ''; @@ -1078,65 +1076,75 @@ class ItemList extends BaseType public function extendJsonStats() { - $onUseStats = []; + $enchantments = []; // buffer Ids for lookup id => src; src>0: socketBonus; src<0: gemEnchant - // convert ItemMods - $this->itemMods[$this->id] = []; - for ($h = 1; $h <= 10; $h++) + foreach ($this->iterate() as $__) { - $mod = $this->curTpl['statType'.$h]; - $val = $this->curTpl['statValue'.$h]; - if (!$mod || !$val) - continue; + $this->itemMods[$this->id] = []; - @$this->itemMods[$this->id][$mod] += $val; + foreach (Util::$itemMods as $mod) + if (!empty($this->curTpl[$mod])) + @$this->itemMods[$this->id][$mod] += $this->curTpl[$mod]; + + // fetch and add socketbonusstats + if (@$this->json[$this->id]['socketbonus'] > 0) + $enchantments[$this->json[$this->id]['socketbonus']][] = $this->id; + + + // Item is a gem (don't mix with sockets) + if ($geId = $this->curTpl['gemEnchantmentId']) + $enchantments[$geId][] = -$this->id; } + if ($enchantments) + { + $parsed = Util::parseItemEnchantment(array_keys($enchantments)); + + // and merge enchantments back + foreach ($parsed as $eId => $stats) + { + foreach ($enchantments[$eId] as $item) + { + if ($item > 0) // apply socketBonus + $this->json[$item]['socketbonusstat'] = $stats; + else /* if ($item < 0) */ + foreach ($stats as $mod => $qty) // apply gemEnchantment + @$this->json[-$item][$mod] += $qty; + } + } + } + + foreach ($this->json as $item => $json) + foreach ($json as $k => $v) + if (!$v && !in_array($k, ['classs', 'subclass', 'quality', 'side'])) + unset($this->json[$item][$k]); + } + + public function getOnUseStats() + { + $onUseStats = []; + // convert Spells - $equipSpells = []; + $useSpells = []; for ($h = 1; $h <= 5; $h++) { if ($this->curTpl['spellId'.$h] <= 0) continue; - // armor & weapons only onEquip && consumables only onUse - if (!(in_array($this->curTpl['class'], [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]) && $this->curTpl['spellTrigger'.$h] == 1) && - !( $this->curTpl['class'] == ITEM_CLASS_CONSUMABLE && $this->curTpl['spellTrigger'.$h] == 0)) + if ($this->curTpl['class'] != ITEM_CLASS_CONSUMABLE || $this->curTpl['spellTrigger'.$h]) continue; - $equipSpells[] = $this->curTpl['spellId'.$h]; + $useSpells[] = $this->curTpl['spellId'.$h]; } - if ($equipSpells) + if ($useSpells) { - $eqpSplList = new SpellList(array(['s.id', $equipSpells])); + $eqpSplList = new SpellList(array(['s.id', $useSpells])); foreach ($eqpSplList->getStatGain() as $stat) - { foreach ($stat as $mId => $qty) - { - @$this->itemMods[$this->id][$mId] += $qty; - if ($this->curTpl['class'] == ITEM_CLASS_CONSUMABLE) - @$onUseStats[$mId] += $qty; - } - } + @$onUseStats[$mId] += $qty; } - // fetch and add socketbonusstats - if (@$this->json[$this->id]['socketbonus'] > 0) - $this->json[$this->id]['socketbonusstat'] = Util::parseItemEnchantment($this->json[$this->id]['socketbonus']); - - // Item is a gem (don't mix with sockets) - if ($geId = $this->curTpl['gemEnchantmentId']) - { - $gemStats = Util::parseItemEnchantment($geId); - foreach ($gemStats as $mod => $qty) - @$this->json[$this->id][$mod] += $qty; - } - - foreach ($this->json[$this->id] as $k => $v) - if (!isset($v) || $v === "false" || (!in_array($k, ['classs', 'subclass', 'quality', 'side']) && $v == "0")) - unset($this->json[$this->id][$k]); - return $onUseStats; } @@ -1296,7 +1304,7 @@ class ItemList extends BaseType { $stats = Util::parseItemEnchantment($enchId, false, $misc); $this->rndEnchIds[$enchId] = array( - 'text' => $misc['name'], + 'text' => $misc[$enchId]['name'], 'stats' => $stats ); } @@ -1398,7 +1406,7 @@ class ItemList extends BaseType // clear zero-values afterwards foreach ($json as $k => $v) - if (!isset($v) || $v === "false" || (!in_array($k, ['classs', 'subclass', 'quality', 'side']) && $v == "0")) + if (!$v && !in_array($k, ['classs', 'subclass', 'quality', 'side'])) unset($json[$k]); $this->json[$json['id']] = $json; @@ -1618,7 +1626,8 @@ class ItemListFilter extends Filter if ($select) { - $this->extraOpts['is']['s'][] = ', ('.implode(' + ', $select).') / '.$wtSum.' AS score'; + $this->extraOpts['is']['s'][] = ', IF(is.id IS NULL, 0, ('.implode(' + ', $select).') / '.$wtSum.') AS score'; + $this->extraOpts['is']['o'][] = 'score DESC'; $this->extraOpts['i']['o'][] = null; // remove default ordering } else diff --git a/includes/utilities.php b/includes/utilities.php index bd54c63a..920c8c87 100644 --- a/includes/utilities.php +++ b/includes/utilities.php @@ -1090,103 +1090,107 @@ class Util // 8 => TYPE_PRISMATIC_SOCKET Extra Sockets AmountX as socketCount (ignore) public static function parseItemEnchantment($ench, $raw = false, &$misc = null) { - $enchant = []; - if (is_numeric($ench)) - $enchant = DB::Aowow()->selectRow('SELECT *, Id AS ARRAY_KEY FROM ?_itemenchantment WHERE Id = ?d', $ench); - else if (is_array($ench)) - $enchant = $ench; - - if (!$enchant) + if (!$ench) return []; - $misc = array( - 'name' => self::localizedString($enchant, 'text'), - 'text' => array( - 'text_loc0' => $enchant['text_loc0'], - 'text_loc2' => $enchant['text_loc2'], - 'text_loc3' => $enchant['text_loc3'], - 'text_loc6' => $enchant['text_loc6'], - 'text_loc8' => $enchant['text_loc8'] - ) - ); + if (is_numeric($ench)) + $ench = [$ench]; - if ($enchant['skillLine'] > 0) - $misc['reqskill'] = $enchant['skillLine']; + if (!is_array($ench)) + return []; - if ($enchant['skillLevel'] > 0) - $misc['reqskillrank'] = $enchant['skillLevel']; + $enchants = DB::Aowow()->select('SELECT *, Id AS ARRAY_KEY FROM ?_itemenchantment WHERE id IN (?a)', $ench); + if (!$enchants) + return []; - if ($enchant['requiredLevel'] > 0) - $misc['reqlevel'] = $enchant['requiredLevel']; - - // parse stats - $jsonStats = []; - for ($h = 1; $h <= 3; $h++) + $result = []; + foreach ($enchants as $eId => $e) { - $obj = (int)$enchant['object'.$h]; - $val = (int)$enchant['amount'.$h]; + $misc[$eId] = array( + 'name' => self::localizedString($e, 'text'), + 'text' => array( + 'text_loc0' => $e['text_loc0'], + 'text_loc2' => $e['text_loc2'], + 'text_loc3' => $e['text_loc3'], + 'text_loc6' => $e['text_loc6'], + 'text_loc8' => $e['text_loc8'] + ) + ); - switch ($enchant['type'.$h]) + if ($e['skillLine'] > 0) + $misc[$eId]['reqskill'] = $e['skillLine']; + + if ($e['skillLevel'] > 0) + $misc[$eId]['reqskillrank'] = $e['skillLevel']; + + if ($e['requiredLevel'] > 0) + $misc[$eId]['reqlevel'] = $e['requiredLevel']; + + // parse stats + $jsonStats = []; + for ($h = 1; $h <= 3; $h++) { - case 2: - @$jsonStats[ITEM_MOD_WEAPON_DMG] += $val; - break; - case 3: - case 7: - $spl = new SpellList(array(['s.id', $obj])); - if ($spl->error) + $obj = (int)$e['object'.$h]; + $val = (int)$e['amount'.$h]; + + switch ($e['type'.$h]) + { + case 2: + @$jsonStats[ITEM_MOD_WEAPON_DMG] += $val; break; + case 3: + case 7: + $spl = new SpellList(array(['s.id', $obj])); + if ($spl->error) + break; - $gains = $spl->getStatGain(); + $gains = $spl->getStatGain(); - foreach ($gains as $gain) - foreach ($gain as $k => $v) // array_merge screws up somehow... - @$jsonStats[$k] += $v; - break; - case 4: - switch ($obj) - { - case 0: // Physical - @$jsonStats[ITEM_MOD_ARMOR] += $val; - break; - case 1: // Holy - @$jsonStats[ITEM_MOD_HOLY_RESISTANCE] += $val; - break; - case 2: // Fire - @$jsonStats[ITEM_MOD_FIRE_RESISTANCE] += $val; - break; - case 3: // Nature - @$jsonStats[ITEM_MOD_NATURE_RESISTANCE] += $val; - break; - case 4: // Frost - @$jsonStats[ITEM_MOD_FROST_RESISTANCE] += $val; - break; - case 5: // Shadow - @$jsonStats[ITEM_MOD_SHADOW_RESISTANCE] += $val; - break; - case 6: // Arcane - @$jsonStats[ITEM_MOD_ARCANE_RESISTANCE] += $val; - break; - } - break; - case 5: - @$jsonStats[$obj] += $val; - break; + foreach ($gains as $gain) + foreach ($gain as $k => $v) // array_merge screws up somehow... + @$jsonStats[$k] += $v; + break; + case 4: + switch ($obj) + { + case 0: // Physical + @$jsonStats[ITEM_MOD_ARMOR] += $val; + break; + case 1: // Holy + @$jsonStats[ITEM_MOD_HOLY_RESISTANCE] += $val; + break; + case 2: // Fire + @$jsonStats[ITEM_MOD_FIRE_RESISTANCE] += $val; + break; + case 3: // Nature + @$jsonStats[ITEM_MOD_NATURE_RESISTANCE] += $val; + break; + case 4: // Frost + @$jsonStats[ITEM_MOD_FROST_RESISTANCE] += $val; + break; + case 5: // Shadow + @$jsonStats[ITEM_MOD_SHADOW_RESISTANCE] += $val; + break; + case 6: // Arcane + @$jsonStats[ITEM_MOD_ARCANE_RESISTANCE] += $val; + break; + } + break; + case 5: + @$jsonStats[$obj] += $val; + break; + } } + + if ($raw) + $result[$eId] = $jsonStats; + else + foreach ($jsonStats as $k => $v) // check if we use these mods + if ($str = Util::$itemMods[$k]) + $result[$eId][$str] = $v; } - if ($raw) - return $jsonStats; - - // check if we use these mods - $return = []; - foreach ($jsonStats as $k => $v) - { - if ($str = Util::$itemMods[$k]) - $return[$str] = $v; - } - - return $return; + return $result; } // default ucFirst doesn't convert UTF-8 chars diff --git a/pages/achievement.php b/pages/achievement.php index db7231b8..504c9240 100644 --- a/pages/achievement.php +++ b/pages/achievement.php @@ -77,7 +77,7 @@ class AchievementPage extends GenericPage /* Infobox */ /***********/ - $infobox = []; + $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); // points if ($_ = $this->subject->getField('points')) @@ -397,7 +397,7 @@ class AchievementPage extends GenericPage protected function generateTooltip($asError = false) { if ($asError) - die('$WowheadPower.registerAchievement('.$this->typeId.', '.User::$localeId.', {});'); + return '$WowheadPower.registerAchievement('.$this->typeId.', '.User::$localeId.', {});'; $x = '$WowheadPower.registerAchievement('.$this->typeId.', '.User::$localeId.",{\n"; $x .= "\tname_".User::$localeString.": '".Util::jsEscape($this->subject->getField('name', true))."',\n"; diff --git a/pages/class.php b/pages/class.php index 1a3cb56b..c3856b71 100644 --- a/pages/class.php +++ b/pages/class.php @@ -43,7 +43,7 @@ class ClassPage extends GenericPage protected function generateContent() { - $infobox = []; + $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); $_mask = 1 << ($this->typeId - 1); $tcClassId = [null, 8, 3, 1, 5, 4, 9, 6, 2, 7, null, 0]; // see TalentCalc.js diff --git a/pages/currency.php b/pages/currency.php index 1bfddc8a..9e731749 100644 --- a/pages/currency.php +++ b/pages/currency.php @@ -49,17 +49,18 @@ class CurrencyPage extends GenericPage /* Infobox */ /**********/ - $infobox = ''; + $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); + if ($this->typeId == 103) // Arena Points - $infobox = '[ul][li]'.Lang::$currency['cap'].Lang::$main['colon'].'10\'000[/li][/ul]'; + $infobox[] = Lang::$currency['cap'].Lang::$main['colon'].'10\'000'; else if ($this->typeId == 104) // Honor - $infobox = '[ul][li]'.Lang::$currency['cap'].Lang::$main['colon'].'75\'000[/li][/ul]'; + $infobox[] = Lang::$currency['cap'].Lang::$main['colon'].'75\'000'; /****************/ /* Main Content */ /****************/ - $this->infobox = $infobox; + $this->infobox = '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]'; $this->name = $this->subject->getField('name', true); $this->headIcons = $this->typeId == 104 ? ['inv_bannerpvp_02', 'inv_bannerpvp_01'] : [$this->subject->getField('iconString')]; $this->redButtons = array( @@ -73,26 +74,28 @@ class CurrencyPage extends GenericPage if (!$_isSpecial) { - include 'includes/loot.class.php'; - // tabs: this currency is contained in.. - $lootTabs = Loot::getByItem($_itemId); - $this->extendGlobalData(Loot::$jsGlobals); + $lootTabs = new Loot(); - foreach ($lootTabs as $tab) + if ($lootTabs->getByItem($_itemId)) { - $this->lvData[] = array( - 'file' => $tab[0], - 'data' => $tab[1], - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => $tab[2], - 'id' => $tab[3], - 'extraCols' => $tab[4] ? '$['.implode(', ', array_unique($tab[4])).']' : null, - 'hiddenCols' => $tab[5] ? '$['.implode(', ', array_unique($tab[5])).']' : null, - 'visibleCols' => $tab[6] ? '$'. json_encode( array_unique($tab[6])) : null - ] - ); + $this->extendGlobalData($lootTabs->jsGlobals); + + foreach ($lootTabs->iterate() as $tab) + { + $this->lvData[] = array( + 'file' => $tab[0], + 'data' => $tab[1], + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => $tab[2], + 'id' => $tab[3], + 'extraCols' => $tab[4] ? '$['.implode(', ', array_unique($tab[4])).']' : null, + 'hiddenCols' => $tab[5] ? '$['.implode(', ', array_unique($tab[5])).']' : null, + 'visibleCols' => $tab[6] ? '$'. json_encode( array_unique($tab[6])) : null + ] + ); + } } // tab: sold by diff --git a/pages/event.php b/pages/event.php index f9678c5c..15c0f5e5 100644 --- a/pages/event.php +++ b/pages/event.php @@ -65,7 +65,7 @@ class EventPage extends GenericPage /* Infobox */ /***********/ - $this->infobox = []; + $this->infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); // boss if ($_ = $this->subject->getField('bossCreature')) diff --git a/pages/faction.php b/pages/faction.php index d213dc32..bc6b9350 100644 --- a/pages/faction.php +++ b/pages/faction.php @@ -51,7 +51,7 @@ class FactionPage extends GenericPage /***********/ /* Infobox */ /***********/ - $infobox = []; + $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); // Quartermaster if any if ($ids = $this->subject->getField('qmNpcIds')) diff --git a/pages/item.php b/pages/item.php index 76eb8af9..938c7155 100644 --- a/pages/item.php +++ b/pages/item.php @@ -4,122 +4,977 @@ if (!defined('AOWOW_REVISION')) die('illegal access'); -require 'includes/community.class.php'; - -$_id = intVal($pageParam); -$_path = [0, 0]; -$_visSlots = array( - INVTYPE_HEAD, INVTYPE_SHOULDERS, INVTYPE_BODY, INVTYPE_CHEST, INVTYPE_WAIST, INVTYPE_LEGS, INVTYPE_FEET, INVTYPE_WRISTS, - INVTYPE_HANDS, INVTYPE_WEAPON, INVTYPE_SHIELD, INVTYPE_RANGED, INVTYPE_CLOAK, INVTYPE_2HWEAPON, INVTYPE_TABARD, INVTYPE_ROBE, - INVTYPE_WEAPONMAINHAND, INVTYPE_WEAPONOFFHAND, INVTYPE_HOLDABLE, INVTYPE_THROWN, INVTYPE_RANGEDRIGHT -); - -$cacheKeyPage = implode('_', [CACHETYPE_PAGE, TYPE_ITEM, $_id, -1, User::$localeId]); - -// AowowPower-request -if (isset($_GET['power'])) +// menuId 0: Item g_initPath() +// tabId 0: Database g_initHeader() +class ItemPage extends genericPage { - header('Content-type: application/x-javascript; charsetUTF-8'); + use DetailPage; - Util::powerUseLocale(@$_GET['domain']); + protected $type = TYPE_ITEM; + protected $typeId = 0; + protected $tpl = 'item'; + protected $path = [0, 0]; + protected $tabId = 0; + protected $mode = CACHETYPE_PAGE; + protected $enhancedTT = []; + protected $js = array( + 'swfobject.js', // view in 3d, ok + 'profile.js', // item upgrade search, also ok + 'filters.js' // lolwut? + ); - $enh = []; - $itemString = $_id; + public function __construct($__, $param) + { + parent::__construct(); - if (isset($_GET['rand'])) - { - $enh['rand'] = $_GET['rand']; - $itemString .= 'r'.$_GET['rand']; - } - if (isset($_GET['ench'])) - { - $enh['ench'] = $_GET['ench']; - $itemString .= 'e'.$_GET['ench']; - } - if (isset($_GET['gems'])) - { - $enh['gems'] = explode(':', $_GET['gems']); - $itemString .= 'g'.str_replace(':', ',', $_GET['gems']); - } - if (isset($_GET['sock'])) - { - $enh['sock'] = $_GET['sock']; - $itemString .= 's'; + $conditions = [['i.id', intVal($param)]]; + + $this->typeId = intVal($param); + + if ($this->mode == CACHETYPE_TOOLTIP) + { + // temp locale + if (isset($_GET['domain'])) + Util::powerUseLocale($_GET['domain']); + + if (isset($_GET['rand'])) + $this->enhancedTT['r'] = $_GET['rand']; + if (isset($_GET['ench'])) + $this->enhancedTT['e'] = $_GET['ench']; + if (isset($_GET['gems'])) + $this->enhancedTT['g'] = explode(':', $_GET['gems']); + if (isset($_GET['sock'])) + $this->enhancedTT['s'] = ''; + } + else if ($this->mode == CACHETYPE_XML) + { + // temp locale + if (isset($_GET['domain'])) + Util::powerUseLocale($_GET['domain']); + + // allow lookup by name for xml + if (!is_numeric($param)) + $conditions = [['name_loc'.User::$localeId, utf8_encode(urldecode($param))]]; + } + + $this->subject = new ItemList($conditions); + if ($this->subject->error) + $this->notFound(Lang::$game['item']); + + if (!is_numeric($param)) + $this->typeId = $this->subject->id; + + $this->name = $this->subject->getField('name', true); + + $jsg = $this->subject->getJSGlobals(GLOBALINFO_EXTRA | GLOBALINFO_SELF, $extra); + $this->extendGlobalData($jsg, $extra); } - $cacheKeyTooltip = implode('_', [CACHETYPE_TOOLTIP, TYPE_ITEM, str_replace(':', ',', $itemString), -1, User::$localeId]); - - // output json for tooltips - if (!$smarty->loadCache($cacheKeyTooltip, $x)) + protected function generatePath() { - $item = new ItemList(array(['i.id', $_id])); - if ($item->error) - die('$WowheadPower.registerItem(\''.$itemString.'\', '.User::$localeId.', {})'); + $_class = $this->subject->getField('class'); + $_subClass = $this->subject->getField('subClass'); - $item->renderTooltip($enh); - $x .= '$WowheadPower.registerItem(\''.$itemString.'\', '.User::$localeId.", {\n"; - $x .= "\tname_".User::$localeString.": '".Util::jsEscape($item->getField('name', true))."',\n"; - $x .= "\tquality: ".$item->getField('quality').",\n"; - $x .= "\ticon: '".urlencode($item->getField('iconString'))."',\n"; - $x .= "\ttooltip_".User::$localeString.": '".Util::jsEscape($item->tooltip[$_id])."'\n"; + if (in_array($_class, [ITEM_CLASS_REAGENT, ITEM_CLASS_GENERIC, ITEM_CLASS_PERMANENT])) + { + $this->path[] = ITEM_CLASS_MISC; // misc. + + if ($_class == ITEM_CLASS_REAGENT) // reagent + $this->path[] = 1; + else // other + $this->path[] = 4; + } + else + { + $this->path[] = $_class; + + if (!in_array($_class, [ITEM_CLASS_MONEY, ITEM_CLASS_QUEST, ITEM_CLASS_KEY])) + $this->path[] = $_subClass; + + if ($_class == ITEM_CLASS_ARMOR && in_array($_subClass, [1, 2, 3, 4])) + { + if ($_ = $this->subject->getField('slot')); + $this->path[] = $_; + } + else if (($_class == ITEM_CLASS_CONSUMABLE && $_subClass == 2) || $_class == ITEM_CLASS_GLYPH) + $this->path[] = $this->subject->getField('subSubClass'); + } + } + + protected function generateTitle() + { + array_unshift($this->title, $this->subject->getField('name', true), Util::ucFirst(Lang::$game['item'])); + } + + protected function generateContent() + { + $this->addJS('?data=weight-presets&locale='.User::$localeId.'&t='.$_SESSION['dataKey']); + + $_flags = $this->subject->getField('flags'); + $_slot = $this->subject->getField('slot'); + $_class = $this->subject->getField('class'); + $_subClass = $this->subject->getField('subClass'); + $_bagFamily = $this->subject->getField('bagFamily'); + $_model = $this->subject->getField('displayId'); + $_visSlots = array( + INVTYPE_HEAD, INVTYPE_SHOULDERS, INVTYPE_BODY, INVTYPE_CHEST, INVTYPE_WAIST, INVTYPE_LEGS, INVTYPE_FEET, INVTYPE_WRISTS, + INVTYPE_HANDS, INVTYPE_WEAPON, INVTYPE_SHIELD, INVTYPE_RANGED, INVTYPE_CLOAK, INVTYPE_2HWEAPON, INVTYPE_TABARD, INVTYPE_ROBE, + INVTYPE_WEAPONMAINHAND, INVTYPE_WEAPONOFFHAND, INVTYPE_HOLDABLE, INVTYPE_THROWN, INVTYPE_RANGEDRIGHT + ); + + /***********/ + /* Infobox */ + /***********/ + + $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); + + // itemlevel + if (in_array($_class, [ITEM_CLASS_ARMOR, ITEM_CLASS_WEAPON, ITEM_CLASS_AMMUNITION]) || $this->subject->getField('gemEnchantmentId')) + $infobox[] = Lang::$game['level'].Lang::$main['colon'].$this->subject->getField('itemLevel'); + + // account-wide + if ($_flags & ITEM_FLAG_ACCOUNTBOUND) + $infobox[] = Lang::$item['accountWide']; + + // side + if ($si = $this->subject->json[$this->typeId]['side']) + if ($si != 3) + $infobox[] = Lang::$main['side'].Lang::$main['colon'].'[span class=icon-'.($si == 1 ? 'alliance' : 'horde').']'.Lang::$game['si'][$si].'[/span]'; + + // consumable / not consumable + if (!$_slot) + { + $hasUse = false; + for ($i = 1; $i < 6; $i++) + { + if ($this->subject->getField('spellId'.$i) <= 0 || in_array($this->subject->getField('spellTrigger'.$i), [1, 2])) + continue; + + $hasUse = true; + + if ($this->subject->getField('spellCharges'.$i) >= 0) + continue; + + $tt = '[tooltip=tooltip_consumedonuse]'.Lang::$item['consumable'].'[/tooltip]'; + break; + } + + if ($hasUse) + $infobox[] = isset($tt) ? $tt : '[tooltip=tooltip_notconsumedonuse]'.Lang::$item['nonConsumable'].'[/tooltip]'; + } + + // related holiday + if ($hId = $this->subject->getField('holidayId')) + if ($hName = DB::Aowow()->selectRow('SELECT * FROM ?_holidays WHERE id = ?d', $hId)) + $infobox[] = Lang::$game['eventShort'].Lang::$main['colon'].'[url=?event='.$hId.']'.Util::localizedString($hName, 'name').'[/url]'; + + // tool + if ($tId = $this->subject->getField('totemCategory')) + if ($tName = DB::Aowow()->selectRow('SELECT * FROM ?_totemCategory WHERE id = ?d', $tId)) + $infobox[] = Lang::$item['tool'].Lang::$main['colon'].'[url=?items&filter=cr=91;crs='.$tId.';crv=0]'.Util::localizedString($tName, 'name').'[/url]'; + + // extendedCost + if ($_ = @$this->subject->getExtendedCost([], $_reqRating)[$this->subject->id]) + { + $each = $this->subject->getField('stackable') > 1 ? '[color=q0] ('.Lang::$item['each'].')[/color]' : null; + $handled = []; + $costList = []; + foreach ($_ as $npcId => $data) + { + $tokens = []; + $currency = []; + + if (!is_array($data)) + continue; + + foreach ($data as $c => $qty) + { + if (is_string($c)) + { + unset($data[$c]); // unset miscData to prevent having two vendors /w the same cost being cached, because of different stock or rating-requirements + continue; + } + + if ($c < 0) // currency items (and honor or arena) + $currency[] = -$c.','.$qty; + else if ($c > 0) // plain items (item1,count1,item2,count2,...) + $tokens[$c] = $c.','.$qty; + } + + // display every cost-combination only once + if (in_array(md5(serialize($data)), $handled)) + continue; + + $handled[] = md5(serialize($data)); + + $cost = isset($data[0]) ? '[money='.$data[0] : '[money'; + + if ($tokens) + $cost .= ' items='.implode(',', $tokens); + + if ($currency) + $cost .= ' currency='.implode(',', $currency); + + $cost .= ']'; + + $costList[] = $cost; + } + + if (count($costList) == 1) + $infobox[] = Lang::$item['cost'].Lang::$main['colon'].$costList[0].$each; + else if (count($costList) > 1) + $infobox[] = Lang::$item['cost'].$each.Lang::$main['colon'].'[ul][li]'.implode('[/li][li]', $costList).'[/li][/ul]'; + + if ($_reqRating) + { + $res = []; + $i = 0; + $len = 0; + $parts = explode(' ', sprintf(Lang::$item['reqRating'], $_reqRating)); + foreach ($parts as $p) + { + $res[$i][] = $p; + $len += mb_strlen($p); + + if ($len < 30) + continue; + + $len = 0; + $i++; + } + foreach ($res as &$r) + $r = implode(' ', $r); + + $infobox[] = implode('[br]', $res); + } + } + + // repair cost + if ($_ = $this->subject->getField('repairPrice')) + $infobox[] = Lang::$item['repairCost'].Lang::$main['colon'].'[money='.$_.']'; + + // avg auction buyout + if (in_array($this->subject->getField('bonding'), [0, 2, 3])) + if ($_ = Util::getBuyoutForItem($this->typeId)) + $infobox[] = '[tooltip=tooltip_buyoutprice]'.Lang::$item['buyout.'].'[/tooltip]'.Lang::$main['colon'].'[money='.$_.']'.$each; + + // avg money contained + if ($_flags & ITEM_FLAG_OPENABLE) + if ($_ = intVal(($this->subject->getField('minMoneyLoot') + $this->subject->getField('maxMoneyLoot')) / 2)) + $infobox[] = Lang::$item['worth'].Lang::$main['colon'].'[tooltip=tooltip_avgmoneycontained][money='.$_.'][/tooltip]'; + + // if it goes into a slot it may be disenchanted + if ($_slot && $_class != ITEM_CLASS_CONTAINER) + { + if ($this->subject->getField('disenchantId')) + { + $_ = $this->subject->getField('requiredDisenchantSkill'); + if ($_ < 1) // these are some items, that never went live .. extremely rough emulation here + $_ = intVal($this->subject->getField('itemLevel') / 7.5) * 25; + + $infobox[] = Lang::$item['disenchantable'].' ([tooltip=tooltip_reqenchanting]'.$_.'[/tooltip])'; + } + else + $infobox[] = Lang::$item['cantDisenchant']; + } + + if (($_flags & ITEM_FLAG_MILLABLE) && $this->subject->getField('requiredSkill') == 773) + $infobox[] = Lang::$item['millable'].' ([tooltip=tooltip_reqinscription]'.$this->subject->getField('requiredSkillRank').'[/tooltip])'; + + if (($_flags & ITEM_FLAG_PROSPECTABLE) && $this->subject->getField('requiredSkill') == 755) + $infobox[] = Lang::$item['prospectable'].' ([tooltip=tooltip_reqjewelcrafting]'.$this->subject->getField('requiredSkillRank').'[/tooltip])'; + + if ($_flags & ITEM_FLAG_DEPRECATED) + $infobox[] = '[tooltip=tooltip_deprecated]'.Lang::$item['deprecated'].'[/tooltip]'; + + if ($_flags & ITEM_FLAG_NO_EQUIPCD) + $infobox[] = '[tooltip=tooltip_noequipcooldown]'.Lang::$item['noEquipCD'].'[/tooltip]'; + + if ($_flags & ITEM_FLAG_PARTYLOOT) + $infobox[] = '[tooltip=tooltip_partyloot]'.Lang::$item['partyLoot'].'[/tooltip]'; + + if ($_flags & ITEM_FLAG_REFUNDABLE) + $infobox[] = '[tooltip=tooltip_refundable]'.Lang::$item['refundable'].'[/tooltip]'; + + if ($_flags & ITEM_FLAG_SMARTLOOT) + $infobox[] = '[tooltip=tooltip_smartloot]'.Lang::$item['smartLoot'].'[/tooltip]'; + + if ($_flags & ITEM_FLAG_INDESTRUCTIBLE) + $infobox[] = Lang::$item['indestructible']; + + if ($_flags & ITEM_FLAG_USABLE_ARENA) + $infobox[] = Lang::$item['useInArena']; + + if ($_flags & ITEM_FLAG_USABLE_SHAPED) + $infobox[] = Lang::$item['useInShape']; + + // cant roll need + if ($this->subject->getField('flagsExtra') & 0x0100) + $infobox[] = '[tooltip=tooltip_cannotrollneed]'.Lang::$item['noNeedRoll'].'[/tooltip]'; + + // fits into keyring + if ($_bagFamily & 0x0100) + $infobox[] = Lang::$item['atKeyring']; + + /****************/ + /* Main Content */ + /****************/ + + $_cu = in_array($_class, [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]) || $this->subject->getField('gemEnchantmentId'); + + $this->headIcons = [$this->subject->getField('iconString'), $this->subject->getField('stackable')]; + $this->infobox = $infobox ? '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]' : null; + $this->tooltip = $this->subject->renderTooltip(true); + $this->redButtons = array( + BUTTON_WOWHEAD => true, + BUTTON_LINKS => ['color' => 'ff'.Util::$rarityColorStings[$this->subject->getField('quality')], 'linkId' => 'item:'.$this->typeId.':0:0:0:0:0:0:0:0'], + BUTTON_VIEW3D => in_array($_slot, $_visSlots) && $_model ? ['displayId' => $this->subject->getField('displayId'), 'slot' => $_slot, 'type' => TYPE_ITEM, 'typeId' => $this->typeId] : false, + BUTTON_COMPARE => $_cu, // bool required + BUTTON_EQUIP => in_array($_class, [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]), + BUTTON_UPGRADE => $_cu ? ['class' => $_class, 'slot' => $_slot] : false + ); + + // availablility + $this->disabled = false; // todo (med): get itemSources (which are not yet in DB :x) or + + // pageText + if ($next = $this->subject->getField('pageTextId')) + { + $this->addJS('Book.js'); + $this->addCSS(['path' => 'Book.css']); + + while ($next) + { + $row = DB::Aowow()->selectRow('SELECT *, text as Text_loc0 FROM page_text pt LEFT JOIN locales_page_text lpt ON pt.entry = lpt.entry WHERE pt.entry = ?d', $next); + $next = $row['next_page']; + $this->pageText[] = Util::parseHtmlText(Util::localizedString($row, 'Text')); + } + } + + // subItems + $this->subject->initSubItems(); + if (!empty($this->subject->subItems[$this->typeId])) + { + uaSort($this->subject->subItems[$this->typeId], function($a, $b) { return strcmp($a['name'], $b['name']); }); + $this->subItems = array( + 'data' => array_values($this->subject->subItems[$this->typeId]), + 'quality' => $this->subject->getField('quality') + ); + + // merge identical stats and names for normal users (e.g. spellPower of a specific school became generel spellPower with 3.0) + if (!User::isInGroup(U_GROUP_STAFF)) + { + for ($i = 1; $i < count($this->subItems['data']); $i++) + { + $prev = &$this->subItems['data'][$i - 1]; + $cur = &$this->subItems['data'][$i]; + if ($prev['jsonequip'] == $cur['jsonequip'] && $prev['name'] == $cur['name']) + { + $prev['chance'] += $cur['chance']; + array_splice($this->subItems['data'], $i , 1); + $i = 1; + } + } + } + } + + // factionchange-equivalent + if ($pendant = DB::Aowow()->selectCell('SELECT IF(horde_id = ?d, alliance_id, -horde_id) FROM player_factionchange_items WHERE alliance_id = ?d OR horde_id = ?d', $this->typeId, $this->typeId, $this->typeId)) + { + $altItem = new ItemList(array(['id', abs($pendant)])); + if (!$altItem->error) + { + $this->transfer = sprintf( + Lang::$item['_transfer'], + $altItem->id, + $altItem->getField('quality'), + $altItem->getField('iconString'), + $altItem->getField('name', true), + $pendant > 0 ? 'alliance' : 'horde', + $pendant > 0 ? Lang::$game['si'][1] : Lang::$game['si'][2] + ); + } + } + + /**************/ + /* Extra Tabs */ + /**************/ + + // tabs: this item is contained in.. + $lootTabs = new Loot(); + if ($lootTabs->getByItem($this->typeId)) + { + $this->extendGlobalData($lootTabs->jsGlobals); + + foreach ($lootTabs->iterate() as $tab) + { + $this->lvData[] = array( + 'file' => $tab[0], + 'data' => $tab[1], + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => $tab[2], + 'id' => $tab[3], + 'extraCols' => $tab[4] ? '$['.implode(', ', array_unique($tab[4])).']' : null, + 'hiddenCols' => $tab[5] ? '$['.implode(', ', array_unique($tab[5])).']' : null, + 'visibleCols' => $tab[6] ? '$'. json_encode( array_unique($tab[6])) : null + ] + ); + } + } + + // tabs: this item contains.. + $sourceFor = array( + [LOOT_ITEM, $this->subject->id, '$LANG.tab_contains', 'contains', ['Listview.extraCols.percent'], [] , []], + [LOOT_PROSPECTING, $this->subject->id, '$LANG.tab_prospecting', 'prospecting', ['Listview.extraCols.percent'], ['side', 'slot', 'reqlevel'], []], + [LOOT_MILLING, $this->subject->id, '$LANG.tab_milling', 'milling', ['Listview.extraCols.percent'], ['side', 'slot', 'reqlevel'], []], + [LOOT_DISENCHANT, $this->subject->getField('disenchantId'), '$LANG.tab_disenchanting', 'disenchanting', ['Listview.extraCols.percent'], ['side', 'slot', 'reqlevel'], []] + ); + + $reqQuest = []; + foreach ($sourceFor as $sf) + { + $lootTab = new Loot(); + if ($lootTab->getByContainer($sf[0], $sf[1])) + { + $this->extendGlobalData($lootTab->jsGlobals); + + foreach ($lootTab->iterate() as $lv) + { + if (!$lv['quest']) + continue; + + $sf[4] = array_merge($sf[4], $lootTab->extraCols, ['Listview.extraCols.condition']); + + $reqQuest[$lv['id']] = 0; + + $lv['condition'][] = ['type' => TYPE_QUEST, 'typeId' => &$reqQuest[$lv['id']], 'status' => 1]; + } + + $this->lvData[] = array( + 'file' => 'item', + 'data' => $lootTab->getResult(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => $sf[2], + 'id' => $sf[3], + 'extraCols' => $sf[4] ? "$[".implode(', ', array_unique($sf[4]))."]" : null, + 'hiddenCols' => $sf[5] ? "$".json_encode($sf[5]) : null, + 'visibleCols' => $sf[6] ? '$'.json_encode($sf[6]) : null + ] + ); + } + } + + if ($reqIds = array_keys($reqQuest)) // apply quest-conditions as back-reference + { + $conditions = array( + 'OR', + ['reqSourceItemId1', $reqIds], ['reqSourceItemId2', $reqIds], + ['reqSourceItemId3', $reqIds], ['reqSourceItemId4', $reqIds], + ['reqItemId1', $reqIds], ['reqItemId2', $reqIds], ['reqItemId3', $reqIds], + ['reqItemId4', $reqIds], ['reqItemId5', $reqIds], ['reqItemId6', $reqIds] + ); + + $reqQuests = new QuestList($conditions); + $reqQuests->getJSGlobals(GLOBALINFO_SELF); + + foreach ($reqQuests->iterate() as $qId => $__) + { + if (empty($reqQuests->requires[$qId][TYPE_ITEM])) + continue; + + foreach ($reqIds as $rId) + if (in_array($rId, $reqQuests->requires[$qId][TYPE_ITEM])) + $reqQuest[$rId] = $reqQuests->id; + } + } + + // tab: container can contain + if ($this->subject->getField('slots') > 0) + { + $contains = new ItemList(array(['bagFamily', $_bagFamily, '&'], ['slots', 1, '<'], 0)); + if (!$contains->error) + { + $this->extendGlobalData($contains->getJSGlobals(GLOBALINFO_SELF)); + + $hCols = ['side']; + if (!$contains->hasSetFields(['slot'])) + $hCols[] = 'slot'; + + $this->lvData[] = array( + 'file' => 'item', + 'data' => $contains->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_cancontain', + 'id' => 'can-contain', + 'hiddenCols' => '$'.json_encode($hCols) + ] + ); + } + } + + // tab: can be contained in (except keys) + else if ($_bagFamily != 0x0100) + { + $contains = new ItemList(array(['bagFamily', $_bagFamily, '&'], ['slots', 0, '>'], 0)); + if (!$contains->error) + { + $this->extendGlobalData($contains->getJSGlobals(GLOBALINFO_SELF)); + + $this->lvData[] = array( + 'file' => 'item', + 'data' => $contains->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_canbeplacedin', + 'id' => 'can-be-placed-in', + 'hiddenCols' => "$['side']" + ] + ); + } + } + + // tab: criteria of + $conditions = array( + ['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM, ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM, ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM]], + ['ac.value1', $this->typeId] + ); + + $criteriaOf = new AchievementList($conditions); + if (!$criteriaOf->error) + { + $this->extendGlobalData($criteriaOf->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS)); + + $hCols = []; + if (!$criteriaOf->hasSetFields(['rewardIds'])) + $hCols = ['rewards']; + + $this->lvData[] = array( + 'file' => 'achievement', + 'data' => $criteriaOf->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_criteriaof', + 'id' => 'criteria-of', + 'visibleCols' => "$['category']", + 'hiddenCols' => '$'.json_encode($hCols) + ] + ); + } + + // tab: reagent for + $conditions = array( + 'OR', + ['reagent1', $this->typeId], ['reagent2', $this->typeId], ['reagent3', $this->typeId], ['reagent4', $this->typeId], + ['reagent5', $this->typeId], ['reagent6', $this->typeId], ['reagent7', $this->typeId], ['reagent8', $this->typeId] + ); + + $reagent = new SpellList($conditions); + if (!$reagent->error) + { + $this->extendGlobalData($reagent->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); + + $this->lvData[] = array( + 'file' => 'spell', + 'data' => $reagent->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_reagentfor', + 'id' => 'reagent-for', + 'visibleCols' => "$['reagents']" + ] + ); + } + + // tab: unlocks (object or item) + $lockIds = DB::Aowow()->selectCol( + 'SELECT id FROM ?_lock WHERE (type1 = 1 AND properties1 = ?d) OR + (type2 = 1 AND properties2 = ?d) OR (type3 = 1 AND properties3 = ?d) OR + (type4 = 1 AND properties4 = ?d) OR (type5 = 1 AND properties5 = ?d)', + $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId + ); + + if ($lockIds) + { + // objects + $lockedObj = new GameObjectList(array(['lockId', $lockIds])); + if (!$lockedObj->error) + { + $this->lvData[] = array( + 'file' => 'object', + 'data' => $lockedObj->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_unlocks', + 'id' => 'unlocks-object' + ] + ); + } + + // items (generally unused. It's the spell on the item, that unlocks stuff) + $lockedItm = new ItemList(array(['lockId', $lockIds])); + if (!$lockedItm->error) + { + $this->extendGlobalData($lockedItm->getJSGlobals(GLOBALINFO_SELF)); + + $this->lvData[] = array( + 'file' => 'item', + 'data' => $lockedItm->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_unlocks', + 'id' => 'unlocks-item' + ] + ); + } + } + + // tab: see also + $conditions = array( + ['id', $this->typeId, '!'], + [ + 'OR', + ['name_loc'.User::$localeId, $this->subject->getField('name', true)], + [ + 'AND', + ['class', $_class], + ['subClass', $_subClass], + ['slot', $_slot], + ['itemLevel', $this->subject->getField('itemLevel') - 15, '>'], + ['itemLevel', $this->subject->getField('itemLevel') + 15, '<'], + ['quality', $this->subject->getField('quality')], + ['requiredClass', $this->subject->getField('requiredClass')] + ] + ] + ); + + $saItems = new ItemList($conditions); + if (!$saItems->error) + { + $this->extendGlobalData($saItems->getJSGlobals(GLOBALINFO_SELF)); + + $this->lvData[] = array( + 'file' => 'item', + 'data' => $saItems->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_seealso', + 'id' => 'see-also' + ] + ); + } + + // tab: starts (quest) + if ($qId = $this->subject->getField('startQuest')) + { + $starts = new QuestList(array(['id', $qId])); + if (!$starts->error) + { + $this->extendGlobalData($starts->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS)); + + $this->lvData[] = array( + 'file' => 'quest', + 'data' => $starts->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_starts', + 'id' => 'starts-quest' + ] + ); + } + } + + // tab: objective of (quest) + $conditions = array( + 'OR', + ['reqItemId1', $this->typeId], ['reqItemId2', $this->typeId], ['reqItemId3', $this->typeId], + ['reqItemId4', $this->typeId], ['reqItemId5', $this->typeId], ['reqItemId6', $this->typeId] + ); + $objective = new QuestList($conditions); + if (!$objective->error) + { + $this->extendGlobalData($objective->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS)); + + $this->lvData[] = array( + 'file' => 'quest', + 'data' => $objective->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_objectiveof', + 'id' => 'objective-of-quest' + ] + ); + } + + // tab: provided for (quest) + $conditions = array( + 'OR', ['sourceItemId', $this->typeId], + ['reqSourceItemId1', $this->typeId], ['reqSourceItemId2', $this->typeId], + ['reqSourceItemId3', $this->typeId], ['reqSourceItemId4', $this->typeId] + ); + $provided = new QuestList($conditions); + if (!$provided->error) + { + $this->extendGlobalData($provided->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS)); + + $this->lvData[] = array( + 'file' => 'quest', + 'data' => $provided->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_providedfor', + 'id' => 'provided-for-quest' + ] + ); + } + + // tab: same model as + // todo (low): should also work for creatures summoned by item + if (($model = $this->subject->getField('model')) && $_slot) + { + $sameModel = new ItemList(array(['model', $model], ['id', $this->typeId, '!'], ['slot', $_slot])); + if (!$sameModel->error) + { + $this->extendGlobalData($sameModel->getJSGlobals(GLOBALINFO_SELF)); + + $this->lvData[] = array( + 'file' => 'genericmodel', + 'data' => $sameModel->getListviewData(ITEMINFO_MODEL), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_samemodelas', + 'id' => 'same-model-as', + 'genericlinktype' => 'item' + ] + ); + } + } + + // tab: sold by + if ($vendors = @$this->subject->getExtendedCost([], $_reqRating)[$this->subject->id]) + { + $soldBy = new CreatureList(array(['id', array_keys($vendors)])); + if (!$soldBy->error) + { + $sbData = $soldBy->getListviewData(); + $this->extendGlobalData($soldBy->getJSGlobals(GLOBALINFO_SELF)); + + $extraCols = ['Listview.extraCols.stock', "Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')", 'Listview.extraCols.cost']; + + $holidays = []; + foreach ($sbData as $k => &$row) + { + $currency = []; + $tokens = []; + foreach ($vendors[$k] as $id => $qty) + { + if (is_string($id)) + continue; + + if ($id > 0) + $tokens[] = [$id, $qty]; + else if ($id < 0) + $currency[] = [-$id, $qty]; + } + + $row['stock'] = $vendors[$k]['stock']; + $row['cost'] = [$this->subject->getField('buyPrice')]; + + if ($e = $vendors[$k]['event']) + { + if (count($extraCols) == 3) + $extraCols[] = 'Listview.extraCols.condition'; + + Util::$pageTemplate->extendGlobalIds(TYPE_WORLDEVENT, $e); + $row['condition'][] = array( + 'type' => TYPE_WORLDEVENT, + 'typeId' => -$e, + 'status' => 1 + ); + } + + if ($currency || $tokens) // fill idx:3 if required + $row['cost'][] = $currency; + + if ($tokens) + $row['cost'][] = $tokens; + + if ($x = $this->subject->getField('buyPrice')) + $row['buyprice'] = $x; + + if ($x = $this->subject->getField('sellPrice')) + $row['sellprice'] = $x; + + if ($x = $this->subject->getField('buyCount')) + $row['stack'] = $x; + } + + + $this->lvData[] = array( + 'file' => 'creature', + 'data' => $sbData, + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_soldby', + 'id' => 'sold-by-npc', + 'extraCols' => '$['.implode(', ', $extraCols).']', + 'hiddenCols' => "$['level', 'type']" + ] + ); + } + } + + // tab: currency for + // some minor trickery: get arenaPoints(43307) and honorPoints(43308) directly + if ($this->typeId == 43307) + $w = 'iec.reqArenaPoints > 0'; + else if ($this->typeId == 43308) + $w = 'iec.reqHonorPoints > 0'; + else + $w = 'iec.reqItemId1 = '.$this->typeId.' OR iec.reqItemId2 = '.$this->typeId.' OR iec.reqItemId3 = '.$this->typeId.' OR iec.reqItemId4 = '.$this->typeId.' OR iec.reqItemId5 = '.$this->typeId; + + $boughtBy = DB::Aowow()->selectCol(' + SELECT item FROM npc_vendor nv JOIN ?_itemExtendedCost iec ON iec.id = nv.extendedCost WHERE '.$w.' + UNION + SELECT item FROM game_event_npc_vendor genv JOIN ?_itemExtendedCost iec ON iec.id = genv.extendedCost WHERE '.$w + ); + if ($boughtBy) + { + $boughtBy = new ItemList(array(['id', $boughtBy])); + if (!$boughtBy->error) + { + $this->extendGlobalData($boughtBy->getJSGlobals(GLOBALINFO_SELF)); + + $iCur = new CurrencyList(array(['itemId', $this->typeId])); + $filter = $iCur->error ? [TYPE_ITEM => $this->typeId] : [TYPE_CURRENCY => $iCur->id]; + + $this->lvData[] = array( + 'file' => 'item', + 'data' => $boughtBy->getListviewData(ITEMINFO_VENDOR, $filter), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_currencyfor', + 'id' => 'currency-for', + 'extraCols' => "$[Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack'), Listview.extraCols.cost]" + ] + ); + } + } + + // tab: teaches + $ids = $indirect = []; + for ($i = 1; $i < 6; $i++) + { + if ($this->subject->getField('spellTrigger'.$i) == 6) + $ids[] = $this->subject->getField('spellId'.$i); + else if ($this->subject->getField('spellTrigger'.$i) == 0 && $this->subject->getField('spellId'.$i) > 0) + $indirect[] = $this->subject->getField('spellId'.$i); + } + + // taught indirectly + if ($indirect) + { + $indirectSpells = new SpellList(array(['id', $indirect])); + foreach ($indirectSpells->iterate() as $__) + if ($_ = $indirectSpells->canTeachSpell()) + foreach ($_ as $idx) + $ids[] = $indirectSpells->getField('effect'.$idx.'TriggerSpell'); + + $ids = array_merge($ids, Util::getTaughtSpells($indirect)); + } + + if ($ids) + { + $taughtSpells = new SpellList(array(['id', $ids])); + if (!$taughtSpells->error) + { + $this->extendGlobalData($taughtSpells->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); + + $visCols = ['level', 'schools']; + if ($taughtSpells->hasSetFields(['reagent1'])) + $visCols[] = 'reagents'; + + $this->lvData[] = array( + 'file' => 'spell', + 'data' => $taughtSpells->getListviewData(), + 'params' => [ + 'tabs' => '$tabsRelated', + 'name' => '$LANG.tab_teaches', + 'id' => 'teaches', + 'visibleCols' => '$'.json_encode($visCols), + ] + ); + } + } + + // todo: taught by (req. workaround over the spell taught) + + // todo: Shared cooldown + } + + protected function generateTooltip($asError = false) + { + $itemString = $this->typeId; + foreach ($this->enhancedTT as $k => $val) + $itemString .= $k.(is_array($val) ? implode(':', $val) : $val); + + if ($asError) + return '$WowheadPower.registerItem(\''.$itemString.'\', '.User::$localeId.', {})'; + + $this->subject->renderTooltip(false, 0, $this->enhancedTT); + $x = '$WowheadPower.registerItem(\''.$itemString.'\', '.User::$localeId.", {\n"; + $x .= "\tname_".User::$localeString.": '".Util::jsEscape($this->subject->getField('name', true))."',\n"; + $x .= "\tquality: ".$this->subject->getField('quality').",\n"; + $x .= "\ticon: '".urlencode($this->subject->getField('iconString'))."',\n"; + $x .= "\ttooltip_".User::$localeString.": '".Util::jsEscape($this->subject->tooltip[$this->typeId])."'\n"; $x .= "});"; - $smarty->saveCache($cacheKeyTooltip, $x); + return $x; } - die($x); -} - -// xml object -if (isset($_GET['xml'])) -{ - header('Content-type: text/xml; charsetUTF-8'); - - $cacheKeyXML = implode('_', [CACHETYPE_XML, TYPE_ITEM, $_id, -1, User::$localeId]); - - if (!$smarty->loadCache($cacheKeyXML, $root)) + protected function generateXML($asError = false) { $root = new SimpleXML(''); - $cnd = array($_id ? ['i.id', $_id] : ['name_loc'.User::$localeId, urldecode($pageParam)]); - $item = new ItemList($cnd); - if ($item->error) + if ($asError) $root->addChild('error', 'Item not found!'); else { // item root $xml = $root->addChild('item'); - $xml->addAttribute('id', $item->id); + $xml->addAttribute('id', $this->subject->id); // name - $xml->addChild('name')->addCData($item->getField('name', true)); + $xml->addChild('name')->addCData($this->subject->getField('name', true)); // itemlevel - $xml->addChild('level', $item->getField('itemLevel')); + $xml->addChild('level', $this->subject->getField('itemLevel')); // quality - $xml->addChild('quality', Lang::$item['quality'][$item->getField('quality')])->addAttribute('id', $item->getField('quality')); + $xml->addChild('quality', Lang::$item['quality'][$this->subject->getField('quality')])->addAttribute('id', $this->subject->getField('quality')); // class - $x = Lang::$item['cat'][$item->getField('class')]; - $xml->addChild('class')->addCData(is_array($x) ? $x[0] : $x)->addAttribute('id', $item->getField('class')); + $x = Lang::$item['cat'][$this->subject->getField('class')]; + $xml->addChild('class')->addCData(is_array($x) ? $x[0] : $x)->addAttribute('id', $this->subject->getField('class')); // subclass - $x = $item->getField('class') == 2 ? Lang::$spell['weaponSubClass'] : Lang::$item['cat'][$item->getField('class')][1]; - $xml->addChild('subclass')->addCData(is_array($x) ? (is_array($x[$item->getField('subClass')]) ? $x[$item->getField('subClass')][0] : $x[$item->getField('subClass')]) : null)->addAttribute('id', $item->getField('subClass')); + $x = $this->subject->getField('class') == 2 ? Lang::$spell['weaponSubClass'] : Lang::$item['cat'][$this->subject->getField('class')][1]; + $xml->addChild('subclass')->addCData(is_array($x) ? (is_array($x[$this->subject->getField('subClass')]) ? $x[$this->subject->getField('subClass')][0] : $x[$this->subject->getField('subClass')]) : null)->addAttribute('id', $this->subject->getField('subClass')); // icon + displayId - $xml->addChild('icon', $item->getField('iconString'))->addAttribute('displayId', $item->getField('displayId')); + $xml->addChild('icon', $this->subject->getField('iconString'))->addAttribute('displayId', $this->subject->getField('displayId')); // inventorySlot - $xml->addChild('inventorySlot', Lang::$item['inventoryType'][$item->getField('slot')])->addAttribute('id', $item->getField('slot')); + $xml->addChild('inventorySlot', Lang::$item['inventoryType'][$this->subject->getField('slot')])->addAttribute('id', $this->subject->getField('slot')); // tooltip - $xml->addChild('htmlTooltip')->addCData($item->renderTooltip()); + $xml->addChild('htmlTooltip')->addCData($this->subject->renderTooltip()); - $onUse = $item->extendJsonStats(); + $this->subject->extendJsonStats(); // json $fields = ["classs", "displayid", "dps", "id", "level", "name", "reqlevel", "slot", "slotbak", "source", "sourcemore", "speed", "subclass"]; $json = ''; foreach ($fields as $f) { - if (($_ = @$item->json[$item->id][$f]) !== null) + if (($_ = @$this->subject->json[$this->subject->id][$f]) !== null) { - $_ = $f == 'name' ? (7 - $item->getField('quality')).$_ : $_; + $_ = $f == 'name' ? (7 - $this->subject->getField('quality')).$_ : $_; $json .= ',"'.$f.'":'.$_; } } @@ -127,44 +982,43 @@ if (isset($_GET['xml'])) // jsonEquip missing: avgbuyout, cooldown $json = ''; - if ($_ = $item->getField('sellPrice')) // sellprice + if ($_ = $this->subject->getField('sellPrice')) // sellprice $json .= ',"sellprice":'.$_; - if ($_ = $item->getField('requiredLevel')) // reqlevel + if ($_ = $this->subject->getField('requiredLevel')) // reqlevel $json .= ',"reqlevel":'.$_; - if ($_ = $item->getField('requiredSkill')) // reqskill + if ($_ = $this->subject->getField('requiredSkill')) // reqskill $json .= ',"reqskill":'.$_; - if ($_ = $item->getField('requiredSkillRank')) // reqskillrank + if ($_ = $this->subject->getField('requiredSkillRank')) // reqskillrank $json .= ',"reqskillrank":'.$_; - foreach (Util::$itemMods as $idx => $str) - if ($_ = @$item->itemMods[$item->id][$idx]) - $json .= ',"'.$str.'":'.$_; + foreach ($this->subject->itemMods[$this->subject->id] as $mod => $qty) + $json .= ',"'.$mod.'":'.$qty; - foreach ($_ = $item->json[$item->id] as $name => $qty) + foreach ($_ = $this->subject->json[$this->subject->id] as $name => $qty) if (in_array($name, Util::$itemFilter)) $json .= ',"'.$name.'":'.$qty; $xml->addChild('jsonEquip')->addCData(substr($json, 1)); // jsonUse - if ($onUse) + if ($onUse = $this->subject->getOnUseStats()) { $j = ''; foreach ($onUse as $idx => $qty) $j .= ',"'.Util::$itemMods[$idx].'":'.$qty; - $xml->addChild('jsonUse')->addCdata(substr($j, 1)); + $xml->addChild('jsonUse')->addCData(substr($j, 1)); } // reagents $cnd = array( 'OR', - ['AND', ['effect1CreateItemId', $item->id], ['OR', ['effect1Id', SpellList::$effects['itemCreate']], ['effect1AuraId', SpellList::$auras['itemCreate']]]], - ['AND', ['effect2CreateItemId', $item->id], ['OR', ['effect2Id', SpellList::$effects['itemCreate']], ['effect2AuraId', SpellList::$auras['itemCreate']]]], - ['AND', ['effect3CreateItemId', $item->id], ['OR', ['effect3Id', SpellList::$effects['itemCreate']], ['effect3AuraId', SpellList::$auras['itemCreate']]]], + ['AND', ['effect1CreateItemId', $this->subject->id], ['OR', ['effect1Id', SpellList::$effects['itemCreate']], ['effect1AuraId', SpellList::$auras['itemCreate']]]], + ['AND', ['effect2CreateItemId', $this->subject->id], ['OR', ['effect2Id', SpellList::$effects['itemCreate']], ['effect2AuraId', SpellList::$auras['itemCreate']]]], + ['AND', ['effect3CreateItemId', $this->subject->id], ['OR', ['effect3Id', SpellList::$effects['itemCreate']], ['effect3AuraId', SpellList::$auras['itemCreate']]]], ); $spellSource = new SpellList($cnd); @@ -176,13 +1030,13 @@ if (isset($_GET['xml'])) { foreach ($spellSource->canCreateItem() as $idx) { - if ($spellSource->getField('effect'.$idx.'CreateItemId') != $item->id) + if ($spellSource->getField('effect'.$idx.'CreateItemId') != $this->subject->id) continue; $splNode = $cbNode->addChild('spell'); $splNode->addAttribute('id', $sId); $splNode->addAttribute('name', $spellSource->getField('name', true)); - $splNode->addAttribute('icon', $item->getField('iconString')); + $splNode->addAttribute('icon', $this->subject->getField('iconString')); $splNode->addAttribute('minCount', $spellSource->getField('effect'.$idx.'BasePoints') + 1); $splNode->addAttribute('maxCount', $spellSource->getField('effect'.$idx.'BasePoints') + $spellSource->getField('effect'.$idx.'DieSides')); @@ -205,859 +1059,11 @@ if (isset($_GET['xml'])) } // link - $xml->addChild('link', HOST_URL.'?item='.$item->id); + $xml->addChild('link', HOST_URL.'?item='.$this->subject->id); } - $smarty->saveCache($cacheKeyXML, $root); + return $root->asXML(); } - - die($root->asXML()); } - -// regular page -if (!$smarty->loadCache($cacheKeyPage, $pageData)) -{ - $item = new ItemList(array(['i.id', $_id])); - if ($item->error) - $smarty->notFound(Lang::$game['item'], $_id); - - $item->addGlobalsToJScript(GLOBALINFO_EXTRA | GLOBALINFO_SELF); - - $_flags = $item->getField('flags'); - $_slot = $item->getField('slot'); - $_class = $item->getField('class'); - $_subClass = $item->getField('subClass'); - $_bagFamily = $item->getField('bagFamily'); - - /***********/ - /* Infobox */ - /***********/ - - $quickInfo = Lang::getInfoBoxForFlags($item->getField('cuFlags')); - - if (in_array($_class, [ITEM_CLASS_ARMOR, ITEM_CLASS_WEAPON, ITEM_CLASS_AMMUNITION]) || $item->getField('gemEnchantmentId')) // itemlevel - $quickInfo[] = Lang::$game['level'].Lang::$colon.$item->getField('itemLevel'); - - if ($_flags & ITEM_FLAG_ACCOUNTBOUND) // account-wide - $quickInfo[] = Lang::$item['accountWide']; - - if ($si = $item->json[$_id]['side']) // side - if ($si != 3) - $quickInfo[] = Lang::$main['side'].Lang::$colon.'[span class=icon-'.($si == 1 ? 'alliance' : 'horde').']'.Lang::$game['si'][$si].'[/span]'; - - // consumable / not consumable - if (!$_slot) - { - $hasUse = false; - for ($i = 1; $i < 6; $i++) - { - if ($item->getField('spellId'.$i) <= 0 || in_array($item->getField('spellTrigger'.$i), [1, 2])) - continue; - - $hasUse = true; - - if ($item->getField('spellCharges'.$i) >= 0) - continue; - - $tt = '[tooltip=tooltip_consumedonuse]'.Lang::$item['consumable'].'[/tooltip]'; - break; - } - - if ($hasUse) - $quickInfo[] = isset($tt) ? $tt : '[tooltip=tooltip_notconsumedonuse]'.Lang::$item['nonConsumable'].'[/tooltip]'; - } - - if ($hId = $item->getField('holidayId')) - if ($hName = DB::Aowow()->selectRow('SELECT * FROM ?_holidays WHERE id = ?d', $hId)) - $quickInfo[] = Lang::$game['eventShort'].Lang::$colon.'[url=?event='.$hId.']'.Util::localizedString($hName, 'name').'[/url]'; - - if ($tId = $item->getField('totemCategory')) - if ($tName = DB::Aowow()->selectRow('SELECT * FROM ?_totemCategory WHERE id = ?d', $tId)) - $quickInfo[] = Lang::$item['tool'].Lang::$colon.'[url=?items&filter=cr=91;crs='.$tId.';crv=0]'.Util::localizedString($tName, 'name').'[/url]'; - - $each = $item->getField('stackable') > 1 ? '[color=q0] ('.Lang::$item['each'].')[/color]' : null; - - if ($_ = @$item->getExtendedCost([], $_reqRating)[$item->id]) - { - $handled = []; - $costList = []; - foreach ($_ as $npcId => $data) - { - $tokens = []; - $currency = []; - - if (!is_array($data)) - continue; - - foreach ($data as $c => $qty) - { - if (is_string($c)) - { - unset($data[$c]); // unset miscData to prevent having two vendors /w the same cost being cached, because of different stock or rating-requirements - continue; - } - - if ($c < 0) // currency items (and honor or arena) - $currency[] = -$c.','.$qty; - else if ($c > 0) // plain items (item1,count1,item2,count2,...) - $tokens[$c] = $c.','.$qty; - } - - if (in_array(md5(serialize($data)), $handled)) // display every cost-combination only once - continue; - - $handled[] = md5(serialize($data)); - - $cost = isset($data[0]) ? '[money='.$data[0] : '[money'; - - if ($tokens) - $cost .= ' items='.implode(',', $tokens); - - if ($currency) - $cost .= ' currency='.implode(',', $currency); - - $cost .= ']'; - - $costList[] = $cost; - } - - if (count($costList) == 1) - $quickInfo[] = Lang::$item['cost'].Lang::$colon.$costList[0].$each; - else if (count($costList) > 1) - $quickInfo[] = Lang::$item['cost'].$each.Lang::$colon.'[ul][li]'.implode('[/li][li]', $costList).'[/li][/ul]'; - - if ($_reqRating) - { - $res = []; - $i = 0; - $len = 0; - $parts = explode(' ', sprintf(Lang::$item['reqRating'], $_reqRating)); - foreach ($parts as $p) - { - $res[$i][] = $p; - $len += mb_strlen($p); - - if ($len < 30) - continue; - - $len = 0; - $i++; - } - foreach ($res as &$r) - $r = implode(' ', $r); - - $quickInfo[] = implode('[br]', $res); - } - } - - if ($_ = $item->getField('repairPrice')) - $quickInfo[] = Lang::$item['repairCost'].Lang::$colon.'[money='.$_.']'; - - if (in_array($item->getField('bonding'), [0, 2, 3])) // avg auction buyout - if ($_ = Util::getBuyoutForItem($_id)) - $quickInfo[] = '[tooltip=tooltip_buyoutprice]'.Lang::$item['buyout.'].'[/tooltip]'.Lang::$colon.'[money='.$_.']'.$each; - - if ($_flags & ITEM_FLAG_OPENABLE) // avg money contained - if ($_ = intVal(($item->getField('minMoneyLoot') + $item->getField('maxMoneyLoot')) / 2)) - $quickInfo[] = Lang::$item['worth'].Lang::$colon.'[tooltip=tooltip_avgmoneycontained][money='.$_.'][/tooltip]'; - - if ($_slot && $_class != ITEM_CLASS_CONTAINER) // if it goes into a slot it may be disenchanted - { - if ($item->getField('disenchantId')) - { - $_ = $item->getField('requiredDisenchantSkill'); - if ($_ < 1) // these are some items, that never went live .. extremely rough emulation here - $_ = intVal($item->getField('itemLevel') / 7.5) * 25; - - $quickInfo[] = Lang::$item['disenchantable'].' ([tooltip=tooltip_reqenchanting]'.$_.'[/tooltip])'; - } - else - $quickInfo[] = Lang::$item['cantDisenchant']; - } - - if (($_flags & ITEM_FLAG_MILLABLE) && $item->getField('requiredSkill') == 773) - $quickInfo[] = Lang::$item['millable'].' ([tooltip=tooltip_reqinscription]'.$item->getField('requiredSkillRank').'[/tooltip])'; - - if (($_flags & ITEM_FLAG_PROSPECTABLE) && $item->getField('requiredSkill') == 755) - $quickInfo[] = Lang::$item['prospectable'].' ([tooltip=tooltip_reqjewelcrafting]'.$item->getField('requiredSkillRank').'[/tooltip])'; - - if ($_flags & ITEM_FLAG_DEPRECATED) - $quickInfo[] = '[tooltip=tooltip_deprecated]'.Lang::$item['deprecated'].'[/tooltip]'; - - if ($_flags & ITEM_FLAG_NO_EQUIPCD) - $quickInfo[] = '[tooltip=tooltip_noequipcooldown]'.Lang::$item['noEquipCD'].'[/tooltip]'; - - if ($_flags & ITEM_FLAG_PARTYLOOT) - $quickInfo[] = '[tooltip=tooltip_partyloot]'.Lang::$item['partyLoot'].'[/tooltip]'; - - if ($_flags & ITEM_FLAG_REFUNDABLE) - $quickInfo[] = '[tooltip=tooltip_refundable]'.Lang::$item['refundable'].'[/tooltip]'; - - if ($_flags & ITEM_FLAG_SMARTLOOT) - $quickInfo[] = '[tooltip=tooltip_smartloot]'.Lang::$item['smartLoot'].'[/tooltip]'; - - if ($_flags & ITEM_FLAG_INDESTRUCTIBLE) - $quickInfo[] = Lang::$item['indestructible']; - - if ($_flags & ITEM_FLAG_USABLE_ARENA) - $quickInfo[] = Lang::$item['useInArena']; - - if ($_flags & ITEM_FLAG_USABLE_SHAPED) - $quickInfo[] = Lang::$item['useInShape']; - - if ($item->getField('flagsExtra') & 0x0100) // cant roll need - $quickInfo[] = '[tooltip=tooltip_cannotrollneed]'.Lang::$item['noNeedRoll'].'[/tooltip]'; - - if ($_bagFamily & 0x0100) // fits into keyring - $quickInfo[] = Lang::$item['atKeyring']; - - - /****************/ - /* Main Content */ - /****************/ - - $cmpUpg = in_array($_class, [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]) || $item->getField('gemEnchantmentId'); - $view3D = in_array($_slot, $_visSlots) && $item->getField('displayId'); - - // path - if (in_array($_class, [5, 8, 14])) - { - $_path[] = 15; // misc. - - if ($_class == 5) // reagent - $_path[] = 1; - else - $_path[] = 4; // other - } - else - { - $_path[] = $_class; - - if (!in_array($_class, [ITEM_CLASS_MONEY, ITEM_CLASS_QUEST, ITEM_CLASS_KEY])) - $_path[] = $_subClass; - - if ($_class == ITEM_CLASS_ARMOR && in_array($_subClass, [1, 2, 3, 4])) - { - if ($_ = $_slot); - $_path[] = $_; - } - else if (($_class == ITEM_CLASS_CONSUMABLE && $_subClass == 2) || $_class == ITEM_CLASS_GLYPH) - $_path[] = $item->getField('subSubClass'); - } - - // pageText - $pageText = []; - if ($next = $item->getField('pageTextId')) - { - while ($next) - { - $row = DB::Aowow()->selectRow('SELECT *, text as Text_loc0 FROM page_text pt LEFT JOIN locales_page_text lpt ON pt.entry = lpt.entry WHERE pt.entry = ?d', $next); - $next = $row['next_page']; - $pageText[] = Util::parseHtmlText(Util::localizedString($row, 'Text')); - } - } - - // menuId 0: Item g_initPath() - // tabId 0: Database g_initHeader() - $pageData = array( - 'page' => array( - 'quality' => $item->getField('quality'), - 'headIcons' => [$item->getField('iconString'), $item->getField('stackable')], - 'name' => $item->getField('name', true), - 'infobox' => $quickInfo ? '[ul][li]'.implode('[/li][li]', $quickInfo).'[/li][/ul]' : null, - 'tooltip' => $item->renderTooltip([], true), - 'path' => json_encode($_path, JSON_NUMERIC_CHECK), - 'title' => $item->getField('name', true).' - '.Util::ucFirst(Lang::$game['item']), - 'pageText' => $pageText, - 'tab' => 0, - 'type' => TYPE_ITEM, - 'typeId' => $_id, - 'reqJS' => array( - $pageText ? STATIC_URL.'/js/Book.js' : null, - STATIC_URL.'/js/swfobject.js', - STATIC_URL.'/js/profile.js', - STATIC_URL.'/js/filters.js', - '?data=weight-presets&locale='.User::$localeId.'&t='.$_SESSION['dataKey'] - ), - 'reqCSS' => array( - $pageText ? ['path' => STATIC_URL.'/css/Book.css'] : null, - ), - 'redButtons' => array( - BUTTON_WOWHEAD => true, - BUTTON_LINKS => ['color' => 'ff'.Util::$rarityColorStings[$item->getField('quality')], 'linkId' => 'item:'.$_id.':0:0:0:0:0:0:0:0'], - BUTTON_VIEW3D => $view3D ? ['displayId' => $item->getField('displayId'), 'slot' => $_slot, 'type' => TYPE_ITEM, 'typeId' => $_id] : false, - BUTTON_COMPARE => $cmpUpg, // bool required - BUTTON_EQUIP => $cmpUpg, - BUTTON_UPGRADE => $cmpUpg ? ['class' => $_class, 'slot' => $_slot] : false - ), - ), - 'relTabs' => [] - ); - - // subItems - $item->initSubItems(); - if (!empty($item->subItems[$_id])) - { - uaSort($item->subItems[$_id], function($a, $b) { return strcmp($a['name'], $b['name']); }); - $pageData['page']['subItems'] = array_values($item->subItems[$_id]); - - // merge identical stats and names for normal users (e.g. spellPower of a specific school became generel spellPower with 3.0) - if (!User::isInGroup(U_GROUP_STAFF)) - { - for ($i = 1; $i < count($pageData['page']['subItems']); $i++) - { - $prev = &$pageData['page']['subItems'][$i - 1]; - $cur = &$pageData['page']['subItems'][$i]; - if ($prev['jsonequip'] == $cur['jsonequip'] && $prev['name'] == $cur['name']) - { - $prev['chance'] += $cur['chance']; - array_splice($pageData['page']['subItems'], $i , 1); - $i = 1; - } - } - } - } - - // factionchange-equivalent - if ($pendant = DB::Aowow()->selectCell('SELECT IF(horde_id = ?d, alliance_id, -horde_id) FROM player_factionchange_items WHERE alliance_id = ?d OR horde_id = ?d', $_id, $_id, $_id)) - { - $altItem = new ItemList(array(['id', abs($pendant)])); - if (!$altItem->error) - { - $pageData['page']['transfer'] = sprintf( - Lang::$item['_transfer'], - $altItem->id, - $altItem->getField('quality'), - $altItem->getField('iconString'), - $altItem->getField('name', true), - $pendant > 0 ? 'alliance' : 'horde', - $pendant > 0 ? Lang::$game['si'][1] : Lang::$game['si'][2] - ); - } - } - - /**************/ - /* Extra Tabs */ - /**************/ - - // tabs: this item is contained in.. - $lootTabs = Util::getLootSource($_id); - foreach ($lootTabs as $tab) - { - $pageData['relTabs'][] = array( - 'file' => $tab[0], - 'data' => $tab[1], - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => $tab[2], - 'id' => $tab[3], - 'extraCols' => $tab[4] ? '$['.implode(', ', array_unique($tab[4])).']' : null, - 'hiddenCols' => $tab[5] ? '$['.implode(', ', array_unique($tab[5])).']' : null, - 'visibleCols' => $tab[6] ? '$'. json_encode( array_unique($tab[6])) : null - ] - ); - } - - // tabs: this item contains.. - $sourceFor = array( - [LOOT_ITEM, $item->id, '$LANG.tab_contains', 'contains', ['Listview.extraCols.percent'], [] , []], - [LOOT_PROSPECTING, $item->id, '$LANG.tab_prospecting', 'prospecting', ['Listview.extraCols.percent'], ['side', 'slot', 'reqlevel'], []], - [LOOT_MILLING, $item->id, '$LANG.tab_milling', 'milling', ['Listview.extraCols.percent'], ['side', 'slot', 'reqlevel'], []], - [LOOT_DISENCHANT, $item->getField('disenchantId'), '$LANG.tab_disenchanting', 'disenchanting', ['Listview.extraCols.percent'], ['side', 'slot', 'reqlevel'], []] - ); - - $reqQuest = []; - foreach ($sourceFor as $sf) - { - if ($itemLoot = Util::handleLoot($sf[0], $sf[1], User::isInGroup(U_GROUP_STAFF), $sf[4])) - { - foreach ($itemLoot as $l => $lv) - { - if (!$lv['quest']) - continue; - - $sf[4][] = 'Listview.extraCols.condition'; - - $reqQuest[$lv['id']] = 0; - - $itemLoot[$l]['condition'][] = ['type' => TYPE_QUEST, 'typeId' => &$reqQuest[$lv['id']], 'status' => 1]; - } - - $pageData['relTabs'][] = array( - 'file' => 'item', - 'data' => $itemLoot, - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => $sf[2], - 'id' => $sf[3], - 'extraCols' => $sf[4] ? "$[".implode(', ', array_unique($sf[4]))."]" : null, - 'hiddenCols' => $sf[5] ? "$".json_encode($sf[5]) : null, - 'visibleCols' => $sf[6] ? '$'.json_encode($sf[6]) : null - ] - ); - } - } - - if ($reqIds = array_keys($reqQuest)) // apply quest-conditions as back-reference - { - $conditions = array( - 'OR', - ['reqSourceItemId1', $reqIds], ['reqSourceItemId2', $reqIds], - ['reqSourceItemId3', $reqIds], ['reqSourceItemId4', $reqIds], - ['reqItemId1', $reqIds], ['reqItemId2', $reqIds], ['reqItemId3', $reqIds], - ['reqItemId4', $reqIds], ['reqItemId5', $reqIds], ['reqItemId6', $reqIds] - ); - - $reqQuests = new QuestList($conditions); - $reqQuests->addGlobalsToJscript(); - - foreach ($reqQuests->iterate() as $qId => $__) - { - if (empty($reqQuests->requires[$qId][TYPE_ITEM])) - continue; - - foreach ($reqIds as $rId) - if (in_array($rId, $reqQuests->requires[$qId][TYPE_ITEM])) - $reqQuest[$rId] = $reqQuests->id; - } - } - - // tab: container can contain - if ($item->getField('slots') > 0) - { - $contains = new ItemList(array(['bagFamily', $_bagFamily, '&'], ['slots', 1, '<'], 0)); - if (!$contains->error) - { - $contains->addGlobalsToJscript(); - - $hCols = ['side']; - if (!$contains->hasSetFields(['slot'])) - $hCols[] = 'slot'; - - $pageData['relTabs'][] = array( - 'file' => 'item', - 'data' => $contains->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_cancontain', - 'id' => 'can-contain', - 'hiddenCols' => '$'.json_encode($hCols) - ] - ); - } - } - - // tab: can be contained in (except keys) - else if ($_bagFamily != 0x0100) - { - $contains = new ItemList(array(['bagFamily', $_bagFamily, '&'], ['slots', 0, '>'], 0)); - if (!$contains->error) - { - $contains->addGlobalsToJscript(); - - $pageData['relTabs'][] = array( - 'file' => 'item', - 'data' => $contains->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_canbeplacedin', - 'id' => 'can-be-placed-in', - 'hiddenCols' => "$['side']" - ] - ); - } - } - - // tab: criteria of - $conditions = array( - ['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM, ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM, ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM]], - ['ac.value1', $_id] - ); - - $criteriaOf = new AchievementList($conditions); - if (!$criteriaOf->error) - { - $criteriaOf->addGlobalsToJScript(GLOBALINFO_SELF | GLOBALINFO_REWARDS); - - $hCols = []; - if (!$criteriaOf->hasSetFields(['rewardIds'])) - $hCols = ['rewards']; - - $pageData['relTabs'][] = array( - 'file' => 'achievement', - 'data' => $criteriaOf->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_criteriaof', - 'id' => 'criteria-of', - 'visibleCols' => "$['category']", - 'hiddenCols' => '$'.json_encode($hCols) - ] - ); - } - - // tab: reagent for - $conditions = array( - 'OR', - ['reagent1', $_id], ['reagent2', $_id], ['reagent3', $_id], ['reagent4', $_id], - ['reagent5', $_id], ['reagent6', $_id], ['reagent7', $_id], ['reagent8', $_id] - ); - - $reagent = new SpellList($conditions); - if (!$reagent->error) - { - $reagent->addGlobalsToJScript(GLOBALINFO_SELF | GLOBALINFO_RELATED); - - $pageData['relTabs'][] = array( - 'file' => 'spell', - 'data' => $reagent->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_reagentfor', - 'id' => 'reagent-for', - 'visibleCols' => "$['reagents']" - ] - ); - } - - // tab: unlocks (object or item) - $lockIds = DB::Aowow()->selectCol( - 'SELECT id FROM ?_lock WHERE - (type1 = 1 AND properties1 = ?d) OR - (type2 = 1 AND properties2 = ?d) OR - (type3 = 1 AND properties3 = ?d) OR - (type4 = 1 AND properties4 = ?d) OR - (type5 = 1 AND properties5 = ?d)', - $_id, $_id, $_id, $_id, $_id - ); - - if ($lockIds) - { - // objects - $lockedObj = new GameObjectList(array(['lockId', $lockIds])); - if (!$lockedObj->error) - { - $pageData['relTabs'][] = array( - 'file' => 'object', - 'data' => $lockedObj->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_unlocks', - 'id' => 'unlocks-object' - ] - ); - } - - // items (generally unused. It's the spell on the item, that unlocks stuff) - $lockedItm = new ItemList(array(['lockId', $lockIds])); - if (!$lockedItm->error) - { - $lockedItm->addGlobalsToJScript(GLOBALINFO_SELF); - - $pageData['relTabs'][] = array( - 'file' => 'item', - 'data' => $lockedItm->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_unlocks', - 'id' => 'unlocks-item' - ] - ); - } - } - - // tab: see also - $conditions = array( - ['id', $_id, '!'], - [ - 'OR', - ['name_loc'.User::$localeId, $item->getField('name', true)], - [ - 'AND', - ['class', $_class], - ['subClass', $_subClass], - ['slot', $_slot], - ['itemLevel', $item->getField('itemLevel') - 15, '>'], - ['itemLevel', $item->getField('itemLevel') + 15, '<'], - ['quality', $item->getField('quality')], - ['requiredClass', $item->getField('requiredClass')] - ] - ] - ); - - $saItems = new ItemList($conditions); - if (!$saItems->error) - { - $saItems->addGlobalsToJScript(GLOBALINFO_SELF); - - $pageData['relTabs'][] = array( - 'file' => 'item', - 'data' => $saItems->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_seealso', - 'id' => 'see-also' - ] - ); - } - - // tab: starts (quest) - if ($qId = $item->getField('startQuest')) - { - $starts = new QuestList(array(['id', $qId])); - if (!$starts->error) - { - $starts->addGlobalsToJscript(); - - $pageData['relTabs'][] = array( - 'file' => 'quest', - 'data' => $starts->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_starts', - 'id' => 'starts-quest' - ] - ); - } - } - - // tab: objective of (quest) - $conditions = array( - 'OR', - ['reqItemId1', $_id], ['reqItemId2', $_id], ['reqItemId3', $_id], - ['reqItemId4', $_id], ['reqItemId5', $_id], ['reqItemId6', $_id] - ); - $objective = new QuestList($conditions); - if (!$objective->error) - { - $objective->addGlobalsToJScript(GLOBALINFO_SELF | GLOBALINFO_REWARDS); - - $pageData['relTabs'][] = array( - 'file' => 'quest', - 'data' => $objective->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_objectiveof', - 'id' => 'objective-of-quest' - ] - ); - } - - // tab: provided for (quest) - $conditions = array( - 'OR', ['sourceItemId', $_id], - ['reqSourceItemId1', $_id], ['reqSourceItemId2', $_id], - ['reqSourceItemId3', $_id], ['reqSourceItemId4', $_id] - ); - $provided = new QuestList($conditions); - if (!$provided->error) - { - $provided->addGlobalsToJScript(GLOBALINFO_SELF | GLOBALINFO_REWARDS); - - $pageData['relTabs'][] = array( - 'file' => 'quest', - 'data' => $provided->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_providedfor', - 'id' => 'provided-for-quest' - ] - ); - } - - // tab: same model as - // todo (low): should also work for creatures summoned by item - if (($model = $item->getField('model')) && $_slot) - { - $sameModel = new ItemList(array(['model', $model], ['id', $_id, '!'], ['slot', $_slot])); - if (!$sameModel->error) - { - $sameModel->addGlobalsToJScript(GLOBALINFO_SELF); - - $pageData['relTabs'][] = array( - 'file' => 'genericmodel', - 'data' => $sameModel->getListviewData(ITEMINFO_MODEL), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_samemodelas', - 'id' => 'same-model-as', - 'genericlinktype' => 'item' - ] - ); - } - } - - // tab: sold by - if ($vendors = @$item->getExtendedCost([], $_reqRating)[$item->id]) - { - $soldBy = new CreatureList(array(['id', array_keys($vendors)])); - if (!$soldBy->error) - { - $soldBy->addGlobalsToJScript(GLOBALINFO_SELF); - $sbData = $soldBy->getListviewData(); - - $extraCols = ['Listview.extraCols.stock', "Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')", 'Listview.extraCols.cost']; - - $holidays = []; - foreach ($sbData as $k => &$row) - { - $currency = []; - $tokens = []; - foreach ($vendors[$k] as $id => $qty) - { - if (is_string($id)) - continue; - - if ($id > 0) - $tokens[] = [$id, $qty]; - else if ($id < 0) - $currency[] = [-$id, $qty]; - } - - $row['stock'] = $vendors[$k]['stock']; - $row['cost'] = [$item->getField('buyPrice')]; - - if ($e = $vendors[$k]['event']) - { - if (count($extraCols) == 3) - $extraCols[] = 'Listview.extraCols.condition'; - - Util::$pageTemplate->extendGlobalIds(TYPE_WORLDEVENT, $e); - $row['condition'][] = array( - 'type' => TYPE_WORLDEVENT, - 'typeId' => -$e, - 'status' => 1 - ); - } - - if ($currency || $tokens) // fill idx:3 if required - $row['cost'][] = $currency; - - if ($tokens) - $row['cost'][] = $tokens; - - if ($x = $item->getField('buyPrice')) - $row['buyprice'] = $x; - - if ($x = $item->getField('sellPrice')) - $row['sellprice'] = $x; - - if ($x = $item->getField('buyCount')) - $row['stack'] = $x; - } - - - $pageData['relTabs'][] = array( - 'file' => 'creature', - 'data' => $sbData, - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_soldby', - 'id' => 'sold-by-npc', - 'extraCols' => '$['.implode(', ', $extraCols).']', - 'hiddenCols' => "$['level', 'type']" - ] - ); - } - } - - // tab: currency for - // some minor trickery: get arenaPoints(43307) and honorPoints(43308) directly - if ($_id == 43307) - $w = 'iec.reqArenaPoints > 0'; - else if ($_id == 43308) - $w = 'iec.reqHonorPoints > 0'; - else - $w = 'iec.reqItemId1 = '.$_id.' OR iec.reqItemId2 = '.$_id.' OR iec.reqItemId3 = '.$_id.' OR iec.reqItemId4 = '.$_id.' OR iec.reqItemId5 = '.$_id; - - $boughtBy = DB::Aowow()->selectCol(' - SELECT item FROM npc_vendor nv JOIN ?_itemExtendedCost iec ON iec.id = nv.extendedCost WHERE '.$w.' - UNION - SELECT item FROM game_event_npc_vendor genv JOIN ?_itemExtendedCost iec ON iec.id = genv.extendedCost WHERE '.$w - ); - if ($boughtBy) - { - $boughtBy = new ItemList(array(['id', $boughtBy])); - if (!$boughtBy->error) - { - $boughtBy->addGlobalsToJscript(); - - $iCur = new CurrencyList(array(['itemId', $_id])); - $filter = $iCur->error ? [TYPE_ITEM => $_id] : [TYPE_CURRENCY => $iCur->id]; - - $pageData['relTabs'][] = array( - 'file' => 'item', - 'data' => $boughtBy->getListviewData(ITEMINFO_VENDOR, $filter), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_currencyfor', - 'id' => 'currency-for', - 'extraCols' => "$[Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack'), Listview.extraCols.cost]" - ] - ); - } - } - - // tab: teaches - $ids = $indirect = []; - for ($i = 1; $i < 6; $i++) - { - if ($item->getField('spellTrigger'.$i) == 6) - $ids[] = $item->getField('spellId'.$i); - else if ($item->getField('spellTrigger'.$i) == 0 && $item->getField('spellId'.$i) > 0) - $indirect[] = $item->getField('spellId'.$i); - } - - // taught indirectly - if ($indirect) - { - $indirectSpells = new SpellList(array(['id', $indirect])); - foreach ($indirectSpells->iterate() as $__) - if ($_ = $indirectSpells->canTeachSpell()) - foreach ($_ as $idx) - $ids[] = $indirectSpells->getField('effect'.$idx.'TriggerSpell'); - - $ids = array_merge($ids, Util::getTaughtSpells($indirect)); - } - - if ($ids) - { - $taughtSpells = new SpellList(array(['id', $ids])); - if (!$taughtSpells->error) - { - $taughtSpells->addGlobalsToJScript(GLOBALINFO_SELF | GLOBALINFO_RELATED); - - $visCols = ['level', 'schools']; - if ($taughtSpells->hasSetFields(['reagent1'])) - $visCols[] = 'reagents'; - - $pageData['relTabs'][] = array( - 'file' => 'spell', - 'data' => $taughtSpells->getListviewData(), - 'params' => [ - 'tabs' => '$tabsRelated', - 'name' => '$LANG.tab_teaches', - 'id' => 'teaches', - 'visibleCols' => '$'.json_encode($visCols), - ] - ); - } - } - - // taught by (req. workaround over the spell taught) - - // Shared cooldown - - $smarty->saveCache($cacheKeyPage, $pageData); -} - -$smarty->updatePageVars($pageData['page']); -$smarty->assign('community', CommunityContent::getAll(TYPE_ITEM, $_id)); // comments, screenshots, videos -$smarty->assign('lang', array_merge(Lang::$main, Lang::$game, Lang::$item, ['colon' => Lang::$colon])); -$smarty->assign('lvData', $pageData['relTabs']); - -// load the page -$smarty->display('item.tpl'); - ?> diff --git a/pages/items.php b/pages/items.php index 90c39ccc..40cd6231 100644 --- a/pages/items.php +++ b/pages/items.php @@ -4,237 +4,454 @@ if (!defined('AOWOW_REVISION')) die('illegal access'); -$cats = Util::extractURLParams($pageParam); -$path = [0, 0]; -$title = [Lang::$game['items']]; -$filter = ['panel1' => false, 'panel2' => false]; -$filterHash = !empty($_GET['filter']) ? '#'.sha1(serialize($_GET['filter'])) : null; -$cacheKey = implode('_', [CACHETYPE_PAGE, TYPE_ITEM, -1, implode('.', $cats).$filterHash, User::$localeId]); -$validCats = array( // if > 0 class => subclass - 2 => [15, 13, 0, 4, 7, 6, 10, 1, 5, 8, 2, 18, 3, 16, 19, 20, 14], - 4 => array( - 0 => true, - 1 => [1, 3, 5, 6, 7, 8, 9, 10], - 2 => [1, 3, 5, 6, 7, 8, 9, 10], - 3 => [1, 3, 5, 6, 7, 8, 9, 10], - 4 => [1, 3, 5, 6, 7, 8, 9, 10], - 6 => true, - 7 => true, - 8 => true, - 9 => true, - 10 => true, - -2 => true, // Rings - -3 => true, // Amulets - -4 => true, // Trinkets - -5 => true, // Off-hand Frills - -6 => true, // Cloaks - -7 => true, // Tabards - -8 => true // Shirts - ), - 1 => [0, 1, 2, 3, 4, 5, 6, 7, 8], - 0 => array( - 7 => true, - 0 => true, - 2 => [1, 2], // elixirs: [Battle, Guardian] - 3 => true, - 5 => true, - 6 => true, // Item Enhancements (Permanent) - -3 => true, // Item Enhancements (Temporary) - 1 => true, - 4 => true, - 8 => true - ), - 16 => array( // Glyphs by class: [major, minor] - 1 => [1, 2], - 2 => [1, 2], - 3 => [1, 2], - 4 => [1, 2], - 5 => [1, 2], - 6 => [1, 2], - 7 => [1, 2], - 8 => [1, 2], - 9 => [1, 2], - 11 => [1, 2] - ), - 7 => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - 6 => [2, 3], - 11 => [2, 3], - 9 => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], // some of the books to propper professions - 3 => [0, 1, 2, 3, 4, 5, 6, 7, 8], - 15 => [-2, -7, 0, 1, 2, 3, 4, 5], // -2: armor tokes, -7: flying mounts fuck it .. need major overhaul - 10 => true, - 12 => true, // todo: contains enchantments - 13 => true -); - -if (!Util::isValidPage($validCats, $cats)) - $smarty->error(); - -if (!$smarty->loadCache($cacheKey, $pageData, $filter)) +// menuId 0: Item g_initPath() +// tabId 0: Database g_initHeader() +class ItemsPage extends GenericPage { - $conditions = []; - $visibleCols = []; - $hiddenCols = []; + use ListPage; - if ($cats) - $path = array_merge($path, $cats); - - // display available submenu and slot, if applicable - $type = $slot = [[], null]; - if (!$cats) - { - $slot = [Lang::$item['inventoryType'], null]; - asort($slot[0]); - } - else - { - if (isset($cats[2])) - $catList = Lang::$item['cat'][$cats[0]][1][$cats[1]][1][$cats[2]]; - else if (isset($cats[1])) - $catList = Lang::$item['cat'][$cats[0]][1][$cats[1]]; - else - $catList = Lang::$item['cat'][$cats[0]]; - - array_unshift($title, is_array($catList) ? $catList[0] : $catList); - - switch ($cats[0]) - { - case 0: - if (!isset($cats[1])) - $type = [Lang::$item['cat'][0][1], null]; - - if (!isset($cats[1]) || in_array($cats[1], [6, -3])) - { - $slot = [Lang::$item['inventoryType'], 0x63EFEA]; - asort($slot[0]); - } - break; - case 2: - if (!isset($cats[1])) - $type = [Lang::$spell['weaponSubClass'], null]; - - $slot = [Lang::$item['inventoryType'], 0x262A000]; - asort($slot[0]); - break; - case 4: - if (!isset($cats[1])) - { - $slot = [Lang::$item['inventoryType'], 0x10895FFE]; - $type = [Lang::$item['cat'][4][1], null]; - } - else if (in_array($cats[1], [1, 2, 3, 4])) - $slot = [Lang::$item['inventoryType'], 0x7EA]; - - asort($slot[0]); - break; - case 16: - if (!isset($cats[2])) - $visibleCols[] = 'glyph'; - case 1: - if ($cats[0] == 1) - $visibleCols[] = 'slots'; - case 3: - if (!isset($cats[1])) - asort($catList[1]); - case 7: - case 9: - $hiddenCols[] = 'slot'; - case 15: - if (!isset($cats[1])) - $type = [$catList[1], null]; - - break; - } - } - - foreach ($type[0] as $k => $str) - if ($str && (!$type[1] || ($type[1] & (1 << $k)))) - $filter['type'][$k] = $str; - - foreach ($slot[0] as $k => $str) - if ($str && (!$slot[1] || ($slot[1] & (1 << $k)))) - $filter['slot'][$k] = $str; - - if (isset($filter['slot'][INVTYPE_SHIELD])) // "Off Hand" => "Shield" - $filter['slot'][INVTYPE_SHIELD] = Lang::$item['armorSubClass'][6]; - - $itemFilter = new ItemListFilter(); - - // recreate form selection - $filter = array_merge($itemFilter->getForm('form'), $filter); - $filter['query'] = isset($_GET['filter']) ? $_GET['filter'] : NULL; - $filter['fi'] = $itemFilter->getForm(); - - $xCols = $itemFilter->getForm('extraCols', true); - - // if slot-dropdown is available && Armor && $path points to Armor-Class - if (count($path) == 4 && $cats[0] == 4 && isset($filter['sl']) && !is_array($filter['sl'])) - $path[] = $filter['sl']; - - $infoMask = ITEMINFO_JSON; - if (array_intersect([63, 64, 125], $xCols)) // 63:buyPrice; 64:sellPrice; 125:reqarenartng - $infoMask |= ITEMINFO_VENDOR; - - - // menuId 0: Item g_initPath() - // tabId 0: Database g_initHeader() - $pageData = array( - 'page' => array( - 'title' => implode(' - ', $title), - 'path' => json_encode($path, JSON_NUMERIC_CHECK), - 'tab' => 0, - 'subCat' => $pageParam !== null ? '='.$pageParam : '', - 'reqJS' => array( - STATIC_URL.'/js/filters.js', - STATIC_URL.'/js/swfobject.js', - '?data=weight-presets&locale='.User::$localeId.'&t='.$_SESSION['dataKey'] - ) + protected $type = TYPE_ITEM; + protected $tpl = 'items'; + protected $path = [0, 0]; + protected $tabId = 0; + protected $mode = CACHETYPE_PAGE; + protected $js = ['filters.js', 'swfobject.js']; + protected $validCats = array( // if > 0 class => subclass + 2 => [15, 13, 0, 4, 7, 6, 10, 1, 5, 8, 2, 18, 3, 16, 19, 20, 14], + 4 => array( + 0 => true, + 1 => [1, 3, 5, 6, 7, 8, 9, 10], + 2 => [1, 3, 5, 6, 7, 8, 9, 10], + 3 => [1, 3, 5, 6, 7, 8, 9, 10], + 4 => [1, 3, 5, 6, 7, 8, 9, 10], + 6 => true, + 7 => true, + 8 => true, + 9 => true, + 10 => true, + -2 => true, // Rings + -3 => true, // Amulets + -4 => true, // Trinkets + -5 => true, // Off-hand Frills + -6 => true, // Cloaks + -7 => true, // Tabards + -8 => true // Shirts ), - 'lv' => array( - 'tabs' => [], - 'isGrouped' => false - ) + 1 => [0, 1, 2, 3, 4, 5, 6, 7, 8], + 0 => array( + 7 => true, + 0 => true, + 2 => [1, 2], // Elixirs: [Battle, Guardian] + 3 => true, + 5 => true, + 6 => true, // Item Enhancements (Permanent) + -3 => true, // Item Enhancements (Temporary) + 1 => true, + 4 => true, + 8 => true + ), + 16 => array( // Glyphs by class: [major, minor] + 1 => [1, 2], + 2 => [1, 2], + 3 => [1, 2], + 4 => [1, 2], + 5 => [1, 2], + 6 => [1, 2], + 7 => [1, 2], + 8 => [1, 2], + 9 => [1, 2], + 11 => [1, 2] + ), + 7 => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + 6 => [2, 3], + 11 => [2, 3], + 9 => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], // some of the books to propper professions + 3 => [0, 1, 2, 3, 4, 5, 6, 7, 8], + 15 => [-2, -7, 0, 1, 2, 3, 4, 5], // -2: armor tokes, -7: flying mounts fuck it .. need major overhaul + 10 => true, + 12 => true, // todo: contains enchantments + 13 => true ); + private $sharedLV = array( // common listview components across all tabs + 'hiddenCols' => [], + 'visibleCols' => [], + 'extraCols' => [] + ); - /* - set conditions - */ - - if (isset($cats[0])) - $conditions[] = ['i.class', $cats[0]]; - if (isset($cats[1])) - $conditions[] = ['i.subClass', $cats[1]]; - if (isset($cats[2])) - $conditions[] = ['i.subSubClass', $cats[2]]; - - if ($_ = $itemFilter->getConditions()) - $conditions[] = $_; - - - /* - shared parameter between all possible lv-tabs - */ - - $sharedLvParams = []; - $upgItemData = []; - if (!empty($filter['fi']['extraCols'])) + public function __construct($pageCall, $pageParam) { - $gem = empty($filter['gm']) ? 0 : $filter['gm']; - $cost = array_intersect([63], $xCols) ? 1 : 0; - $sharedLvParams['extraCols'] = '$fi_getExtraCols(fi_extraCols, '.$gem.', '.$cost.')'; + $this->getCategoryFromUrl($pageParam);; + + parent::__construct(); + + $this->name = Util::ucFirst(Lang::$game['gameObjects']); + $this->subCat = $pageParam ? '='.$pageParam : ''; } - if (!empty($filter['fi']['setWeights'])) + protected function generateContent() { - if (!empty($filter['gm'])) - { - $sharedLvParams['computeDataFunc'] = '$fi_scoreSockets'; + $this->addJS('?data=weight-presets&locale='.User::$localeId.'&t='.$_SESSION['dataKey']); + $this->hasGroupedTabs = false; - $q = intVal($filter['gm']); + /*******************/ + /* evaluate filter */ + /*******************/ + + $itemFilter = new ItemListFilter(); + + // recreate form selection + $this->filter = array_merge($itemFilter->getForm('form'), $this->filter); + $this->filter['query'] = @$_GET['filter'] ?: NULL; + $this->filter['fi'] = $itemFilter->getForm(); + + $menu = $this->createExtraMenus(); + + foreach ($menu['type'][0] as $k => $str) + if ($str && (!$menu['type'][1] || ($menu['type'][1] & (1 << $k)))) + $this->filter['type'][$k] = $str; + + foreach ($menu['slot'][0] as $k => $str) + if ($str && (!$menu['slot'][1] || ($menu['slot'][1] & (1 << $k)))) + $this->filter['slot'][$k] = $str; + + if (isset($this->filter['slot'][INVTYPE_SHIELD])) // "Off Hand" => "Shield" + $this->filter['slot'][INVTYPE_SHIELD] = Lang::$item['armorSubClass'][6]; + + $xCols = $itemFilter->getForm('extraCols', true); + + $infoMask = ITEMINFO_JSON; + if (array_intersect([63, 64, 125], $xCols)) // 63:buyPrice; 64:sellPrice; 125:reqarenartng + $infoMask |= ITEMINFO_VENDOR; + + if ($itemFilter->error) + $this->sharedLV['_errors'] = '$1'; + + if (!empty($this->filter['fi']['extraCols'])) + $this->sharedLV['extraCols'] = '$fi_getExtraCols(fi_extraCols, '.($this->filter['gm'] ?: 0).', '.(array_intersect([63], $xCols) ? 1 : 0).')'; + + if ($_ = $itemFilter->getConditions()) + $conditions[] = $_; + + /******************/ + /* set conditions */ + /******************/ + + if (isset($this->category[0])) + $conditions[] = ['i.class', $this->category[0]]; + if (isset($this->category[1])) + $conditions[] = ['i.subClass', $this->category[1]]; + if (isset($this->category[2])) + $conditions[] = ['i.subSubClass', $this->category[2]]; + + /***********************/ + /* handle auto-gemming */ + /***********************/ + + $this->gemScores = $this->createGemScores($itemFilter); + + /*************************/ + /* handle upgrade search */ + /*************************/ + + $upgItemData = []; + if (!empty($this->filter['upg']) && !empty($this->filter['fi']['setWeights'])) + { + $upgItems = new ItemList(array(['id', array_keys($this->filter['upg'])]), ['extraOpts' => $itemFilter->extraOpts]); + if (!$upgItems->error) + { + $this->extendGlobalData($upgItems->getJSGlobals()); + $upgItemData = $upgItems->getListviewData($infoMask); + } + } + + if ($upgItemData) // check if upItems cover multiple slots + { + $singleSlot = true; + $ref = reset($this->filter['upg']); + foreach ($this->filter['upg'] as $slot) + { + if ($slot == $ref) + continue; + + $singleSlot = false; + break; + } + + if ($singleSlot && empty($this->filter['gb'])) // enforce group by slot + $this->filter['gb'] = 1; + else if (!$singleSlot) // multiples can only be grouped by slot + { + $this->filter['gb'] = 1; + $maxResults = 25; + $this->sharedLV['customFilter'] = '$fi_filterUpgradeListview'; + } + } + + /********************************************************************************************************************************/ + /* group by */ + /* */ + /* cases that make sense: */ + /* no upgItems -> everything goes */ + /* 1 upgItems OR */ + /* N upgItems (same slot) -> gb:none - disabled */ + /* -> gb:slot - limited to slot of the upgItems (in theory weapons create a tab for each weapon type) */ + /* -> gb:level - upgItems is added to all tabs */ + /* -> gb:source - upgItems is added to all tabs */ + /* N upgItems (random) -> gb:none - disabled */ + /* -> gb:slot - only slots existing within the upgItems; match upgItems to slot */ + /* -> gb:level - disabled */ + /* -> gb:source - disabled */ + /********************************************************************************************************************************/ + + $availableSlots = array( + ITEM_CLASS_ARMOR => [INVTYPE_HEAD, INVTYPE_NECK, INVTYPE_SHOULDERS, INVTYPE_CHEST, INVTYPE_WAIST, INVTYPE_LEGS, INVTYPE_FEET, INVTYPE_WRISTS, INVTYPE_HANDS, INVTYPE_FINGER, INVTYPE_TRINKET, INVTYPE_SHIELD, INVTYPE_CLOAK], + ITEM_CLASS_WEAPON => [INVTYPE_WEAPON, INVTYPE_RANGED, INVTYPE_2HWEAPON, INVTYPE_WEAPONMAINHAND, INVTYPE_WEAPONOFFHAND, INVTYPE_THROWN, INVTYPE_HOLDABLE] + ); + $groups = []; + $nameSource = []; + $gbField = ''; + $extraOpts = []; + $maxResults = CFG_SQL_LIMIT_DEFAULT; + + switch (@$this->filter['gb']) + { + // slot: (try to limit the lookups by class grouping and intersecting with preselected slots) + // if intersect yields an empty array no lookups will occur + case 3: // todo(med): source .. well .. no, not at the moment .. the database doesn't event have a field for that, so reroute to slots + case 1: + if (isset($this->category[0]) && $this->category[0] == ITEM_CLASS_ARMOR) + $groups = $availableSlots[ITEM_CLASS_ARMOR]; + else if (isset($this->category[0]) && $this->category[0] == ITEM_CLASS_WEAPON) + $groups = $availableSlots[ITEM_CLASS_WEAPON]; + else + $groups = array_merge($availableSlots[ITEM_CLASS_ARMOR], $availableSlots[ITEM_CLASS_WEAPON]); + + if (isset($this->filter['sl'])) // skip lookups for unselected slots + $groups = array_intersect($groups, (array)$this->filter['sl']); + + if (isset($this->filter['upg'])) // skip lookups for slots we dont have items to upgrade for + $groups = array_intersect($groups, (array)$this->filter['upg']); + + if ($groups) + { + $nameSource = Lang::$item['inventoryType']; + $this->hasGroupedTabs = true; + $gbField = 'slot'; + } + + break; + case 2: // itemlevel: first, try to find 10 level steps within range (if given) as tabs + // ohkayy, maybe i need to rethink $this + $this->filterOpts = $itemFilter->extraOpts; + $this->filterOpts['is']['o'] = [null]; // remove 'order by' from itemStats + $extraOpts = array_merge($this->filterOpts, ['i' => ['g' => ['itemlevel'], 'o' => ['itemlevel DESC']]]); + + $levelRef = new ItemList(array_merge($conditions, [10]), ['extraOpts' => $extraOpts]); + + foreach ($levelRef->iterate() as $_) + { + $l = $levelRef->getField('itemLevel'); + $groups[] = $l; + $nameSource[$l] = Lang::$game['level'].' '.$l; + } + + if ($groups) + { + $l = -end($groups); + $groups[] = $l; // push last value as negativ to signal misc group after $this level + $extraOpts = ['i' => ['o' => ['itemlevel DESC']]]; + $nameSource[$l] = Lang::$item['tabOther']; + $this->hasGroupedTabs = true; + $gbField = 'itemlevel'; + } + + break; + case 3: + $groups = array_filter(array_keys(Lang::$game['sources'])); + array_walk($groups, function (&$v, $k) { + $v = $v.':'; + }); + + $nameSource = Lang::$game['sources']; + $this->hasGroupedTabs = true; + $gbField = 'source'; + + break; + // none + default: + $groups[0] = null; + } + + /*****************************/ + /* create lv-tabs for groups */ + /*****************************/ + + foreach ($groups as $group) + { + $finalCnd = $gbField ? array_merge($conditions, [[$gbField, abs($group), $group > 0 ? null : '<'], $maxResults]) : $conditions; + + $items = new ItemList($finalCnd, ['extraOpts' => array_merge($extraOpts, $itemFilter->extraOpts)]); + + if ($items->error) + continue; + + $this->extendGlobalData($items->getJSGlobals()); + $tab = array( + 'data' => $items->getListviewData($infoMask), + 'params' => $this->sharedLV + ); + + $upg = []; + if ($upgItemData) + { + if ($gbField == 'slot') // match upgradeItem to slot + { + $upg = array_keys(array_filter($this->filter['upg'], function ($v) use ($group) { + return $v == $group; + })); + + foreach ($upg as $uId) + $tab['data'][$uId] = $upgItemData[$uId]; + + if ($upg) + $tab['params']['_upgradeIds'] = '$'.json_encode($upg, JSON_NUMERIC_CHECK); + } + else if ($gbField) + { + $upg = array_keys($this->filter['upg']); + $tab['params']['_upgradeIds'] = '$'.json_encode($upg, JSON_NUMERIC_CHECK); + foreach ($upgItemData as $uId => $data) // using numeric keys => cant use array_merge + $tab['data'][$uId] = $data; + } + } + + if ($gbField) + { + $tab['params']['id'] = $group > 0 ? $gbField.'-'.$group : 'other'; + $tab['params']['name'] = $nameSource[$group]; + $tab['params']['tabs'] = '$tabsGroups'; + } + + if (!empty($this->filter['fi']['setWeights'])) + if ($items->hasSetFields(['armor'])) + $tab['params']['visibleCols'][] = 'armor'; + + // create note if search limit was exceeded; overwriting 'note' is intentional + if ($items->getMatches() > $maxResults && count($groups) > 1) + { + $tab['params']['_truncated'] = 1; + + $addCr = []; + if ($gbField == 'slot') + { + $note = 'lvnote_viewmoreslot'; + $override = ['sl' => $group, 'gb' => '']; + } + else if ($gbField == 'itemlevel') + { + $note = 'lvnote_viewmorelevel'; + if ($group > 0) + $override = ['minle' => $group, 'maxle' => $group, 'gb' => '']; + else + $override = ['maxle' => abs($group) - 1, 'gb' => '']; + } + else if ($gbField == 'source') + { + if ($_ = @[null, 3, 4, 5, 6, 7, 8][$group]) + { + $note = 'lvnote_viewmoresource'; + $addCr = ['cr' => 128, 'crs' => $_, 'crv' => 0]; + } + + $override = ['gb' => '']; + } + + if ($upg) + $override['upg'] = implode(':', $upg); + + $cls = isset($this->category[0]) ? '='.$this->category[0] : ''; + $this->filterUrl = $itemFilter->urlize($override, $addCr); + + if ($note) + $tab['params']['note'] = '$$WH.sprintf(LANG.'.$note.', \''.$cls.'\', \''.$this->filterUrl.'\')'; + } + else if ($items->getMatches() > $maxResults) + { + $tab['params']['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_itemsfound', $items->getMatches(), CFG_SQL_LIMIT_DEFAULT); + $tab['params']['_truncated'] = 1; + } + + if (!empty($tab['params']['hiddenCols'])) + $tab['params']['hiddenCols'] = '$'.json_encode($tab['params']['hiddenCols']); + + if (!empty($tab['params']['visibleCols'])) + $tab['params']['visibleCols'] = '$'.json_encode($tab['params']['visibleCols']); + + foreach ($tab['params'] as $k => $p) + if (!$p) + unset($tab['params'][$k]); + + if ($gbField) + $tab['params']['hideCount'] = '$1'; + + $this->lvData[] = $tab; + } + + // reformat for use in template + if (isset($this->filter['upg'])) + $this->filter['upg'] = implode(':', array_keys($this->filter['upg'])); + + // whoops, we have no data? create emergency content + if (!$this->lvData) + $this->lvData[] = ['data' => [], 'params' => []]; + + // sort for dropdown-menus + asort(Lang::$game['ra']); + asort(Lang::$game['cl']); + } + + protected function generateTitle() + { + array_unshift($this->title, $this->name); + + if (isset($this->category[2])) + $tPart = Lang::$item['cat'][$this->category[0]][1][$this->category[1]][1][$this->category[2]]; + else if (isset($this->category[1])) + $tPart = Lang::$item['cat'][$this->category[0]][1][$this->category[1]]; + else + $tPart = Lang::$item['cat'][$this->category[0]]; + + array_unshift($this->title, is_array($tPart) ? $tPart[0] : $tPart); + } + + protected function generatePath() + { + foreach ($this->category as $c) + $this->path[] = $c; + + // if slot-dropdown is available && Armor && $path points to Armor-Class + $form = (new ItemListFilter())->getForm('form'); + if (count($this->path) == 4 && $this->category[0] == 4 && isset($form['sl']) && !is_array($form['sl'])) + $this->path[] = $form['sl']; + } + + // fetch best possible gems for chosen weights + private function createGemScores($itemFilter) + { + $gemScores = []; + + if (empty($this->filter['fi']['setWeights'])) + return []; + + if (!empty($this->filter['gm'])) + { + $this->sharedLV['computeDataFunc'] = '$fi_scoreSockets'; + + $q = intVal($this->filter['gm']); $mask = 14; $cnd = [10, ['class', ITEM_CLASS_GEM], ['gemColorMask', &$mask, '&'], ['quality', &$q]]; - if (!isset($filter['jc'])) + if (!isset($this->filter['jc'])) $cnd[] = ['itemLimitCategory', 0]; // Jeweler's Gems If ($itemFilter->wtCnd) @@ -243,295 +460,106 @@ if (!$smarty->loadCache($cacheKey, $pageData, $filter)) $anyColor = new ItemList($cnd, ['extraOpts' => $itemFilter->extraOpts]); if (!$anyColor->error) { - $anyColor->addGlobalsToJScript(); - $pageData['page']['gemScores'][0] = array_values($anyColor->getListviewData(ITEMINFO_GEM)); + $this->extendGlobalData($anyColor->getJSGlobals()); + $gemScores[0] = array_values($anyColor->getListviewData(ITEMINFO_GEM)); } for ($i = 0; $i < 4; $i++) { $mask = 1 << $i; - $q = !$i ? 3 : intVal($filter['gm']); // meta gems are always included.. ($q is backReferenced) + $q = !$i ? 3 : intVal($this->filter['gm']); // meta gems are always included.. ($q is backReferenced) $byColor = new ItemList($cnd, ['extraOpts' => $itemFilter->extraOpts]); if (!$byColor->error) { - $byColor->addGlobalsToJScript(); - $pageData['page']['gemScores'][$mask] = array_values($byColor->getListviewData(ITEMINFO_GEM)); + $this->extendGlobalData($byColor->getJSGlobals()); + $gemScores[$mask] = array_values($byColor->getListviewData(ITEMINFO_GEM)); } } - - $pageData['page']['gemScores'] = json_encode($pageData['page']['gemScores'], JSON_NUMERIC_CHECK); } - $sharedLvParams['onBeforeCreate'] = '$fi_initWeightedListview'; - $sharedLvParams['onAfterCreate'] = '$fi_addUpgradeIndicator'; - $sharedLvParams['sort'] = "$['-score', 'name']"; + $this->sharedLV['onBeforeCreate'] = '$fi_initWeightedListview'; + $this->sharedLV['onAfterCreate'] = '$fi_addUpgradeIndicator'; + $this->sharedLV['sort'] = "$['-score', 'name']"; - array_push($hiddenCols, 'type', 'source'); + array_push($this->sharedLV['hiddenCols'], 'type', 'source'); + + return $gemScores; } - if ($itemFilter->error) - $sharedLvParams['_errors'] = '$1'; - - if (!empty($filter['upg']) && !empty($filter['fi']['setWeights'])) + // display available submenus 'type' and 'slot', if applicable + private function createExtraMenus() { - // v poke it to use item_stats - $upgItems = new ItemList(array(['id', array_keys($filter['upg'])], ['is.id', null, '!']), ['extraOpts' => $itemFilter->extraOpts]); - if (!$upgItems->error) - { - $upgItems->addGlobalsToJScript(); - $upgItemData = $upgItems->getListviewData($infoMask); - } - } - - /* - group by - - cases that make sense: - no upgItems -> everything goes - 1 upgItems OR - N upgItems (same slot) -> gb:none - disabled - -> gb:slot - limited to slot of the upgItems (in theory weapons create a tab for each weapon type) - -> gb:level - upgItems is added to all tabs - -> gb:source - upgItems is added to all tabs - N upgItems (random) -> gb:none - disabled - -> gb:slot - only slots existing within the upgItems; match upgItems to slot - -> gb:level - disabled - -> gb:source - disabled - */ - $availableSlots = array( - ITEM_CLASS_ARMOR => [INVTYPE_HEAD, INVTYPE_NECK, INVTYPE_SHOULDERS, INVTYPE_CHEST, INVTYPE_WAIST, INVTYPE_LEGS, INVTYPE_FEET, INVTYPE_WRISTS, INVTYPE_HANDS, INVTYPE_FINGER, INVTYPE_TRINKET, INVTYPE_SHIELD, INVTYPE_CLOAK], - ITEM_CLASS_WEAPON => [INVTYPE_WEAPON, INVTYPE_RANGED, INVTYPE_2HWEAPON, INVTYPE_WEAPONMAINHAND, INVTYPE_WEAPONOFFHAND, INVTYPE_THROWN, INVTYPE_HOLDABLE] - ); - $sourcesGlobalToItem = [1 => 3, 2 => 4, 3 => 5, 4 => 6, 5 => 7, 6 => 8]; - $groups = []; - $nameSource = []; - $gbField = ''; - $extraOpts = []; - $singleSlot = true; - $maxResults = CFG_SQL_LIMIT_DEFAULT; - - if ($upgItemData) - { - // check if upItems cover multiple slots - $ref = reset($filter['upg']); - foreach ($filter['upg'] as $slot) - { - if ($slot == $ref) - continue; - - $singleSlot = false; - break; - } - - if ($singleSlot && empty($filter['gb'])) // enforce group by slot - $filter['gb'] = 1; - else if (!$singleSlot) // multiples can only be grouped by slot - { - $filter['gb'] = 1; - $maxResults = 25; - $sharedLvParams['customFilter'] = '$fi_filterUpgradeListview'; - } - } - - switch (@$filter['gb']) - { - // slot: (try to limit the lookups by class grouping and intersecting with preselected slots) - // if intersect yields an empty array no lookups will occur - case 1: - case 3: // todo(med): source .. well .. no, not at the moment .. the database doesn't event have a field for that, so reroute to slots - if (isset($cats[0]) && $cats[0] == ITEM_CLASS_ARMOR) - $groups = isset($filter['sl']) ? array_intersect($availableSlots[ITEM_CLASS_ARMOR], (array)$filter['sl']) : $availableSlots[ITEM_CLASS_ARMOR]; - else if (isset($cats[0]) && $cats[0] == ITEM_CLASS_WEAPON) - $groups = isset($filter['sl']) ? array_intersect($availableSlots[ITEM_CLASS_WEAPON], (array)$filter['sl']) : $availableSlots[ITEM_CLASS_WEAPON]; - else - { - $groups = array_merge($availableSlots[ITEM_CLASS_ARMOR], $availableSlots[ITEM_CLASS_WEAPON]); - if (isset($filter['sl'])) - $groups = array_intersect($groups, (array)$filter['sl']); - } - - if ($groups) - { - $nameSource = Lang::$item['inventoryType']; - $pageData['lv']['isGrouped'] = true; - $gbField = 'slot'; - } - - break; - // itemlevel: first, try to find 10 level steps within range (if given) as tabs - case 2: - // ohkayy, maybe i need to rethink this - $filterOpts = $itemFilter->extraOpts; - $filterOpts['is']['o'] = [null]; - $extraOpts = array_merge($filterOpts, ['i' => ['g' => ['itemlevel'], 'o' => ['itemlevel DESC']]]); - - $levelRef = new ItemList(array_merge($conditions, [10]), ['extraOpts' => $extraOpts]); - - foreach ($levelRef->iterate() as $_) - { - $l = $levelRef->getField('itemLevel'); - $groups[] = $l; - $nameSource[$l] = Lang::$game['level'].' '.$l; - } - - if ($groups) - { - $l = -end($groups); - $groups[] = $l; // push last value as negativ to signal misc group after this level - $extraOpts = ['i' => ['o' => ['itemlevel DESC']]]; - $nameSource[$l] = Lang::$item['tabOther']; - $pageData['lv']['isGrouped'] = true; - $gbField = 'itemlevel'; - } - - break; - case 3: - $groups = array_filter(array_keys(Lang::$game['sources'])); - array_walk($groups, function (&$v, $k) { - $v = $v.':'; - }); - - $nameSource = Lang::$game['sources']; - $pageData['lv']['isGrouped'] = true; - $gbField = 'source'; - - break; - // none - default: - $groups[0] = null; - } - - foreach ($groups as $group) - { - $finalCnd = $gbField ? array_merge($conditions, [[$gbField, abs($group), $group > 0 ? null : '<'], $maxResults]) : $conditions; - - $items = new ItemList($finalCnd, ['extraOpts' => array_merge($extraOpts, $itemFilter->extraOpts)]); - $items->addGlobalsToJscript(); - - if ($items->error) - continue; - - $tab = array( - 'data' => $items->getListviewData($infoMask), - 'params' => $sharedLvParams + $menu = array( + 'type' => [[], null], + 'slot' => [[], null] ); - $upg = []; - if ($upgItemData) + if (!$this->category) { - if ($gbField == 'slot') // match upgradeItem to slot - { - $upg = array_keys(array_filter($filter['upg'], function ($v) use ($group) { - return $v == $group; - })); + $menu['slot'] = [Lang::$item['inventoryType'], null]; + asort($menu['slot'][0]); + } + else + { + if (isset($this->category[2])) + $catList = Lang::$item['cat'][$this->category[0]][1][$this->category[1]][1][$this->category[2]]; + else if (isset($this->category[1])) + $catList = Lang::$item['cat'][$this->category[0]][1][$this->category[1]]; + else + $catList = Lang::$item['cat'][$this->category[0]]; - foreach ($upg as $uId) - $tab['data'][$uId] = $upgItemData[$uId]; - - if ($upg) - $tab['params']['_upgradeIds'] = '$'.json_encode($upg, JSON_NUMERIC_CHECK); - } - else if ($gbField) + switch ($this->category[0]) { - $upg = array_keys($filter['upg']); - $tab['params']['_upgradeIds'] = '$'.json_encode($upg, JSON_NUMERIC_CHECK); - foreach ($upgItemData as $uId => $data) // using numeric keys => cant use array_merge - $tab['data'][$uId] = $data; + case 0: + if (!isset($this->category[1])) + $menu['type'] = [Lang::$item['cat'][0][1], null]; + + if (!isset($this->category[1]) || in_array($this->category[1], [6, -3])) + { + $menu['slot'] = [Lang::$item['inventoryType'], 0x63EFEA]; + asort($menu['slot'][0]); + } + break; + case 2: + if (!isset($this->category[1])) + $menu['type'] = [Lang::$spell['weaponSubClass'], null]; + + $menu['slot'] = [Lang::$item['inventoryType'], 0x262A000]; + asort($menu['slot'][0]); + break; + case 4: + if (!isset($this->category[1])) + { + $menu['slot'] = [Lang::$item['inventoryType'], 0x10895FFE]; + $menu['type'] = [Lang::$item['cat'][4][1], null]; + } + else if (in_array($this->category[1], [1, 2, 3, 4])) + $menu['slot'] = [Lang::$item['inventoryType'], 0x7EA]; + + asort($menu['slot'][0]); + break; + case 16: + if (!isset($this->category[2])) + $this->sharedLV['visibleCols'][] = 'glyph'; + case 1: + if ($this->category[0] == 1) + $this->sharedLV['visibleCols'][] = 'slots'; + case 3: + if (!isset($this->category[1])) + asort($catList[1]); + case 7: + case 9: + $this->sharedLV['hiddenCols'][] = 'slot'; + case 15: + if (!isset($this->category[1])) + $menu['type'] = [$catList[1], null]; + + break; } } - if ($gbField) - { - $tab['params']['id'] = $group > 0 ? $gbField.'-'.$group : 'other'; - $tab['params']['name'] = $nameSource[$group]; - $tab['params']['tabs'] = '$tabsGroups'; - } - - if (!empty($filter['fi']['setWeights'])) - if ($items->hasSetFields(['armor'])) - $visibleCols[] = 'armor'; - - // create note if search limit was exceeded; overwriting 'note' is intentional - if ($items->getMatches() > $maxResults && count($groups) > 1) - { - $tab['params']['_truncated'] = 1; - - $addCr = []; - if ($gbField == 'slot') - { - $note = 'lvnote_viewmoreslot'; - $override = ['sl' => $group, 'gb' => '']; - } - else if ($gbField == 'itemlevel') - { - $note = 'lvnote_viewmorelevel'; - if ($group > 0) - $override = ['minle' => $group, 'maxle' => $group, 'gb' => '']; - else - $override = ['maxle' => abs($group) - 1, 'gb' => '']; - } - else if ($gbField == 'source') - { - if ($_ = @$sourcesGlobalToItem[$group]) - { - $note = 'lvnote_viewmoresource'; - $addCr = ['cr' => 128, 'crs' => $_, 'crv' => 0]; - } - - $override = ['gb' => '']; - } - - if ($upg) - $override['upg'] = implode(':', $upg); - - $cls = isset($cats[0]) ? '='.$cats[0] : ''; - $filterUrl = $itemFilter->urlize($override, $addCr); - - if ($note) - $tab['params']['note'] = '$$WH.sprintf(LANG.'.$note.', \''.$cls.'\', \''.$filterUrl.'\')'; - } - else if ($items->getMatches() > $maxResults) - { - $tab['params']['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_itemsfound', $items->getMatches(), CFG_SQL_LIMIT_DEFAULT); - $tab['params']['_truncated'] = 1; - } - - if ($hiddenCols) - $tab['params']['hiddenCols'] = '$'.json_encode($hiddenCols); - - if ($visibleCols) - $tab['params']['visibleCols'] = '$'.json_encode($visibleCols); - - if ($gbField) - $tab['params']['hideCount'] = '$1'; - - $pageData['lv']['tabs'][] = $tab; + return $menu; } - - if (isset($filter['upg'])) - $filter['upg'] = implode(':', array_keys($filter['upg'])); - - // whoops, we have no data? create emergency content - if (!$pageData['lv']['tabs']) - { - $pageData['lv']['isGrouped'] = false; - $pageData['lv']['tabs'][] = ['data' => [], 'params' => []]; - } - - $smarty->saveCache($cacheKey, $pageData, $filter); } - -// sort for dropdown-menus -asort(Lang::$game['ra']); -asort(Lang::$game['cl']); - -$smarty->updatePageVars($pageData['page']); -$smarty->assign('filter', $filter); -$smarty->assign('lang', array_merge(Lang::$main, Lang::$game, Lang::$item, ['colon' => Lang::$colon])); -$smarty->assign('lvData', $pageData['lv']); - -// load the page -$smarty->display('items.tpl'); - ?> diff --git a/pages/itemset.php b/pages/itemset.php index 15e5c466..499cf9c4 100644 --- a/pages/itemset.php +++ b/pages/itemset.php @@ -37,12 +37,12 @@ if (!$smarty->loadCache($cacheKeyPage, $pageData)) // holiday if ($_ev) - $infobox[] = Lang::$game['eventShort'].Lang::$colon.'[url=?event='.$_ev.']'.WorldEventList::getName($_ev).'[/url]'; + $infobox[] = Lang::$game['eventShort'].Lang::$main['colon'].'[url=?event='.$_ev.']'.WorldEventList::getName($_ev).'[/url]'; // itemLevel if ($min = $iSet->getField('minLevel')) { - $foo = Lang::$game['level'].Lang::$colon.$min; + $foo = Lang::$game['level'].Lang::$main['colon'].$min; $max = $iSet->getField('maxLevel'); if ($min < $max) @@ -60,7 +60,7 @@ if (!$smarty->loadCache($cacheKeyPage, $pageData)) $foo[] = (!fMod(count($foo) + 1, 3) ? '\n' : null) . '[class='.($i + 1).']'; $t = count($foo) == 1 ? Lang::$game['class'] : Lang::$game['classes']; - $infobox[] = Util::ucFirst($t).Lang::$colon.implode(', ', $foo); + $infobox[] = Util::ucFirst($t).Lang::$main['colon'].implode(', ', $foo); } // required level @@ -69,11 +69,11 @@ if (!$smarty->loadCache($cacheKeyPage, $pageData)) // type if ($_ty) - $infobox[] = Lang::$game['type'].lang::$colon.Lang::$itemset['types'][$_ty]; + $infobox[] = Lang::$game['type'].Lang::$main['colon'].Lang::$itemset['types'][$_ty]; // tag if ($_ta) - $infobox[] = Lang::$itemset['_tag'].Lang::$colon.'[url=?itemsets&filter=ta='.$_ta.']'.Lang::$itemset['notes'][$_ta].'[/url]'; + $infobox[] = Lang::$itemset['_tag'].Lang::$main['colon'].'[url=?itemsets&filter=ta='.$_ta.']'.Lang::$itemset['notes'][$_ta].'[/url]'; /****************/ /* Main Content */ @@ -208,7 +208,7 @@ if (!$smarty->loadCache($cacheKeyPage, $pageData)) 'relTabs' => [] ); - $iSet->addGlobalsToJscript(); + $iSet->getJSGlobals(); /**************/ /* Extra Tabs */ @@ -262,7 +262,7 @@ if (!$smarty->loadCache($cacheKeyPage, $pageData)) if (!$mask) $pageData['related']['params']['hiddenCols'] = "$['classes']"; - $relSets->addGlobalsToJscript(); + $relSets->getJSGlobals(); } } @@ -272,7 +272,7 @@ if (!$smarty->loadCache($cacheKeyPage, $pageData)) $smarty->updatePageVars($pageData['page']); $smarty->assign('community', CommunityContent::getAll(TYPE_ITEMSET, $_id)); // comments, screenshots, videos -$smarty->assign('lang', array_merge(Lang::$main, Lang::$itemset, ['colon' => Lang::$colon])); +$smarty->assign('lang', array_merge(Lang::$main, Lang::$itemset, ['colon' => Lang::$main['colon']])); $smarty->assign('lvData', $pageData['relTabs']); // load the page diff --git a/pages/itemsets.php b/pages/itemsets.php index a6ee4c29..b364bce4 100644 --- a/pages/itemsets.php +++ b/pages/itemsets.php @@ -14,7 +14,7 @@ if (!$smarty->loadCache($cacheKey, $pageData, $filter)) $itemsetFilter = new ItemsetListFilter(); $itemsets = new ItemsetList([$itemsetFilter->getConditions()]); - $itemsets->addGlobalsToJscript(); + $itemsets->getJSGlobals(); // recreate form selection $filter = array_merge($itemsetFilter->getForm('form'), $filter); @@ -70,7 +70,7 @@ asort(Lang::$game['cl']); $smarty->updatePageVars($pageData['page']); $smarty->assign('filter', $filter); -$smarty->assign('lang', array_merge(Lang::$main, Lang::$game, Lang::$itemset, Lang::$item, ['colon' => lang::$colon])); +$smarty->assign('lang', array_merge(Lang::$main, Lang::$game, Lang::$itemset, Lang::$item, ['colon' => Lang::$main['colon']])); $smarty->assign('lvData', $pageData['lv']); // load the page diff --git a/pages/object.php b/pages/object.php index 5a0622f9..ea55d85f 100644 --- a/pages/object.php +++ b/pages/object.php @@ -65,7 +65,7 @@ class ObjectPage extends GenericPage /* Infobox */ /***********/ - $infobox = []; + $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); // Event if ($_ = DB::Aowow()->selectRow('SELECT e.id, holidayId FROM ?_events e, game_event_gameobject geg, gameobject g WHERE e.id = ABS(geg.eventEntry) AND g.guid = geg.guid AND g.id = ?d', $this->typeId)) @@ -393,17 +393,15 @@ class ObjectPage extends GenericPage $reqQuest = []; if ($_ = $this->subject->getField('lootId')) { - include 'includes/loot.class.php'; - - if (Loot::getByContainer(LOOT_GAMEOBJECT, $_)) + $goLoot = new Loot(); + if ($goLoot->getByContainer(LOOT_GAMEOBJECT, $_)) { - $extraCols = Loot::$extraCols; + $extraCols = $goLoot->extraCols; $hiddenCols = ['source', 'side', 'slot', 'reqlevel']; - $itemLoot = Loot::getResult(); - $this->extendGlobalData(Loot::$jsGlobals); + $this->extendGlobalData($goLoot->jsGlobals); - foreach ($itemLoot as $l => $lv) + foreach ($goLoot->iterate() as &$lv) { if (!empty($hiddenCols)) foreach ($hiddenCols as $k => $str) @@ -417,14 +415,14 @@ class ObjectPage extends GenericPage $reqQuest[$lv['id']] = 0; - $itemLoot[$l]['condition'][] = ['type' => TYPE_QUEST, 'typeId' => &$reqQuest[$lv['id']], 'status' => 1]; + $lv['condition'][] = ['type' => TYPE_QUEST, 'typeId' => &$reqQuest[$lv['id']], 'status' => 1]; } $extraCols[] = 'Listview.extraCols.percent'; $this->lvData[] = array( 'file' => 'item', - 'data' => $itemLoot, + 'data' => $goLoot->getResult(), 'params' => [ 'tabs' => '$tabsRelated', 'name' => '$LANG.tab_contains', @@ -481,7 +479,7 @@ class ObjectPage extends GenericPage protected function generateTooltip($asError = false) { if ($asError) - die('$WowheadPower.registerObject('.$this->typeId.', '.User::$localeId.', {});'); + return '$WowheadPower.registerObject('.$this->typeId.', '.User::$localeId.', {});'; $s = $this->subject->getSpawns(true); diff --git a/static/js/global.js b/static/js/global.js index eb2c0f9c..8bbef298 100644 --- a/static/js/global.js +++ b/static/js/global.js @@ -6358,7 +6358,7 @@ Listview.extraCols = { cnd.color = cond.status ? 'q2' : 'q10'; cnd.links = [{ icon: item.icon.toLowerCase(), - name: $WH.ct(item['name_' + g_locale.name]), + name: item['name_' + g_locale.name], url : '?skill=' + cond.typeId }]; @@ -6380,7 +6380,7 @@ Listview.extraCols = { cnd.color = cond.status ? 'q2' : 'q10'; cnd.links = [{ icon: item.icon.toLowerCase(), - name: $WH.ct(item['name_' + g_locale.name]), + name: item['name_' + g_locale.name], url : '?spell=' + cond.typeId }]; @@ -6399,7 +6399,7 @@ Listview.extraCols = { cnd.color = cond.status ? 'q2' : 'q10'; cnd.links = [{ icon : item.icon.toLowerCase(), - name : $WH.ct(item['name_' + g_locale.name]), + name : item['name_' + g_locale.name], url : '?item=' + cond.typeId, color: 'q' + item.quality }]; @@ -6419,7 +6419,7 @@ Listview.extraCols = { cnd.color = cond.status ? 'q2' : 'q10'; cnd.links = [{ icon: item.icon.toLowerCase(), - name: $WH.ct(item['name_' + g_locale.name]), + name: item['name_' + g_locale.name], url : '?achievement=' + cond.typeId }]; @@ -6437,7 +6437,7 @@ Listview.extraCols = { cnd.state = $WH.ct((cond.status == 1 ? LANG.progress : (cond.status == 2 ? LANG.pr_note_complete : LANG.pr_note_incomplete)) + LANG.colon); cnd.color = cond.status == 1 ? 'q1' : cond.status == 2 ? 'q2' : 'q10'; cnd.links = [{ - name: $WH.ct(item['name_' + g_locale.name]), + name: item['name_' + g_locale.name], url : '?quest=' + cond.typeId }]; @@ -6459,7 +6459,7 @@ Listview.extraCols = { for (var i = 0, len = races.length; i < len; ++i) { cnd.links.push({ - name: $WH.ct(g_chr_races[races[i]]), + name: g_chr_races[races[i]], url : '?class=' + races[i] }); } diff --git a/template/bricks/book.tpl.php b/template/bricks/book.tpl.php index 5529ceb4..aea68c21 100644 --- a/template/bricks/book.tpl.php +++ b/template/bricks/book.tpl.php @@ -2,7 +2,7 @@ if (!empty($this->pageText)): ?>
-

+

diff --git a/template/pages/detail-page-generic.tpl.php b/template/pages/detail-page-generic.tpl.php index 0f7bcb05..79b3281d 100644 --- a/template/pages/detail-page-generic.tpl.php +++ b/template/pages/detail-page-generic.tpl.php @@ -9,8 +9,8 @@ diff --git a/template/pages/item.tpl b/template/pages/item.tpl deleted file mode 100644 index 74f2688c..00000000 --- a/template/pages/item.tpl +++ /dev/null @@ -1,83 +0,0 @@ -{include file='header.tpl'} - -
-
-
- -{if !empty($announcements)} - {foreach from=$announcements item=item} - {include file='bricks/announcement.tpl' an=$item} - {/foreach} -{/if} - - - -{include file='bricks/infobox.tpl'} - -
-{include file='bricks/redButtons.tpl'} - - {$name}{else}>{$name}{/if} - -{include file='bricks/tooltip.tpl'} - -{include file='bricks/article.tpl'} - -{if !empty($disabled)} -
- {$lang._unavailable} -{/if} -{if !empty($transfer)} -
- {$transfer} -{/if} -{if !empty($subItems)} -
-

{$lang._rndEnchants}

- -
-
    - {foreach from=$subItems item=i key=k}{if $k < (count($subItems) / 2)} -
  • - ...{$i.name} - {$lang._chance|@sprintf:$i.chance} -
    {$i.enchantment} -
  • - {/if}{/foreach} -
-
- - {if count($subItems) > 1} -
-
    - {foreach from=$subItems item=i key=k}{if $k >= (count($subItems) / 2)} -
  • - ...{$i.name} - {$lang._chance|@sprintf:$i.chance} -
    {$i.enchantment} -
  • - {/if}{/foreach} -
-
- {/if} -{/if} -{include file='bricks/book.tpl'} - -

{$lang.related}

-
- -{include file='bricks/tabsRelated.tpl' tabs=$lvData} - -{include file='bricks/contribute.tpl'} - -
-
- -{include file='footer.tpl'} diff --git a/template/pages/item.tpl.php b/template/pages/item.tpl.php new file mode 100644 index 00000000..78a58c5d --- /dev/null +++ b/template/pages/item.tpl.php @@ -0,0 +1,94 @@ +brick('header'); ?> + +
+
+
+ +brick('announcement'); ?> + + + +brick('infobox'); ?> + +
+brick('redButtons'); ?> + +

name; ?>

+ +brick('tooltip'); + + $this->brick('article'); + +if ($this->disabled): +?> +
+ +transfer)): + echo "
\n ".$this->transfer."\n"; +endif; + +if (!empty($this->subItems)): +?> +
+

+ +
+
    +subItems['data'] as $k => $i): + if ($k < (count($this->subItems['data']) / 2)): + echo '
  • ...'.$i['name'].''; + echo ' '.sprintf(Lang::$item['_chance'], $i['chance']).'
    '.$i['enchantment'].'
  • '; + endif; + endforeach; +?> +
+
+subItems) > 1): +?> +
+
    +subItems['data'] as $k => $i): + if ($k >= (count($this->subItems['data']) / 2)): + echo '
  • ...'.$i['name'].''; + echo ' '.sprintf(Lang::$item['_chance'], $i['chance']).'
    '.$i['enchantment'].'
  • '; + endif; + endforeach; +?> +
+
+brick('book'); +?> + +

+
+ +brick('tabsRelated'); + + $this->brick('contribute'); +?> + +
+
+ +brick('footer'); ?> diff --git a/template/pages/items.tpl b/template/pages/items.tpl deleted file mode 100644 index 0b8017d8..00000000 --- a/template/pages/items.tpl +++ /dev/null @@ -1,196 +0,0 @@ -{include file='header.tpl'} - -
-
-
- -{if !empty($announcements)} - {foreach from=$announcements item=item} - {include file='bricks/announcement.tpl' an=$item} - {/foreach} -{/if} - - - -
-
- -
-
{$lang._quality}{$lang.colon}
- {$lang.clear} -
- -
- -{if !empty($filter.slot)} -
-
{$lang.slot}{$lang.colon}
- {$lang.clear} -
- -
-{/if} - -{if !empty($filter.type)} -
-
{$lang.type}{$lang.colon}
- {$lang.clear} -
- -
-{/if} - - - - - - - - - - - - - - - - - -
{$lang.name|ucFirst}{$lang.colon} 
{$lang.level}{$lang.colon}  - - - - - - -
   {$lang._reqLevel}{$lang.colon}  -
-
{$lang.usableBy}{$lang.colon}  -  
- -
- - -
-
{$lang.refineSearch}
- {$lang.match}{$lang.colon} -
- -
- - - - - -
-
{$lang.groupBy}{$lang.colon} -{foreach from=$lang.gb key=k item=str} - {if $k == 0} - - {else} - - {/if} -{/foreach} -
- -
- -
- - -
- - - -
- -
-
-
- - - -{if $lvData.isGrouped} -
-{/if} -
- - -
-
-
- -{include file='footer.tpl'} diff --git a/template/pages/items.tpl.php b/template/pages/items.tpl.php new file mode 100644 index 00000000..c59677b2 --- /dev/null +++ b/template/pages/items.tpl.php @@ -0,0 +1,226 @@ +brick('header'); +$f = $this->filter; // shorthand +?> + +
+
+
+ +brick('announcement'); ?> + + + +
+
+ +
+
+ +
+ +
+ + +
+
+ +
+ +
+ +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + +
 />
 /> - /> + + + + + +
    /> - />
+
  +  
+ +
+
+ +
+
+ />/> +
+ +
+ +
+

+
+ + + +
+
+ $str): + if ($k): + echo ' \n"; + else: + echo ' \n"; + endif; +endforeach; +?> +
+ +
+ +
+ + +
+ + /> + +
+ +
+
+
+ + + +hasGroupedTabs): + echo "
\n"; +endif; +?> +
+ + +
+
+
+ +brick('footer'); ?> diff --git a/template/pages/object.tpl.php b/template/pages/object.tpl.php index 48c43009..67d7bd14 100644 --- a/template/pages/object.tpl.php +++ b/template/pages/object.tpl.php @@ -9,8 +9,8 @@