Template/Update (Part 18)

* convert dbtype 'item'
 * StatsContainer::toJson - exclude empty values in listviews + xml
This commit is contained in:
Sarjuuk
2025-08-08 23:25:13 +02:00
parent 11bb5a521b
commit 26226e2bad
24 changed files with 844 additions and 742 deletions

View File

@@ -6,142 +6,80 @@ if (!defined('AOWOW_REVISION'))
die('illegal access');
// menuId 0: Item g_initPath()
// tabId 0: Database g_initHeader()
class ItemPage extends genericPage
class ItemBaseResponse extends TemplateResponse implements ICache
{
use TrDetailPage;
use TrDetailPage, TrCache;
protected $pageText = [];
protected $tooltip = null;
protected $unavailable = false;
protected $subItems = [];
protected int $cacheType = CACHE_TYPE_PAGE;
protected $type = Type::ITEM;
protected $typeId = 0;
protected $tpl = 'item';
protected $path = [0, 0];
protected $tabId = 0;
protected $mode = CACHE_TYPE_PAGE;
protected $enhancedTT = [];
protected $scripts = array(
protected string $template = 'item';
protected string $pageName = 'item';
protected ?int $activeTab = parent::TAB_DATABASE;
protected array $breadcrumb = [0, 0];
protected array $scripts = array(
[SC_JS_FILE, 'js/swfobject.js'],
[SC_JS_FILE, 'js/profile.js'],
[SC_JS_FILE, 'js/filters.js']
);
protected $_get = array(
'domain' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\Locale::tryFromDomain'],
'rand' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkInt'],
'ench' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkInt'],
'gems' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkIntArray'],
'sock' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkEmptySet']
);
public int $type = Type::ITEM;
public int $typeId = 0;
public bool $unavailable = false;
public ?Book $book = null;
public ?array $subItems = null;
public array $tooltip = [];
private $powerTpl = '$WowheadPower.registerItem(%s, %d, %s);';
private ItemList $subject;
public function __construct($pageCall, $param)
public function __construct(string $id)
{
parent::__construct($pageCall, $param);
parent::__construct($id);
$conditions = [['i.id', intVal($param)]];
$this->typeId = intVal($id);
$this->contribute = Type::getClassAttrib($this->type, 'contribute') ?? CONTRIBUTE_NONE;
}
$this->typeId = intVal($param);
if ($this->mode == CACHE_TYPE_TOOLTIP)
{
// temp locale
if ($this->_get['domain'])
Lang::load($this->_get['domain']);
if ($this->_get['rand'])
$this->enhancedTT['r'] = $this->_get['rand'];
if ($this->_get['ench'])
$this->enhancedTT['e'] = $this->_get['ench'];
if ($this->_get['gems'])
$this->enhancedTT['g'] = $this->_get['gems'];
if ($this->_get['sock'])
$this->enhancedTT['s'] = '';
}
else if ($this->mode == CACHE_TYPE_XML)
{
// temp locale
if ($this->_get['domain'])
Lang::load($this->_get['domain']);
// allow lookup by name for xml
if (!is_numeric($param))
$conditions = [['name_loc'.Lang::getLocale()->value, urldecode($param)]];
}
$this->subject = new ItemList($conditions);
protected function generate() : void
{
$this->subject = new ItemList(array(['i.id', $this->typeId]));
if ($this->subject->error)
$this->notFound(Lang::game('item'), Lang::item('notFound'));
$this->generateNotFound(Lang::game('item'), Lang::item('notFound'));
if (!is_numeric($param))
$this->typeId = $this->subject->id;
$jsg = $this->subject->getJSGlobals(GLOBALINFO_EXTRA | GLOBALINFO_SELF, $extra);
$this->extendGlobalData($jsg, $extra);
$this->name = Lang::unescapeUISequences($this->subject->getField('name', true), Lang::FMT_HTML);
$this->h1 = Lang::unescapeUISequences($this->subject->getField('name', true), Lang::FMT_HTML);
if ($this->mode == CACHE_TYPE_PAGE)
{
$jsg = $this->subject->getJSGlobals(GLOBALINFO_EXTRA | GLOBALINFO_SELF, $extra);
$this->extendGlobalData($jsg, $extra);
}
}
protected function generatePath()
{
$_class = $this->subject->getField('class');
$_subClass = $this->subject->getField('subClass');
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, Lang::unescapeUISequences($this->subject->getField('name', true), Lang::FMT_RAW), Util::ucFirst(Lang::game('item')));
}
protected function generateContent()
{
$this->addScript([SC_JS_FILE, '?data=weight-presets.zones']);
$this->gPageInfo += array(
'type' => $this->type,
'typeId' => $this->typeId,
'name' => $this->h1
);
$_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');
$_displayId = $this->subject->getField('displayId');
$_ilvl = $this->subject->getField('itemLevel');
$_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
);
/*************/
/* Menu Path */
/*************/
if ($path = $this->followBreadcrumbPath())
array_push($this->breadcrumb, ...$path);
/**************/
/* Page Title */
/**************/
array_unshift($this->title, Lang::unescapeUISequences($this->subject->getField('name', true), Lang::FMT_RAW), Util::ucFirst(Lang::game('item')));
/***********/
/* Infobox */
@@ -159,8 +97,12 @@ class ItemPage extends genericPage
// 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]';
$infobox[] = Lang::main('side') . match ($si)
{
SIDE_ALLIANCE => '[span class=icon-alliance]'.Lang::game('si', SIDE_ALLIANCE).'[/span]',
SIDE_HORDE => '[span class=icon-horde]'.Lang::game('si', SIDE_HORDE).'[/span]',
SIDE_BOTH => Lang::game('si', SIDE_BOTH)
};
// icon
if ($_ = $this->subject->getField('iconId'))
@@ -188,20 +130,20 @@ class ItemPage extends genericPage
}
if ($hasUse)
$infobox[] = isset($tt) ? $tt : '[tooltip=tooltip_notconsumedonuse]'.Lang::item('nonConsumable').'[/tooltip]';
$infobox[] = $tt ?? '[tooltip=tooltip_notconsumedonuse]'.Lang::item('nonConsumable').'[/tooltip]';
}
// related holiday
if ($eId = $this->subject->getField('eventId'))
{
$this->extendGlobalIds(Type::WORLDEVENT, $eId);
$infobox[] = Lang::game('eventShort').Lang::main('colon').'[event='.$eId.']';
$infobox[] = Lang::game('eventShort', ['[event='.$eId.']']);
}
// 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]';
if ($tName = DB::Aowow()->selectRow('SELECT * FROM ?_totemcategory WHERE `id` = ?d', $tId))
$infobox[] = Lang::item('tool').'[url=?items&filter=cr=91;crs='.$tId.';crv=0]'.Util::localizedString($tName, 'name').'[/url]';
// extendedCost
if (!empty($this->subject->getExtendedCost([], $_reqRating)[$this->subject->id]))
@@ -265,17 +207,17 @@ class ItemPage extends genericPage
else
$cost = '[money';
$stringify = function(&$v) use ($divisor) { return $v = $v[0] . ',' . ($v[1] / $divisor); };
$stringify = fn(&$x) => $x = $x[0] . ',' . ($x[1] / $divisor);
if ($tokens)
{
array_walk($tokens, $stringify, $divisor);
array_walk($tokens, $stringify);
$cost .= ' items='.implode(',', $tokens);
}
if ($currency)
{
array_walk($currency, $stringify, $divisor);
array_walk($currency, $stringify);
$cost .= ' currency='.implode(',', $currency);
}
@@ -304,7 +246,7 @@ class ItemPage extends genericPage
// repair cost
if ($_ = $this->subject->getField('repairPrice'))
$infobox[] = Lang::item('repairCost').Lang::main('colon').'[money='.$_.']';
$infobox[] = Lang::item('repairCost').'[money='.$_.']';
// avg auction buyout
if (in_array($this->subject->getField('bonding'), [0, 2, 3]))
@@ -314,7 +256,7 @@ class ItemPage extends genericPage
// 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]';
$infobox[] = Lang::item('worth').'[tooltip=tooltip_avgmoneycontained][money='.$_.'][/tooltip]';
// if it goes into a slot it may be disenchanted
if ($_slot && $_class != ITEM_CLASS_CONTAINER)
@@ -375,28 +317,31 @@ class ItemPage extends genericPage
if ($_bagFamily & 0x0100)
$infobox[] = Lang::item('atKeyring');
if ($infobox)
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
/****************/
/* Main Content */
/****************/
$_cu = in_array($_class, [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]) || $this->subject->getField('gemEnchantmentId');
if ($canBeWeighted = in_array($_class, [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR, ITEM_CLASS_GEM]))
$this->addDataLoader('weight-presets');
// pageText
if ($this->pageText = Game::getBook($this->subject->getField('pageTextId')))
if ($this->book = Game::getBook($this->subject->getField('pageTextId')))
$this->addScript(
[SC_JS_FILE, 'js/Book.js'],
[SC_CSS_FILE, 'css/Book.css']
);
$this->headIcons = [$this->subject->getField('iconString', true, true), $this->subject->getField('stackable')];
$this->infobox = $infobox ? '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]' : null;
$this->tooltip = $this->subject->renderTooltip(true);
$this->tooltip = [$this->subject->getField('iconString'), $this->subject->getField('stackable'), false];
$this->redButtons = array(
BUTTON_WOWHEAD => true,
BUTTON_VIEW3D => in_array($_slot, $_visSlots) && $_model ? ['displayId' => $this->subject->getField('displayId'), 'slot' => $_slot, 'type' => Type::ITEM, 'typeId' => $this->typeId] : false,
BUTTON_COMPARE => $_cu,
BUTTON_VIEW3D => $this->subject->isDisplayable() ? ['displayId' => $_displayId, 'slot' => $_slot, 'type' => Type::ITEM, 'typeId' => $this->typeId] : false,
BUTTON_COMPARE => $canBeWeighted,
BUTTON_EQUIP => in_array($_class, [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]),
BUTTON_UPGRADE => ($_cu ? ['class' => $_class, 'slot' => $_slot] : false),
BUTTON_UPGRADE => $canBeWeighted ? ['class' => $_class, 'slot' => $_slot] : false,
BUTTON_LINKS => array(
'linkColor' => 'ff'.Game::$rarityColorStings[$this->subject->getField('quality')],
'linkId' => 'item:'.$this->typeId.':0:0:0:0:0:0:0:0',
@@ -413,7 +358,7 @@ class ItemPage extends genericPage
$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']); });
uaSort($this->subject->subItems[$this->typeId], fn($a, $b) => $a['name'] <=> $b['name']);
$this->subItems = array(
'data' => array_values($this->subject->subItems[$this->typeId]),
'randIds' => array_keys($this->subject->subItems[$this->typeId]),
@@ -440,29 +385,31 @@ class ItemPage extends genericPage
}
// factionchange-equivalent
if ($pendant = DB::World()->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))
if ($pendant = DB::World()->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'),
$this->transfer = Lang::item('_transfer', [
$altItem->id,
$altItem->getField('quality'),
$altItem->getField('iconString', true, true),
$altItem->getField('iconString'),
$altItem->getField('name', true),
$pendant > 0 ? 'alliance' : 'horde',
$pendant > 0 ? Lang::game('si', 1) : Lang::game('si', 2)
);
$pendant > 0 ? Lang::game('si', SIDE_ALLIANCE) : Lang::game('si', SIDE_HORDE)
]);
}
}
/**************/
/* Extra Tabs */
/**************/
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
// tab: createdBy (perfect item specific)
if ($perfItem = DB::World()->select('SELECT *, spellId AS ARRAY_KEY FROM skill_perfect_item_template WHERE perfectItemType = ?d', $this->typeId))
if ($perfItem = DB::World()->select('SELECT *, `spellId` AS ARRAY_KEY FROM skill_perfect_item_template WHERE `perfectItemType` = ?d', $this->typeId))
{
$perfSpells = new SpellList(array(['id', array_column($perfItem, 'spellId')]));
if (!$perfSpells->error)
@@ -477,12 +424,12 @@ class ItemPage extends genericPage
$this->extendGlobalIDs(Type::SPELL, $perfItem[$sId]['requiredSpecialization']);
}
$this->lvTabs[] = [SpellList::$brickFile, array(
'data' => array_values($lvData),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $lvData,
'name' => '$LANG.tab_createdby',
'id' => 'created-by', // should by exclusive with created-by from spell_loot
'extraCols' => ['$Listview.extraCols.percent', '$Listview.extraCols.condition']
)];
), SpellList::$brickFile));
}
}
@@ -493,7 +440,7 @@ class ItemPage extends genericPage
{
$this->extendGlobalData($lootTabs->jsGlobals);
foreach ($lootTabs->iterate() as $idx => [$file, $tabData])
foreach ($lootTabs->iterate() as $idx => [$template, $tabData])
{
if (!$tabData['data'])
continue;
@@ -518,7 +465,10 @@ class ItemPage extends genericPage
}
}
$this->lvTabs[] = [$file, $tabData];
if ($template == 'npc' || $template == 'object')
$this->addDataLoader('zones');
$this->lvTabs->addListviewTab(new Listview($tabData, $template));
}
}
@@ -539,7 +489,7 @@ class ItemPage extends genericPage
$extraCols = array_merge($extraCols, $lootTab->extraCols);
$tabData = array(
'data' => array_values($lootTab->getResult()),
'data' => $lootTab->getResult(),
'name' => $tabName,
'id' => $tabId,
);
@@ -550,7 +500,7 @@ class ItemPage extends genericPage
if ($hiddenCols)
$tabData['hiddenCols'] = array_unique($hiddenCols);
$this->lvTabs[] = [ItemList::$brickFile, $tabData];
$this->lvTabs->addListviewTab(new Listview($tabData, ItemList::$brickFile));
}
}
@@ -566,12 +516,12 @@ class ItemPage extends genericPage
if (!$contains->hasSetFields('slot'))
$hCols[] = 'slot';
$this->lvTabs[] = [ItemList::$brickFile, array(
'data' => array_values($contains->getListviewData()),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $contains->getListviewData(),
'name' => '$LANG.tab_cancontain',
'id' => 'can-contain',
'hiddenCols' => $hCols
)];
), ItemList::$brickFile));
}
}
@@ -583,12 +533,12 @@ class ItemPage extends genericPage
{
$this->extendGlobalData($contains->getJSGlobals(GLOBALINFO_SELF));
$this->lvTabs[] = [ItemList::$brickFile, array(
'data' => array_values($contains->getListviewData()),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $contains->getListviewData(),
'name' => '$LANG.tab_canbeplacedin',
'id' => 'can-be-placed-in',
'hiddenCols' => ['side']
)];
), ItemList::$brickFile));
}
}
@@ -604,7 +554,7 @@ class ItemPage extends genericPage
$this->extendGlobalData($criteriaOf->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
$tabData = array(
'data' => array_values($criteriaOf->getListviewData()),
'data' => $criteriaOf->getListviewData(),
'name' => '$LANG.tab_criteriaof',
'id' => 'criteria-of',
'visibleCols' => ['category']
@@ -613,7 +563,7 @@ class ItemPage extends genericPage
if (!$criteriaOf->hasSetFields('reward_loc0'))
$tabData['hiddenCols'] = ['rewards'];
$this->lvTabs[] = [AchievementList::$brickFile, $tabData];
$this->lvTabs->addListviewTab(new Listview($tabData, AchievementList::$brickFile));
}
// tab: reagent for
@@ -628,19 +578,19 @@ class ItemPage extends genericPage
{
$this->extendGlobalData($reagent->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
$this->lvTabs[] = [SpellList::$brickFile, array(
'data' => array_values($reagent->getListviewData()),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $reagent->getListviewData(),
'name' => '$LANG.tab_reagentfor',
'id' => 'reagent-for',
'visibleCols' => ['reagents']
)];
), SpellList::$brickFile));
}
// tab: unlocks (object or item)
// tab: unlocks (object or item) - LOCK_TYPE_ITEM: 1
$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)',
'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
);
@@ -650,11 +600,12 @@ class ItemPage extends genericPage
$lockedObj = new GameObjectList(array(['lockId', $lockIds]));
if (!$lockedObj->error)
{
$this->lvTabs[] = [GameObjectList::$brickFile, array(
'data' => array_values($lockedObj->getListviewData()),
$this->addDataLoader('zones');
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $lockedObj->getListviewData(),
'name' => '$LANG.tab_unlocks',
'id' => 'unlocks-object'
)];
'id' => 'unlocks-object',
), GameObjectList::$brickFile));
}
// items (generally unused. It's the spell on the item, that unlocks stuff)
@@ -663,11 +614,11 @@ class ItemPage extends genericPage
{
$this->extendGlobalData($lockedItm->getJSGlobals(GLOBALINFO_SELF));
$this->lvTabs[] = [ItemList::$brickFile, array(
'data' => array_values($lockedItm->getListviewData()),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $lockedItm->getListviewData(),
'name' => '$LANG.tab_unlocks',
'id' => 'unlocks-item'
)];
), ItemList::$brickFile));
}
}
@@ -698,11 +649,11 @@ class ItemPage extends genericPage
{
$this->extendGlobalData($saItems->getJSGlobals(GLOBALINFO_SELF));
$this->lvTabs[] = [ItemList::$brickFile, array(
'data' => array_values($saItems->getListviewData()),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $saItems->getListviewData(),
'name' => '$LANG.tab_seealso',
'id' => 'see-also'
)];
), ItemList::$brickFile));
}
// tab: starts (quest)
@@ -713,11 +664,11 @@ class ItemPage extends genericPage
{
$this->extendGlobalData($starts->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
$this->lvTabs[] = [QuestList::$brickFile, array(
'data' => array_values($starts->getListviewData()),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $starts->getListviewData(),
'name' => '$LANG.tab_starts',
'id' => 'starts-quest'
)];
), QuestList::$brickFile));
}
}
@@ -732,11 +683,11 @@ class ItemPage extends genericPage
{
$this->extendGlobalData($objective->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
$this->lvTabs[] = [QuestList::$brickFile, array(
'data' => array_values($objective->getListviewData()),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $objective->getListviewData(),
'name' => '$LANG.tab_objectiveof',
'id' => 'objective-of-quest'
)];
), QuestList::$brickFile));
}
// tab: provided for (quest)
@@ -750,11 +701,11 @@ class ItemPage extends genericPage
{
$this->extendGlobalData($provided->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
$this->lvTabs[] = [QuestList::$brickFile, array(
'data' => array_values($provided->getListviewData()),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $provided->getListviewData(),
'name' => '$LANG.tab_providedfor',
'id' => 'provided-for-quest'
)];
), QuestList::$brickFile));
}
// tab: same model as
@@ -766,12 +717,12 @@ class ItemPage extends genericPage
{
$this->extendGlobalData($sameModel->getJSGlobals(GLOBALINFO_SELF));
$this->lvTabs[] = ['genericmodel', array(
'data' => array_values($sameModel->getListviewData(ITEMINFO_MODEL)),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $sameModel->getListviewData(ITEMINFO_MODEL),
'name' => '$LANG.tab_samemodelas',
'id' => 'same-model-as',
'genericlinktype' => 'item'
)];
), 'genericmodel'));
}
}
@@ -785,7 +736,12 @@ class ItemPage extends genericPage
// show mapper for vendors
if ($vendorSpawns = $soldBy->getSpawns(SPAWNINFO_FULL, true, true, true, true))
{
$this->map = ['data' => ['parent' => 'mapper-generic'], 'mapperData' => &$vendorSpawns, 'foundIn' => Lang::item('purchasedIn')];
$this->map = array(
['parent' => 'mapper-generic'], // Mapper
$vendorSpawns, // mapperData
null, // ShowOnMap
[Lang::item('purchasedIn')] // foundIn
);
foreach ($vendorSpawns as $areaId => $_)
$this->map['extra'][$areaId] = ZoneList::getName($areaId);
}
@@ -839,13 +795,14 @@ class ItemPage extends genericPage
if ($cnd->toListviewColumn($sbData, $extraCols, 'id', $this->typeId))
$this->extendGlobalData($cnd->getJsGlobals());
$this->lvTabs[] = [CreatureList::$brickFile, array(
'data' => array_values($sbData),
$this->addDataLoader('zones');
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $sbData,
'name' => '$LANG.tab_soldby',
'id' => 'sold-by-npc',
'extraCols' => $extraCols,
'hiddenCols' => ['level', 'type']
)];
), CreatureList::$brickFile));
}
}
@@ -865,7 +822,7 @@ class ItemPage extends genericPage
else
$w = '`reqItemId1` = '.$this->typeId.' OR `reqItemId2` = '.$this->typeId.' OR `reqItemId3` = '.$this->typeId.' OR `reqItemId4` = '.$this->typeId.' OR `reqItemId5` = '.$this->typeId;
if (!$n && ItemListFilter::isCurrencyFor($this->typeId))
if (!$n && !is_null(ItemListFilter::getCriteriaIndex(158, $this->typeId)))
$n = '?items&filter=cr=158;crs='.$this->typeId.';crv=0';
$xCosts = DB::Aowow()->selectCol('SELECT `id` FROM ?_itemextendedcost WHERE '.$w);
@@ -879,7 +836,7 @@ class ItemPage extends genericPage
$filter = $iCur->error ? [Type::ITEM => $this->typeId] : [Type::CURRENCY => $iCur->id];
$tabData = array(
'data' => array_values($boughtBy->getListviewData(ITEMINFO_VENDOR, $filter)),
'data' => $boughtBy->getListviewData(ITEMINFO_VENDOR, $filter),
'name' => '$LANG.tab_currencyfor',
'id' => 'currency-for',
'extraCols' => ["\$Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')", '$Listview.extraCols.cost']
@@ -888,7 +845,7 @@ class ItemPage extends genericPage
if ($n)
$tabData['note'] = sprintf(Util::$filterResultString, $n);
$this->lvTabs[] = [ItemList::$brickFile, $tabData];
$this->lvTabs->addListviewTab(new Listview($tabData, ItemList::$brickFile));
$this->extendGlobalData($boughtBy->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
}
@@ -927,12 +884,12 @@ class ItemPage extends genericPage
if ($taughtSpells->hasSetFields('reagent1', 'reagent2', 'reagent3', 'reagent4', 'reagent5', 'reagent6', 'reagent7', 'reagent8'))
$visCols[] = 'reagents';
$this->lvTabs[] = [SpellList::$brickFile, array(
'data' => array_values($taughtSpells->getListviewData()),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $taughtSpells->getListviewData(),
'name' => '$LANG.tab_teaches',
'id' => 'teaches',
'visibleCols' => $visCols
)];
), SpellList::$brickFile));
}
}
@@ -950,7 +907,7 @@ class ItemPage extends genericPage
$useSpells[] = $this->subject->getField('spellId'.$i);
}
if ($useSpells)
if ($_ = DB::Aowow()->selectCol('SELECT category FROM ?_spell WHERE id IN (?a) AND recoveryCategory > 0', $useSpells))
if ($_ = DB::Aowow()->selectCol('SELECT `category` FROM ?_spell WHERE `id` IN (?a) AND `recoveryCategory` > 0', $useSpells))
$cdCats += $_;
if ($cdCats)
@@ -967,18 +924,18 @@ class ItemPage extends genericPage
]
);
if ($spellsByCat = DB::Aowow()->selectCol('SELECT id FROM ?_spell WHERE category IN (?a)', $cdCats))
if ($spellsByCat = DB::Aowow()->selectCol('SELECT `id` FROM ?_spell WHERE `category` IN (?a)', $cdCats))
for ($i = 1; $i < 6; $i++)
$conditions[1][] = ['spellId'.$i, $spellsByCat];
$cdItems = new ItemList($conditions);
if (!$cdItems->error)
{
$this->lvTabs[] = [ItemList::$brickFile, array(
'data' => array_values($cdItems->getListviewData()),
$this->lvTabs->addListviewTab(new Listview(array(
'data' => $cdItems->getListviewData(),
'name' => '$LANG.tab_sharedcooldown',
'id' => 'shared-cooldown'
)];
), ItemList::$brickFile));
$this->extendGlobalData($cdItems->getJSGlobals(GLOBALINFO_SELF));
}
@@ -992,7 +949,7 @@ class ItemPage extends genericPage
if ($this->subject->getField('soundOverrideSubclass') > 0)
$scm = (1 << $this->subject->getField('soundOverrideSubclass'));
$soundIds = DB::Aowow()->selectCol('SELECT soundId FROM ?_items_sounds WHERE subClassMask & ?d', $scm);
$soundIds = DB::Aowow()->selectCol('SELECT `soundId` FROM ?_items_sounds WHERE `subClassMask` & ?d', $scm);
}
$fields = ['pickUpSoundId', 'dropDownSoundId', 'sheatheSoundId', 'unsheatheSoundId'];
@@ -1002,7 +959,7 @@ class ItemPage extends genericPage
if ($x = $this->subject->getField('spellVisualId'))
{
if ($spellSounds = DB::Aowow()->selectRow('SELECT * FROM ?_spell_sounds WHERE id = ?d', $x))
if ($spellSounds = DB::Aowow()->selectRow('SELECT * FROM ?_spell_sounds WHERE `id` = ?d', $x))
{
array_shift($spellSounds); // bye 'id'-field
foreach ($spellSounds as $ss)
@@ -1017,7 +974,7 @@ class ItemPage extends genericPage
if (!$sounds->error)
{
$this->extendGlobalData($sounds->getJSGlobals(GLOBALINFO_SELF));
$this->lvTabs[] = [SoundList::$brickFile, ['data' => array_values($sounds->getListviewData())]];
$this->lvTabs->addListviewTab(new Listview(['data' => $sounds->getListviewData()], SoundList::$brickFile));
}
}
@@ -1027,7 +984,7 @@ class ItemPage extends genericPage
if ($tab = $cnd->toListviewTab('condition-for', '$LANG.tab_condition_for'))
{
$this->extendGlobalData($cnd->getJsGlobals());
$this->lvTabs[] = $tab;
$this->lvTabs->addDataTab(...$tab);
}
@@ -1035,174 +992,39 @@ class ItemPage extends genericPage
// use var $createdBy to find source of this spell
// id: 'taught-by-X',
// name: LANG.tab_taughtby
parent::generate();
}
protected function generateTooltip()
private function followBreadcrumbPath() : array
{
$power = new \StdClass();
if (!$this->subject->error)
{
$power->{'name_'.Lang::getLocale()->json()} = Lang::unescapeUISequences($this->subject->getField('name', true, false, $this->enhancedTT), Lang::FMT_RAW);
$power->quality = $this->subject->getField('quality');
$power->icon = rawurlencode($this->subject->getField('iconString', true, true));
$power->{'tooltip_'.Lang::getLocale()->json()} = $this->subject->renderTooltip(false, 0, $this->enhancedTT);
}
$c = $this->subject->getField('class');
$sc = $this->subject->getField('subClass');
$ssc = $this->subject->getField('subSubClass');
$slot = $this->subject->getField('slot');
$itemString = $this->typeId;
if ($this->enhancedTT)
{
foreach ($this->enhancedTT as $k => $val)
$itemString .= $k.(is_array($val) ? implode(',', $val) : $val);
$itemString = "'".$itemString."'";
}
if ($c == ITEM_CLASS_REAGENT)
return [ITEM_CLASS_MISC, 1]; // misc > reagents
return sprintf($this->powerTpl, $itemString,Lang::getLocale()->value, Util::toJSON($power, JSON_AOWOW_POWER));
}
if ($c == ITEM_CLASS_GENERIC || $c == ITEM_CLASS_PERMANENT)
return [ITEM_CLASS_MISC, 4]; // misc > other
protected function generateXML()
{
$root = new SimpleXML('<aowow />');
// depths: 1
$path = [$c];
if ($this->subject->error)
$root->addChild('error', 'Item not found!');
else
{
// item root
$xml = $root->addChild('item');
$xml->addAttribute('id', $this->typeId);
if (in_array($c, [ITEM_CLASS_MONEY, ITEM_CLASS_QUEST, ITEM_CLASS_KEY]))
return $path;
// name
$xml->addChild('name')->addCData($this->subject->getField('name', true));
// itemlevel
$xml->addChild('level', $this->subject->getField('itemLevel'));
// quality
$xml->addChild('quality', Lang::item('quality', $this->subject->getField('quality')))->addAttribute('id', $this->subject->getField('quality'));
// 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 = $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')]) : Lang::item('cat', $this->subject->getField('class')))->addAttribute('id', $this->subject->getField('subClass'));
// icon + displayId
$xml->addChild('icon', $this->subject->getField('iconString', true, true))->addAttribute('displayId', $this->subject->getField('displayId'));
// inventorySlot
$xml->addChild('inventorySlot', Lang::item('inventoryType', $this->subject->getField('slot')))->addAttribute('id', $this->subject->getField('slot'));
// tooltip
$xml->addChild('htmlTooltip')->addCData($this->subject->renderTooltip());
// depths: 2
$path[] = $sc;
$this->subject->extendJsonStats();
// maybe depths: 3
if ($this->subject->isBodyArmor() && $slot)
$path[] = $slot;
else if (($c == ITEM_CLASS_CONSUMABLE && $sc == ITEM_SUBCLASS_ELIXIR) || $c == ITEM_CLASS_GLYPH)
$path[] = $ssc;
// json
$fields = ['classs', 'displayid', 'dps', 'id', 'level', 'name', 'reqlevel', 'slot', 'slotbak', 'speed', 'subclass'];
$json = [];
foreach ($fields as $f)
{
if (isset($this->subject->json[$this->typeId][$f]))
{
$_ = $this->subject->json[$this->typeId][$f];
if ($f == 'name')
$_ = (7 - $this->subject->getField('quality')).$_;
$json[$f] = $_;
}
}
// itemsource
if ($this->subject->getSources($s, $sm))
{
$json['source'] = $s;
if ($sm)
$json['sourcemore'] = $sm;
}
$xml->addChild('json')->addCData(substr(json_encode($json), 1, -1));
// jsonEquip missing: avgbuyout
$json = [];
if ($_ = $this->subject->getField('sellPrice')) // sellprice
$json['sellprice'] = $_;
if ($_ = $this->subject->getField('requiredLevel')) // reqlevel
$json['reqlevel'] = $_;
if ($_ = $this->subject->getField('requiredSkill')) // reqskill
$json['reqskill'] = $_;
if ($_ = $this->subject->getField('requiredSkillRank')) // reqskillrank
$json['reqskillrank'] = $_;
if ($_ = $this->subject->getField('cooldown')) // cooldown
$json['cooldown'] = $_ / 1000;
Util::arraySumByKey($json, $this->subject->jsonStats[$this->typeId] ?? []);
foreach ($this->subject->json[$this->typeId] as $name => $qty)
if ($idx = Stat::getIndexFrom(Stat::IDX_JSON_STR, $name))
if (Stat::getFilterCriteriumId($idx))
$json[$name] = $qty;
$xml->addChild('jsonEquip')->addCData(substr(json_encode($json), 1, -1));
// jsonUse
if ($onUse = $this->subject->getOnUseStats())
{
$j = '';
foreach ($onUse->toJson() as $key => $amt)
$j .= ',"'.$key.'":'.$amt;
$xml->addChild('jsonUse')->addCData(substr($j, 1));
}
// reagents
$cnd = array(
'OR',
['AND', ['effect1CreateItemId', $this->typeId], ['OR', ['effect1Id', SpellList::EFFECTS_ITEM_CREATE], ['effect1AuraId', SpellList::AURAS_ITEM_CREATE]]],
['AND', ['effect2CreateItemId', $this->typeId], ['OR', ['effect2Id', SpellList::EFFECTS_ITEM_CREATE], ['effect2AuraId', SpellList::AURAS_ITEM_CREATE]]],
['AND', ['effect3CreateItemId', $this->typeId], ['OR', ['effect3Id', SpellList::EFFECTS_ITEM_CREATE], ['effect3AuraId', SpellList::AURAS_ITEM_CREATE]]],
);
$spellSource = new SpellList($cnd);
if (!$spellSource->error)
{
$cbNode = $xml->addChild('createdBy');
foreach ($spellSource->iterate() as $sId => $__)
{
foreach ($spellSource->canCreateItem() as $idx)
{
if ($spellSource->getField('effect'.$idx.'CreateItemId') != $this->typeId)
continue;
$splNode = $cbNode->addChild('spell');
$splNode->addAttribute('id', $sId);
$splNode->addAttribute('name', $spellSource->getField('name', true));
$splNode->addAttribute('icon', $this->subject->getField('iconString', true, true));
$splNode->addAttribute('minCount', $spellSource->getField('effect'.$idx.'BasePoints') + 1);
$splNode->addAttribute('maxCount', $spellSource->getField('effect'.$idx.'BasePoints') + $spellSource->getField('effect'.$idx.'DieSides'));
foreach ($spellSource->getReagentsForCurrent() as $rId => $qty)
{
if ($reagent = $spellSource->relItems->getEntry($rId))
{
$rgtNode = $splNode->addChild('reagent');
$rgtNode->addAttribute('id', $rId);
$rgtNode->addAttribute('name', Util::localizedString($reagent, 'name'));
$rgtNode->addAttribute('quality', $reagent['quality']);
$rgtNode->addAttribute('icon', $reagent['iconString']);
$rgtNode->addAttribute('count', $qty[1]);
}
}
break;
}
}
}
// link
$xml->addChild('link', Cfg::get('HOST_URL').'?item='.$this->subject->id);
}
return $root->asXML();
return $path;
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class ItemPowerResponse extends TextResponse implements ICache
{
use TrCache, TrTooltip;
private const /* string */ POWER_TEMPLATE = '$WowheadPower.registerItem(%s, %d, %s);';
protected int $type = Type::ITEM;
protected int $typeId = 0;
protected int $cacheType = CACHE_TYPE_TOOLTIP;
protected array $expectedGET = array(
'domain' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFromDomain']],
'rand' => ['filter' => FILTER_VALIDATE_INT ],
'ench' => ['filter' => FILTER_VALIDATE_INT ],
'gems' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIntArray'] ],
'sock' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet'] ]
);
public function __construct($param)
{
parent::__construct($param);
// temp locale
if ($this->_get['domain'])
Lang::load($this->_get['domain']);
$this->typeId = intVal($param);
if ($this->_get['rand'])
$this->enhancedTT['r'] = $this->_get['rand'];
if ($this->_get['ench'])
$this->enhancedTT['e'] = $this->_get['ench'];
if ($this->_get['gems'])
$this->enhancedTT['g'] = $this->_get['gems'];
if ($this->_get['sock'])
$this->enhancedTT['s'] = '';
}
protected function generate() : void
{
$item = new ItemList(array(['i.id', $this->typeId]));
if ($item->error)
$this->cacheType = CACHE_TYPE_NONE;
else
{
$itemString = $this->typeId;
foreach ($this->enhancedTT as $k => $val)
$itemString .= $k.(is_array($val) ? implode(',', $val) : $val);
$opts = array(
'name' => Lang::unescapeUISequences($item->getField('name', true, false, $this->enhancedTT), Lang::FMT_RAW),
'tooltip' => $item->renderTooltip(enhance: $this->enhancedTT),
'icon' => $item->getField('iconString'),
'quality' => $item->getField('quality')
);
}
$this->result = new Tooltip(self::POWER_TEMPLATE, $itemString ?? $this->typeId, $opts ?? []);
}
}
?>

231
endpoints/item/item_xml.php Normal file
View File

@@ -0,0 +1,231 @@
<?php
namespace Aowow;
if (!defined('AOWOW_REVISION'))
die('illegal access');
class ItemXmlResponse extends TextResponse implements ICache
{
use TrCache;
protected string $contentType = MIME_TYPE_XML;
protected int $type = Type::ITEM;
protected int $typeId = 0;
protected int $cacheType = CACHE_TYPE_XML;
protected array $expectedGET = array(
'domain' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFromDomain']]
);
private ItemList $subject;
private string $search = '';
public function __construct(string $param)
{
parent::__construct($param);
// temp locale
if ($this->_get['domain'])
Lang::load($this->_get['domain']);
// allow lookup by name
if (is_numeric($param))
$this->typeId = intVal($param);
else
$this->search = urldecode($param);
}
protected function generate() : void
{
if ($this->search)
$conditions = [['name_loc'.Lang::getLocale()->value, $this->search]];
else
$conditions = [['i.id', $this->typeId]];
$this->subject = new ItemList($conditions);
if ($this->subject->error)
{
$this->cacheType = CACHE_TYPE_NONE;
header('HTTP/1.0 404 Not Found', true, 404);
$root = new SimpleXML('<aowow />');
$root->addChild('error', 'Item not found!');
$this->result = $root->asXML();
return;
}
else
$this->typeId = $this->subject->id;
$root = new SimpleXML('<aowow />');
// item root
$xml = $root->addChild('item');
$xml->addAttribute('id', $this->typeId);
// name
$xml->addChild('name')->addCData($this->subject->getField('name', true));
// itemlevel
$xml->addChild('level', $this->subject->getField('itemLevel'));
// quality
$xml->addChild('quality', Lang::item('quality', $this->subject->getField('quality')))->addAttribute('id', $this->subject->getField('quality'));
// 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
$xml->addChild('subclass')->addCData($this->getSubclass())->addAttribute('id', $this->subject->getField('subClass'));
// icon + displayId
$xml->addChild('icon', $this->subject->getField('iconString'))->addAttribute('displayId', $this->subject->getField('displayId'));
// inventorySlot
$xml->addChild('inventorySlot', Lang::item('inventoryType', $this->subject->getField('slot')))->addAttribute('id', $this->subject->getField('slot'));
// tooltip
$xml->addChild('htmlTooltip')->addCData($this->subject->renderTooltip());
$this->subject->extendJsonStats();
// json
$fields = ['classs', 'displayid', 'dps', 'id', 'level', 'name', 'reqlevel', 'slot', 'slotbak', 'speed', 'subclass'];
$json = [];
foreach ($fields as $f)
{
if (isset($this->subject->json[$this->typeId][$f]))
{
$_ = $this->subject->json[$this->typeId][$f];
if ($f == 'name')
$_ = (7 - $this->subject->getField('quality')).$_;
$json[$f] = $_;
}
}
// itemsource
if ($this->subject->getSources($s, $sm))
{
$json['source'] = $s;
if ($sm)
$json['sourcemore'] = $sm;
}
$xml->addChild('json')->addCData(substr(json_encode($json), 1, -1));
// jsonEquip missing: avgbuyout
$json = [];
if ($_ = $this->subject->getField('sellPrice')) // sellprice
$json['sellprice'] = $_;
if ($_ = $this->subject->getField('requiredLevel')) // reqlevel
$json['reqlevel'] = $_;
if ($_ = $this->subject->getField('requiredSkill')) // reqskill
$json['reqskill'] = $_;
if ($_ = $this->subject->getField('requiredSkillRank')) // reqskillrank
$json['reqskillrank'] = $_;
if ($_ = $this->subject->getField('cooldown')) // cooldown
$json['cooldown'] = $_ / 1000;
Util::arraySumByKey($json, $this->subject->jsonStats[$this->typeId] ?? []);
foreach ($this->subject->json[$this->typeId] as $name => $qty)
if ($idx = Stat::getIndexFrom(Stat::IDX_JSON_STR, $name))
if (Stat::getFilterCriteriumId($idx))
$json[$name] = $qty;
$xml->addChild('jsonEquip')->addCData(substr(json_encode($json), 1, -1));
// jsonUse
if ($onUse = $this->subject->getOnUseStats())
{
$j = '';
foreach ($onUse->toJson(includeEmpty: false) as $key => $amt)
$j .= ',"'.$key.'":'.$amt;
$xml->addChild('jsonUse')->addCData(substr($j, 1));
}
// reagents
$cnd = array(
'OR',
['AND', ['effect1CreateItemId', $this->typeId], ['OR', ['effect1Id', SpellList::EFFECTS_ITEM_CREATE], ['effect1AuraId', SpellList::AURAS_ITEM_CREATE]]],
['AND', ['effect2CreateItemId', $this->typeId], ['OR', ['effect2Id', SpellList::EFFECTS_ITEM_CREATE], ['effect2AuraId', SpellList::AURAS_ITEM_CREATE]]],
['AND', ['effect3CreateItemId', $this->typeId], ['OR', ['effect3Id', SpellList::EFFECTS_ITEM_CREATE], ['effect3AuraId', SpellList::AURAS_ITEM_CREATE]]],
);
$spellSource = new SpellList($cnd);
if (!$spellSource->error)
{
$cbNode = $xml->addChild('createdBy');
foreach ($spellSource->iterate() as $sId => $__)
{
foreach ($spellSource->canCreateItem() as $idx)
{
if ($spellSource->getField('effect'.$idx.'CreateItemId') != $this->typeId)
continue;
$splNode = $cbNode->addChild('spell');
$splNode->addAttribute('id', $sId);
$splNode->addAttribute('name', $spellSource->getField('name', true));
$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'));
foreach ($spellSource->getReagentsForCurrent() as $rId => $qty)
{
if ($reagent = $spellSource->relItems->getEntry($rId))
{
$rgtNode = $splNode->addChild('reagent');
$rgtNode->addAttribute('id', $rId);
$rgtNode->addAttribute('name', Util::localizedString($reagent, 'name'));
$rgtNode->addAttribute('quality', $reagent['quality']);
$rgtNode->addAttribute('icon', $reagent['iconString']);
$rgtNode->addAttribute('count', $qty[1]);
}
}
break;
}
}
}
// link
$xml->addChild('link', Cfg::get('HOST_URL').'?item='.$this->subject->id);
$this->result = $root->asXML();
}
private function getSubclass() : string
{
$c = $this->subject->getField('class');
$sc = $this->subject->getField('subClass');
if ($c == ITEM_CLASS_WEAPON)
$langRef = Lang::spell('weaponSubClass');
else
$langRef = Lang::item('cat', $c, 1);
if (!is_array($langRef))
return Lang::item('cat', $c);
if (is_array($langRef[$sc]))
return $langRef[$sc][0];
return $langRef[$sc];
}
public function getCacheKeyComponents() : array
{
return array(
$this->type, // DBType
$this->typeId, // DBTypeId
-1, // category
-1, // staff mask (content does not diff)
'' // misc (unused)
);
}
}
?>

View File

@@ -6,28 +6,24 @@ if (!defined('AOWOW_REVISION'))
die('illegal access');
// menuId 0: Item g_initPath()
// tabId 0: Database g_initHeader()
class ItemsPage extends GenericPage
class ItemsBaseResponse extends TemplateResponse implements ICache
{
use TrListPage;
use TrListPage, TrCache;
protected $forceTabs = false;
protected $gemScores = [];
protected int $type = Type::ITEM;
protected int $cacheType = CACHE_TYPE_PAGE;
protected $typeList = []; // rightPanel - content by context
protected $slotList = []; // rightPanel - INV_TYPE_Xs
protected string $template = 'items';
protected string $pageName = 'items';
protected ?int $activeTab = parent::TAB_DATABASE;
protected array $breadcrumb = [0, 0];
protected $type = Type::ITEM;
protected $tpl = 'items';
protected $path = [0, 0];
protected $tabId = 0;
protected $mode = CACHE_TYPE_PAGE;
protected $scripts = [[SC_JS_FILE, 'js/filters.js'], [SC_JS_FILE, 'js/swfobject.js']];
protected $_get = ['filter' => ['filter' => FILTER_UNSAFE_RAW]];
protected $validCats = array( // if > 0 class => subclass
protected array $dataLoader = ['weight-presets'];
protected array $scripts = [[SC_JS_FILE, 'js/filters.js'], [SC_JS_FILE, 'js/swfobject.js']];
protected array $expectedGET = array(
'filter' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Filter::PATTERN_PARAM]]
);
protected array $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,
@@ -84,51 +80,52 @@ class ItemsPage extends GenericPage
13 => true
);
private $filterOpts = [];
private $sharedLV = array( // common listview components across all tabs
public array $gemScores = [];
public array $typeList = []; // rightPanel - content by context
public array $slotList = []; // rightPanel - INV_TYPE_Xs
private array $filterOpts = [];
private array $sharedLV = array( // common listview components across all tabs
'hiddenCols' => [],
'visibleCols' => [],
'extraCols' => []
);
public function __construct($pageCall, $pageParam)
public function __construct(string $pageParam)
{
$this->getCategoryFromUrl($pageParam);
parent::__construct($pageCall, $pageParam);
parent::__construct($pageParam);
$this->filterObj = new ItemListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
$this->name = Util::ucFirst(Lang::game('items'));
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
$this->filter = new ItemListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
$this->filterError = $this->filter->error;
}
protected function generateContent()
protected function generate() : void
{
$this->addScript([SC_JS_FILE, '?data=weight-presets']);
$this->h1 = Util::ucFirst(Lang::game('items'));
$conditions = [];
if (!User::isInGroup(U_GROUP_EMPLOYEE))
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
$this->filter->evalCriteria();
$this->filter->evalWeights();
if ($_ = $this->filter->getConditions())
$conditions[] = $_;
$this->filterError = $this->filter->error; // maybe the evalX() caused something
/*******************/
/* evaluate filter */
/*******************/
$this->filterObj->evalCriteria();
$this->filterObj->evalWeights();
$fiForm = $this->filter->values;
if ($_ = $this->filterObj->getConditions())
$conditions[] = $_;
// recreate form selection (must be evaluated first via getConditions())
$fiForm = $this->filterObj->values;
$xCols = $this->filterObj->fiExtraCols;
$this->createExtraMenus();
$xCols = $this->filter->fiExtraCols;
$infoMask = ITEMINFO_JSON;
if (array_intersect([63, 64, 125], $xCols)) // 63:buyPrice; 64:sellPrice; 125:reqarenartng
@@ -137,8 +134,42 @@ class ItemsPage extends GenericPage
if ($xCols)
$this->sharedLV['extraCols'] = '$fi_getExtraCols(fi_extraCols, '.($fiForm['gm'] ?? 0).', '.(array_intersect([63], $xCols) ? 1 : 0).')';
if ($this->filterObj->error)
$this->sharedLV['_errors'] = '$1';
$this->createExtraMenus(); // right side panels in search form
/*************/
/* Menu Path */
/*************/
foreach ($this->category as $c)
$this->breadcrumb[] = $c;
// if slot-dropdown is available && Armor && $path points to Armor-Class
if (count($this->breadcrumb) == 4 && $this->category[0] == 4 && count($fiForm['sl']) == 1)
$this->breadcrumb[] = $fiForm['sl'][0];
else if (isset($this->category[0]) && $this->category[0] == 0 && count($fiForm['ty']) == 1)
$this->breadcrumb[] = $fiForm['ty'][0];
/**************/
/* Page Title */
/**************/
array_unshift($this->title, $this->h1);
if ($this->category)
{
if (isset($this->category[2]) && is_array(Lang::item('cat', $this->category[0], 1, $this->category[1])))
$tPart = Lang::item('cat', $this->category[0], 1, $this->category[1], 1, $this->category[2]);
else if (isset($this->category[1]) && is_array(Lang::item('cat', $this->category[0])))
$tPart = Lang::item('cat', $this->category[0], 1, $this->category[1]);
else if ($this->category[0] == 0 && count($fiForm['ty']) == 1)
$tPart = Lang::item('cat', 0, 1, $fiForm['ty'][0]);
else
$tPart = Lang::item('cat', $this->category[0]);
array_unshift($this->title, is_array($tPart) ? $tPart[0] : $tPart);
}
/******************/
@@ -157,7 +188,7 @@ class ItemsPage extends GenericPage
/* handle auto-gemming */
/***********************/
$this->gemScores = $this->createGemScores($fiForm['gm'] ?? 0);
$this->createGemScores($fiForm['gm'] ?? 0);
/*************************/
@@ -165,9 +196,9 @@ class ItemsPage extends GenericPage
/*************************/
$upgItemData = [];
if ($this->filterObj->upgrades && $this->filterObj->fiSetWeights)
if ($this->filter->upgrades && $this->filter->fiSetWeights)
{
$upgItems = new ItemList(array(['id', array_keys($this->filterObj->upgrades)]), ['extraOpts' => $this->filterObj->extraOpts]);
$upgItems = new ItemList(array(['id', array_keys($this->filter->upgrades)]), ['extraOpts' => $this->filter->extraOpts]);
if (!$upgItems->error)
{
$upgItemData = $upgItems->getListviewData($infoMask);
@@ -175,11 +206,11 @@ class ItemsPage extends GenericPage
}
}
if ($upgItemData) // check if upItems cover multiple slots
if ($upgItemData) // check if upgItems cover multiple slots
{
$singleSlot = true;
$ref = reset($this->filterObj->upgrades);
foreach ($this->filterObj->upgrades as $slot)
$ref = reset($this->filter->upgrades);
foreach ($this->filter->upgrades as $slot)
{
if ($slot == $ref)
continue;
@@ -189,10 +220,10 @@ class ItemsPage extends GenericPage
}
if ($singleSlot && empty($fiForm['gb'])) // enforce group by slot
$fiForm['gb'] = 1;
$fiForm['gb'] = ItemListFilter::GROUP_BY_SLOT;
else if (!$singleSlot) // multiples can only be grouped by slot
{
$fiForm['gb'] = 1;
$fiForm['gb'] = ItemListFilter::GROUP_BY_SLOT;
$maxResults = 25;
$this->sharedLV['customFilter'] = '$fi_filterUpgradeListview';
}
@@ -221,15 +252,17 @@ class ItemsPage extends GenericPage
);
$groups = [];
$nameSource = [];
$grouping = $fiForm['gb'] ?? 0;
$grouping = $fiForm['gb'] ?? ItemListFilter::GROUP_BY_NONE;
$extraOpts = [];
$maxResults = Cfg::get('SQL_LIMIT_DEFAULT');
$forceTabs = false;
$tabs = [];
switch ($grouping)
{
// 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 ItemListFilter::GROUP_BY_SLOT:
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)
@@ -240,20 +273,20 @@ class ItemsPage extends GenericPage
if ($fiForm['sl']) // skip lookups for unselected slots
$groups = array_intersect($groups, $fiForm['sl']);
if (!empty($this->filterObj->upgrades)) // skip lookups for slots we dont have items to upgrade for
$groups = array_intersect($groups, $this->filterObj->upgrades);
if ($this->filter->upgrades) // skip lookups for slots we dont have items to upgrade for
$groups = array_intersect($groups, $this->filter->upgrades);
if ($groups)
{
$nameSource = Lang::item('inventoryType');
$this->forceTabs = true;
$forceTabs = true;
}
break;
case 2: // itemlevel: first, try to find 10 level steps within range (if given) as tabs
case ItemListFilter::GROUP_BY_LEVEL: // itemlevel: first, try to find 10 level steps within range (if given) as tabs
// ohkayy, maybe i need to rethink $this
$this->filterOpts = $this->filterObj->extraOpts;
$this->filterOpts['is']['o'] = [null]; // remove 'order by' from itemStats
$this->filterOpts = $this->filter->extraOpts;
$this->filterOpts['is']['o'] = [null]; // remove 'order by' from ?_item_stats
$extraOpts = array_merge($this->filterOpts, ['i' => ['g' => ['itemlevel'], 'o' => ['itemlevel DESC']]]);
$levelRef = new ItemList(array_merge($conditions, [10]), ['extraOpts' => $extraOpts]);
@@ -270,25 +303,25 @@ class ItemsPage extends GenericPage
$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->forceTabs = true;
$forceTabs = true;
}
break;
case 3: // source
case ItemListFilter::GROUP_BY_SOURCE: // source
$groups = [1, 2, 3, 4, 5, 10, 11, 12, 0];
$nameSource = Lang::game('sources');
$this->forceTabs = true;
$forceTabs = true;
break;
// none
default:
$grouping = 0;
$grouping = ItemListFilter::GROUP_BY_NONE;
$groups[0] = null;
}
// write back 'gb' to filter
if ($grouping)
$this->filterObj->values['gb'] = $grouping;
$this->filter->values['gb'] = $grouping;
/*****************************/
@@ -297,22 +330,15 @@ class ItemsPage extends GenericPage
foreach ($groups as $group)
{
switch ($grouping)
$finalCnd = match ($grouping)
{
case 1:
$finalCnd = array_merge($conditions, [['slot', $group], $maxResults]);
break;
case 2:
$finalCnd = array_merge($conditions, [['itemlevel', abs($group), $group > 0 ? null : '<'], $maxResults]);
break;
case 3:
$finalCnd = array_merge($conditions, [$group ? ['src.src'.$group, null, '!'] : ['src.typeId', null], $maxResults]);
break;
default:
$finalCnd = $conditions;
}
ItemListFilter::GROUP_BY_SLOT => array_merge($conditions, [['slot', $group], $maxResults]),
ItemListFilter::GROUP_BY_LEVEL => array_merge($conditions, [['itemlevel', abs($group), $group > 0 ? null : '<'], $maxResults]),
ItemListFilter::GROUP_BY_SOURCE => array_merge($conditions, [$group ? ['src.src'.$group, null, '!'] : ['src.typeId', null], $maxResults]),
default => $conditions
};
$items = new ItemList($finalCnd, ['extraOpts' => array_merge($extraOpts, $this->filterObj->extraOpts), 'calcTotal' => true]);
$items = new ItemList($finalCnd, ['extraOpts' => array_merge($extraOpts, $this->filter->extraOpts), 'calcTotal' => true]);
if ($items->error)
continue;
@@ -326,11 +352,10 @@ class ItemsPage extends GenericPage
$upg = [];
if ($upgItemData)
{
if ($grouping == 1) // slot: match upgradeItem to slot
// slot: match upgradeItem to slot
if ($grouping == ItemListFilter::GROUP_BY_SLOT)
{
$upg = array_keys(array_filter($this->filterObj->upgrades, function ($v) use ($group) {
return $v == $group;
}));
$upg = array_keys(array_filter($this->filter->upgrades, fn($x) => $x == $group));
foreach ($upg as $uId)
$tabData['data'][$uId] = $upgItemData[$uId];
@@ -340,7 +365,7 @@ class ItemsPage extends GenericPage
}
else if ($grouping)
{
$upg = array_keys($this->filterObj->upgrades);
$upg = array_keys($this->filter->upgrades);
$tabData['_upgradeIds'] = $upg;
foreach ($upgItemData as $uId => $data) // using numeric keys => cant use array_merge
$tabData['data'][$uId] = $data;
@@ -349,24 +374,18 @@ class ItemsPage extends GenericPage
if ($grouping)
{
switch ($grouping)
$tabData['id'] = match ($grouping)
{
case 1:
$tabData['id'] = 'slot-'.$group;
break;
case 2:
$tabData['id'] = $group > 0 ? 'level-'.$group : 'other';
break;
case 3:
$tabData['id'] = $group ? 'source-'.$group : 'unknown';
break;
}
ItemListFilter::GROUP_BY_SLOT => 'slot-'.$group,
ItemListFilter::GROUP_BY_LEVEL => $group > 0 ? 'level-'.$group : 'other',
ItemListFilter::GROUP_BY_SOURCE => $group ? 'source-'.$group : 'unknown'
};
$tabData['name'] = $nameSource[$group];
$tabData['tabs'] = '$tabsGroups';
}
if ($this->filterObj->fiSetWeights)
if ($this->filter->fiSetWeights)
if ($items->hasSetFields('tplArmor'))
$tabData['visibleCols'][] = 'armor';
@@ -375,18 +394,18 @@ class ItemsPage extends GenericPage
{
$tabData['_truncated'] = 1;
$cls = isset($this->category[0]) ? '='.$this->category[0] : '';
$catg = isset($this->category[0]) ? '='.$this->category[0] : '';
$override = ['gb' => ''];
if ($upg)
$override['upg'] = implode(':', $upg);
$override['upg'] = $upg;
switch ($grouping)
{
case 1:
case ItemListFilter::GROUP_BY_SLOT:
$override['sl'] = $group;
$tabData['note'] = '$$WH.sprintf(LANG.lvnote_viewmoreslot, \''.$cls.'\', \''.$this->filterObj->buildGETParam($override).'\')';
$tabData['note'] = '$$WH.sprintf(LANG.lvnote_viewmoreslot, \''.$catg.'\', \''.$this->filter->buildGETParam($override).'\')';
break;
case 2:
case ItemListFilter::GROUP_BY_LEVEL:
if ($group > 0)
{
$override['minle'] = $group;
@@ -395,11 +414,11 @@ class ItemsPage extends GenericPage
else
$override['maxle'] = abs($group) - 1;
$tabData['note'] = '$$WH.sprintf(LANG.lvnote_viewmorelevel, \''.$cls.'\', \''.$this->filterObj->buildGETParam($override).'\')';
$tabData['note'] = '$$WH.sprintf(LANG.lvnote_viewmorelevel, \''.$catg.'\', \''.$this->filter->buildGETParam($override).'\')';
break;
case 3:
case ItemListFilter::GROUP_BY_SOURCE:
if ($_ = [null, 3, 4, 5, 6, 7, 9, 10, 11][$group])
$tabData['note'] = '$$WH.sprintf(LANG.lvnote_viewmoresource, \''.$cls.'\', \''.$this->filterObj->buildGETParam($override, ['cr' => 128, 'crs' => $_, 'crv' => 0]).'\')';
$tabData['note'] = '$$WH.sprintf(LANG.lvnote_viewmoresource, \''.$catg.'\', \''.$this->filter->buildGETParam($override, ['cr' => 128, 'crs' => $_, 'crv' => 0]).'\')';
break;
}
@@ -410,105 +429,43 @@ class ItemsPage extends GenericPage
$tabData['_truncated'] = 1;
}
foreach ($tabData as $k => $p)
if (!$p && $k != 'data')
unset($tabData[$k]);
// inherited from >sharedLV, may be empty
if (!$tabData['hiddenCols'])
unset($tabData['hiddenCols']);
if (!$tabData['visibleCols'])
unset($tabData['visibleCols']);
if (!$tabData['extraCols'])
unset($tabData['extraCols']);
if ($grouping)
$tabData['hideCount'] = 1;
$tabData['data'] = array_values($tabData['data']);
$this->lvTabs[] = [ItemList::$brickFile, $tabData];
$tabs[] = $tabData;
}
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsGroups', $forceTabs && $tabs);
// whoops, we have no data? create emergency content
if (empty($this->lvTabs))
{
$this->forceTabs = false;
$this->lvTabs[] = [ItemList::$brickFile, ['data' => []]];
}
}
if (!count($tabs))
$tabs[] = ['data' => []];
protected function postCache()
{
// sort for dropdown-menus
Lang::sort('game', 'ra');
Lang::sort('game', 'cl');
}
foreach ($tabs as $t)
$this->lvTabs->addListviewTab(new Listview($t, ItemList::$brickFile));
protected function generateTitle()
{
array_unshift($this->title, $this->name);
$this->redButtons[BUTTON_WOWHEAD] = true;
if ($fiQuery = $this->filter->buildGETParam())
$this->wowheadLink .= '&filter='.$fiQuery;
if (!$this->category)
return;
parent::generate();
if (isset($this->category[2]) && is_array(Lang::item('cat', $this->category[0], 1, $this->category[1])))
$tPart = Lang::item('cat', $this->category[0], 1, $this->category[1], 1, $this->category[2]);
else if (isset($this->category[1]) && is_array(Lang::item('cat', $this->category[0])))
$tPart = Lang::item('cat', $this->category[0], 1, $this->category[1]);
else if ($this->category[0] == 0 && count($this->filterObj->values['ty']) == 1)
$tPart = Lang::item('cat', 0, 1, $this->filterObj->values['ty'][0]);
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 = $this->filterObj->values;
if (count($this->path) == 4 && $this->category[0] == 4 && count($form['sl']) == 1)
$this->path[] = $form['sl'][0];
else if (isset($this->category[0]) && $this->category[0] == 0 && count($form['ty']) == 1)
$this->path[] = $form['ty'][0];
$this->setOnCacheLoaded([self::class, 'onBeforeDisplay']);
}
// fetch best possible gems for chosen weights
private function createGemScores(int $gemQuality) : array
private function createGemScores(int $gemQuality) : void
{
$gemScores = [];
if (!$this->filterObj->fiSetWeights)
return [];
if (!$gemQuality)
return [];
$this->sharedLV['computeDataFunc'] = '$fi_scoreSockets';
$q = intVal($this->filterObj->values['gm']);
$mask = 0xE;
$cnd = [10, ['class', ITEM_CLASS_GEM], ['gemColorMask', &$mask, '&'], ['quality', &$q]];
if (!$this->filterObj->values['jc'])
$cnd[] = ['itemLimitCategory', 0]; // Jeweler's Gems
If ($this->filterObj->wtCnd)
$cnd[] = $this->filterObj->wtCnd;
$anyColor = new ItemList($cnd, ['extraOpts' => $this->filterObj->extraOpts]);
if (!$anyColor->error)
{
$this->extendGlobalData($anyColor->getJSGlobals());
$gemScores[0] = array_values($anyColor->getListviewData(ITEMINFO_GEM));
}
for ($i = 0; $i < 4; $i++)
{
$mask = 1 << $i;
$q = !$i ? ITEM_QUALITY_RARE : intVal($gemQuality); // meta gems are always included.. ($q is backReferenced)
$byColor = new ItemList($cnd, ['extraOpts' => $this->filterObj->extraOpts]);
if (!$byColor->error)
{
$this->extendGlobalData($byColor->getJSGlobals());
$gemScores[$mask] = array_values($byColor->getListviewData(ITEMINFO_GEM));
}
}
if (!$this->filter->fiSetWeights)
return;
$this->sharedLV['onBeforeCreate'] = '$fi_initWeightedListview';
$this->sharedLV['onAfterCreate'] = '$fi_addUpgradeIndicator';
@@ -516,7 +473,38 @@ class ItemsPage extends GenericPage
array_push($this->sharedLV['hiddenCols'], 'type', 'source');
return $gemScores;
if (!$gemQuality)
return;
$this->sharedLV['computeDataFunc'] = '$fi_scoreSockets';
$q = intVal($gemQuality);
$mask = 0xE;
$cnd = [10, ['class', ITEM_CLASS_GEM], ['gemColorMask', &$mask, '&'], ['quality', &$q]];
if (!isset($fiForm['jc']))
$cnd[] = ['itemLimitCategory', 0]; // Jeweler's Gems
if ($this->filter->wtCnd)
$cnd[] = $this->filter->wtCnd;
$anyColor = new ItemList($cnd, ['extraOpts' => $this->filter->extraOpts]);
if (!$anyColor->error)
{
$this->extendGlobalData($anyColor->getJSGlobals());
$this->gemScores[0] = array_values($anyColor->getListviewData(ITEMINFO_GEM));
}
for ($i = 0; $i < 4; $i++)
{
$mask = 1 << $i;
$q = !$i ? ITEM_QUALITY_RARE : intVal($gemQuality); // meta gems are always included.. ($q is backReferenced)
$byColor = new ItemList($cnd, ['extraOpts' => $this->filter->extraOpts]);
if (!$byColor->error)
{
$this->extendGlobalData($byColor->getJSGlobals());
$this->gemScores[$mask] = array_values($byColor->getListviewData(ITEMINFO_GEM));
}
}
}
// display available submenus 'type' and 'slot', if applicable
@@ -571,7 +559,6 @@ class ItemsPage extends GenericPage
$slotData = Lang::item('inventoryType');
$slotMask = 0x7EA;
}
asort($slotData);
break;
case 16:
@@ -596,12 +583,19 @@ class ItemsPage extends GenericPage
foreach ($typeData as $k => $str)
if ($str && (!$typeMask || ($typeMask & (1 << $k))))
$this->typeList[$k] = $str;
$this->typeList[$k] = is_array($str) ? $str[0] : $str;
foreach ($slotData as $k => $str) // "Off Hand" => "Shield"
if ($str && (!$slotMask || ($slotMask & (1 << $k))))
$this->slotList[$k] = $k == INVTYPE_SHIELD ? Lang::item('armorSubClass', 6) : $str;
}
protected static function onBeforeDisplay() : void
{
// sort for dropdown-menus
Lang::sort('game', 'ra');
Lang::sort('game', 'cl');
}
}
?>

View File

@@ -114,7 +114,7 @@ class EnchantmentList extends DBTypeList
if (!$data[$this->id]['spells'])
unset($data[$this->id]['spells']);
Util::arraySumByKey($data[$this->id], $this->jsonStats[$this->id]->toJson());
Util::arraySumByKey($data[$this->id], $this->jsonStats[$this->id]->toJson(includeEmpty: false));
}
return $data;
@@ -122,7 +122,7 @@ class EnchantmentList extends DBTypeList
public function getStatGainForCurrent() : array
{
return $this->jsonStats[$this->id]->toJson();
return $this->jsonStats[$this->id]->toJson(includeEmpty: false);
}
public function getRelSpell(int $id) : ?array

View File

@@ -49,7 +49,7 @@ class ItemList extends DBTypeList
// from json to json .. the gentle fuckups of legacy code integration
$this->initJsonStats();
$this->jsonStats[$this->id] = (new StatsContainer())->fromJson($_curTpl, true)->toJson(Stat::FLAG_ITEM /* | Stat::FLAG_SERVERSIDE */);
$this->jsonStats[$this->id] = (new StatsContainer())->fromJson($_curTpl, true)->toJson(Stat::FLAG_ITEM /* | Stat::FLAG_SERVERSIDE */, false);
if ($miscData)
{
@@ -723,32 +723,7 @@ class ItemList extends DBTypeList
// activation conditions for meta gems
if (!empty($gemEnch['conditionId']))
{
if ($gemCnd = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantmentcondition WHERE `id` = ?d', $gemEnch['conditionId']))
{
for ($i = 1; $i < 6; $i++)
{
if (!$gemCnd['color'.$i])
continue;
$vspfArgs = [];
switch ($gemCnd['comparator'.$i])
{
case 2: // requires less <color> than (<value> || <comparecolor>) gems
case 5: // requires at least <color> than (<value> || <comparecolor>) gems
$vspfArgs = [$gemCnd['value'.$i], Lang::item('gemColors', $gemCnd['color'.$i] - 1)];
break;
case 3: // requires more <color> than (<value> || <comparecolor>) gems
$vspfArgs = [Lang::item('gemColors', $gemCnd['color'.$i] - 1), Lang::item('gemColors', $gemCnd['cmpColor'.$i] - 1)];
break;
default:
continue 2;
}
$x .= '<span class="q0">'.Lang::achievement('reqNumCrt').' '.Lang::item('gemConditions', $gemCnd['comparator'.$i], $vspfArgs).'</span><br />';
}
}
}
$x .= Game::getEnchantmentCondition($gemEnch['conditionId'], $interactive);
}
// Random Enchantment - if random enchantment is set, prepend stats from it
@@ -1461,6 +1436,25 @@ class ItemList extends DBTypeList
return in_array($this->curTpl['subClassBak'], [ITEM_SUBCLASS_BOW, ITEM_SUBCLASS_GUN, ITEM_SUBCLASS_THROWN, ITEM_SUBCLASS_CROSSBOW, ITEM_SUBCLASS_WAND]);
}
public function isBodyArmor() : bool
{
if ($this->curTpl['class'] != ITEM_CLASS_ARMOR)
return false;
return in_array($this->curTpl['subClassBak'], [ITEM_SUBCLASS_CLOTH_ARMOR, ITEM_SUBCLASS_LEATHER_ARMOR, ITEM_SUBCLASS_MAIL_ARMOR, ITEM_SUBCLASS_PLATE_ARMOR]);
}
public function isDisplayable() : bool
{
if (!$this->curTpl['displayId'])
return false;
return in_array($this->curTpl['slot'], 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));
}
private function formatRating(int $statId, int $itemMod, int $qty, bool $interactive = false, bool &$scaling = false) : string
{
// clamp level range
@@ -1773,6 +1767,11 @@ class ItemList extends DBTypeList
class ItemListFilter extends Filter
{
public const /* int */ GROUP_BY_NONE = 0;
public const /* int */ GROUP_BY_SLOT = 1;
public const /* int */ GROUP_BY_LEVEL = 2;
public const /* int */ GROUP_BY_SOURCE = 3;
private array $ubFilter = []; // usable-by - limit weapon/armor selection per CharClass - itemClass => available itemsubclasses
private string $extCostQuery = 'SELECT `item` FROM npc_vendor WHERE `extendedCost` IN (?a) UNION
SELECT `item` FROM game_event_npc_vendor WHERE `extendedCost` IN (?a)';
@@ -2372,7 +2371,7 @@ class ItemListFilter extends Filter
return null;
$costs = DB::Aowow()->selectCol(
'SELECT `id` FROM ?_itemextendedcost WHERE `reqItemId1` IN (?a) OR `reqItemId2` IN (?a) OR `reqItemId3` IN (?a) OR `reqItemId4` IN (?a) OR `reqItemId5` IN (?a)',
'SELECT `id` FROM ?_itemextendedcost WHERE `reqItemId1` IN (?a) OR `reqItemId2` IN (?a) OR `reqItemId3` IN (?a) OR `reqItemId4` IN (?a) OR `reqItemId5` IN (?a)',
$_, $_, $_, $_, $_
);
if ($items = DB::World()->selectCol($this->extCostQuery, $costs, $costs))

View File

@@ -210,7 +210,7 @@ class SpellList extends DBTypeList
$data = []; // flat gains
foreach ($this->getStatGain() as $id => $spellData)
{
$data[$id] = $spellData->toJson(STAT::FLAG_ITEM | STAT::FLAG_PROFILER);
$data[$id] = $spellData->toJson(STAT::FLAG_ITEM | STAT::FLAG_PROFILER, false);
// apply weapon restrictions
$this->getEntry($id);

View File

@@ -487,11 +487,11 @@ class StatsContainer implements \Countable
/* Output */
/**********/
public function toJson(int $outFlags = Stat::FLAG_NONE) : array
public function toJson(int $outFlags = Stat::FLAG_NONE, bool $includeEmpty = true) : array
{
$out = [];
foreach ($this->store as $stat => $amt)
if (!$outFlags || (Stat::getFlags($stat) & $outFlags))
if ((!$outFlags || (Stat::getFlags($stat) & $outFlags)) && ($amt || $includeEmpty))
$out[Stat::getJsonString($stat)] = $amt;
return $out;

View File

@@ -37,7 +37,7 @@ $lang = array(
'quickFacts' => "Kurzübersicht",
'screenshots' => "Screenshots",
'videos' => "Videos",
'side' => "Seite",
'side' => "Seite: ",
'related' => "Weiterführende Informationen",
'contribute' => "Beitragen",
// 'replyingTo' => "Antwort zu einem Kommentar von",
@@ -73,7 +73,7 @@ $lang = array(
'refineSearch' => 'Tipp: Präzisiere deine Suche mit Durchsuchen einer <a href="javascript:;" id="fi_subcat">Unterkategorie</a>.',
'clear' => "leeren",
'exactMatch' => "Exakt passend",
'_reqLevel' => "Mindeststufe",
'_reqLevel' => "Mindeststufe: ",
// infobox
'unavailable' => "Nicht für Spieler verfügbar",
@@ -106,12 +106,12 @@ $lang = array(
'langOnly' => "Diese Seite ist nur in <b>%s</b> verfügbar.",
// calculators
'preset' => "Vorlage",
'preset' => "Vorlage: ",
'addWeight' => "Weitere Gewichtung hinzufügen",
'createWS' => "Gewichtungsverteilung erstellen",
'jcGemsOnly' => "<span%s>JS-exklusive</span> Edelsteine einschließen",
'cappedHint' => 'Tipp: <a href="javascript:;" onclick="fi_presetDetails();">Entfernt</a> Gewichtungen für gedeckte Werte wie Trefferwertung.',
'groupBy' => "Ordnen nach",
'groupBy' => "Ordnen nach: ",
'gb' => array(
["Nichts", "none"], ["Platz", "slot"], ["Stufe", "level"], ["Quelle", "source"]
),
@@ -345,7 +345,7 @@ $lang = array(
'reqLevel' => "Benötigt Stufe %s",
'reqSkillLevel' => "Benötigte Fertigkeitsstufe",
'school' => "Magieart",
'type' => "Art",
'type' => "Art: ",
'valueDelim' => " - ", // " bis "
'pvp' => "PvP",
@@ -2059,7 +2059,7 @@ $lang = array(
'refundable' => "Rückzahlbar",
'noNeedRoll' => "Kann nicht für Bedarf werfen",
'atKeyring' => "Passt in den Schlüsselbund",
'worth' => "Wert",
'worth' => "Wert: ",
'consumable' => "Verbrauchbar",
'nonConsumable' => "Nicht verbrauchbar",
'accountWide' => "Accountweit",
@@ -2068,17 +2068,17 @@ $lang = array(
'prospectable' => "Sondierbar",
'disenchantable'=> "Kann entzaubert werden",
'cantDisenchant'=> "Kann nicht entzaubert werden",
'repairCost' => "Reparaturkosten",
'tool' => "Werkzeug",
'repairCost' => "Reparaturkosten: ",
'tool' => "Werkzeug: ",
'cost' => "Preis",
'content' => "Inhalt",
'_transfer' => 'Dieser Gegenstand wird mit <a href="?item=%d" class="q%d icontiny tinyspecial" style="background-image: url(STATIC_URL/images/wow/icons/tiny/%s.gif)">%s</a> vertauscht, wenn Ihr zur <span class="icon-%s">%s</span> wechselt.',
'_unavailable' => "Dieser Gegenstand ist nicht für Spieler verfügbar.",
'_rndEnchants' => "Zufällige Verzauberungen",
'_chance' => "(Chance von %s%%)",
'slot' => "Platz",
'_quality' => "Qualität",
'usableBy' => "Benutzbar von",
'slot' => "Platz: ",
'_quality' => "Qualität: ",
'usableBy' => "Benutzbar von: ",
'buyout' => "Sofortkaufpreis",
'each' => "Stück",
'tabOther' => "Anderes",
@@ -2110,7 +2110,7 @@ $lang = array(
'range' => ['%1$d - %2$d Schaden', '%1$d - %2$d %3$sschaden', '+ %1$d - %2$d Schaden', '+ %1$d - %2$d %3$sschaden' ],
'ammo' => ["Verursacht %g zusätzlichen Schaden pro Sekunde.", "Verursacht %g zusätzlichen %sschaden pro Sekunde", "+ %g Schaden pro Sekunde", "+ %g %sschaden pro Sekunde"]
),
'gems' => "Edelsteine",
'gems' => "Edelsteine: ",
'socketBonus' => "Sockelbonus: %s",
'socket' => array(
"Metasockel", "Roter Sockel", "Gelber Sockel", "Blauer Sockel", -1 => "Prismatischer Sockel"

View File

@@ -37,7 +37,7 @@ $lang = array(
'quickFacts' => "Quick Facts",
'screenshots' => "Screenshots",
'videos' => "Videos",
'side' => "Side",
'side' => "Side: ",
'related' => "Related",
'contribute' => "Contribute",
// 'replyingTo' => "The answer to a comment from",
@@ -73,7 +73,7 @@ $lang = array(
'refineSearch' => 'Tip: Refine your search by browsing a <a href="javascript:;" id="fi_subcat">subcategory</a>.',
'clear' => "clear",
'exactMatch' => "Exact match",
'_reqLevel' => "Required level",
'_reqLevel' => "Required level: ",
// infobox
'unavailable' => "Not available to players", // alternative wording found: "No longer available to players" ... aw screw it <_<
@@ -106,12 +106,12 @@ $lang = array(
'langOnly' => "This page is only available in <b>%s</b>.",
// calculators
'preset' => "Preset",
'preset' => "Preset: ",
'addWeight' => "Add another weight",
'createWS' => "Create a weight scale",
'jcGemsOnly' => "Include <span%s>JC-only</span> gems",
'cappedHint' => 'Tip: <a href="javascript:;" onclick="fi_presetDetails();">Remove</a> weights for capped statistics such as Hit rating.',
'groupBy' => "Group By",
'groupBy' => "Group By: ",
'gb' => array(
["None", "none"], ["Slot", "slot"], ["Level", "level"], ["Source", "source"]
),
@@ -345,7 +345,7 @@ $lang = array(
'reqLevel' => "Requires Level %s",
'reqSkillLevel' => "Required skill level",
'school' => "School",
'type' => "Type",
'type' => "Type: ",
'valueDelim' => " to ",
'pvp' => "PvP", // PVP
@@ -2059,7 +2059,7 @@ $lang = array(
'refundable' => "Refundable",
'noNeedRoll' => "Cannot roll Need",
'atKeyring' => "Can be placed in the keyring",
'worth' => "Worth",
'worth' => "Worth: ",
'consumable' => "Consumable",
'nonConsumable' => "Non-consumable",
'accountWide' => "Account-wide",
@@ -2068,17 +2068,17 @@ $lang = array(
'prospectable' => "Prospectable", // ITEM_PROSPECTABLE
'disenchantable'=> "Disenchantable", // ITEM_DISENCHANT_ANY_SKILL
'cantDisenchant'=> "Cannot be disenchanted", // ITEM_DISENCHANT_NOT_DISENCHANTABLE
'repairCost' => "Repair cost", // REPAIR_COST
'tool' => "Tool",
'repairCost' => "Repair cost: ", // REPAIR_COST
'tool' => "Tool: ",
'cost' => "Cost", // COSTS_LABEL
'content' => "Content",
'_transfer' => 'This item will be converted to <a href="?item=%d" class="q%d icontiny tinyspecial" style="background-image: url(STATIC_URL/images/wow/icons/tiny/%s.gif)">%s</a> if you transfer to <span class="icon-%s">%s</span>.',
'_unavailable' => "This item is not available to players.",
'_rndEnchants' => "Random Enchantments",
'_chance' => "(%s%% chance)",
'slot' => "Slot",
'_quality' => "Quality", // QUALITY
'usableBy' => "Usable by",
'slot' => "Slot: ",
'_quality' => "Quality: ", // QUALITY
'usableBy' => "Usable by: ",
'buyout' => "Buyout price", // BUYOUT_PRICE
'each' => "each",
'tabOther' => "Other",
@@ -2110,7 +2110,7 @@ $lang = array(
'range' => ["%d - %d Damage", "%d - %d %s Damage", "+ %d - %d Damage", "+%d - %d %s Damage" ],
'ammo' => ["Adds %g damage per second", "Adds %g %s damage per second", "+ %g damage per second", "+ %g %s damage per second" ]
),
'gems' => "Gems",
'gems' => "Gems: ",
'socketBonus' => "Socket Bonus: %s", // ITEM_SOCKET_BONUS
'socket' => array( // EMPTY_SOCKET_*
"Meta Socket", "Red Socket", "Yellow Socket", "Blue Socket", -1 => "Prismatic Socket"

View File

@@ -37,7 +37,7 @@ $lang = array(
'quickFacts' => "Notas rápidas",
'screenshots' => "Capturas de pantalla",
'videos' => "Videos",
'side' => "Lado",
'side' => "Lado: ",
'related' => "Información relacionada",
'contribute' => "Contribuir",
// 'replyingTo' => "The answer to a comment from",
@@ -73,7 +73,7 @@ $lang = array(
'refineSearch' => 'Sugerencia: Refina tu búsqueda llendo a una <a href="javascript:;" id="fi_subcat">subcategoría</a>.',
'clear' => "borrar",
'exactMatch' => "Coincidencia exacta",
'_reqLevel' => "Nivel requerido",
'_reqLevel' => "Nivel requerido: ",
// infobox
'unavailable' => "No está disponible a los jugadores",
@@ -106,12 +106,12 @@ $lang = array(
'langOnly' => "Esta página sólo está disponible en <b>%s</b>.",
// calculators
'preset' => "Predet.",
'preset' => "Predet.: ",
'addWeight' => "Añadir otro factor",
'createWS' => "Crear escala de valores",
'jcGemsOnly' => "Incluir solo <span%s>gemas de joyería</span>",
'cappedHint' => 'Consejo: <a href="javascript:;" onclick="fi_presetDetails();">Elimina</a> escalas para atributos al máximo como el Índice de Golpe.',
'groupBy' => "Agrupar por",
'groupBy' => "Agrupar por: ",
'gb' => array(
["Ninguno", "none"], ["Casilla", "slot"], ["Nivel", "level"], ["Fuente", "source"]
),
@@ -345,7 +345,7 @@ $lang = array(
'reqLevel' => "Necesitas ser de nivel %s",
'reqSkillLevel' => "Requiere nivel de habilidad",
'school' => "Escuela",
'type' => "Tipo",
'type' => "Tipo: ",
'valueDelim' => " - ",
'pvp' => "JcJ",
@@ -2059,7 +2059,7 @@ $lang = array(
'refundable' => "Se puede devolver",
'noNeedRoll' => "No se puede hacer una tirada por Necesidad",
'atKeyring' => "Se puede poner en el llavero",
'worth' => "Valor",
'worth' => "Valor: ",
'consumable' => "Consumible",
'nonConsumable' => "No consumible",
'accountWide' => "Ligado a la cuenta",
@@ -2068,17 +2068,17 @@ $lang = array(
'prospectable' => "Prospectable",
'disenchantable'=> "Desencantable",
'cantDisenchant'=> "No se puede desencantar",
'repairCost' => "Coste de reparación",
'tool' => "Herramienta",
'repairCost' => "Coste de reparación: ",
'tool' => "Herramienta: ",
'cost' => "Coste",
'content' => "Contenido",
'_transfer' => 'Este objeto será convertido a <a href="?item=%d" class="q%d icontiny tinyspecial" style="background-image: url(STATIC_URL/images/wow/icons/tiny/%s.gif)">%s</a> si lo transfieres a la <span class="icon-%s">%s</span>.',
'_unavailable' => "Este objeto no está disponible para los jugadores.",
'_rndEnchants' => "Encantamientos aleatorios",
'_chance' => "(probabilidad %s%%)",
'slot' => "Casilla",
'_quality' => "Calidad",
'usableBy' => "Usable por",
'slot' => "Casilla: ",
'_quality' => "Calidad: ",
'usableBy' => "Usable por: ",
'buyout' => "Precio de venta en subasta",
'each' => "cada uno",
'tabOther' => "Otros",
@@ -2110,7 +2110,7 @@ $lang = array(
"range" => ["%d - %d Daño", "%d - %d daño de %s", "+ %d: %d daño", "+%d - %d daño de %s" ],
'ammo' => ["Añade %g daño por segundo", "Añade %g %s daño por segundo", "+ %g daño por segundo", "+ %g %s daño por segundo"]
),
'gems' => "Gemas",
'gems' => "Gemas: ",
'socketBonus' => "Bono de ranura: %s",
'socket' => array(
"Ranura meta", "Ranura roja", "Ranura amarilla", "Ranura azul", -1 => "Ranura prismática"

View File

@@ -37,7 +37,7 @@ $lang = array(
'quickFacts' => "En bref",
'screenshots' => "Captures d'écran",
'videos' => "Vidéos",
'side' => "Coté",
'side' => "Coté : ",
'related' => "Informations connexes",
'contribute' => "Contribuer",
// 'replyingTo' => "En réponse au commentaire de",
@@ -73,7 +73,7 @@ $lang = array(
'refineSearch' => "Astuce : Affinez votre recherche en utilisant une <a href=\"javascript:;\" id=\"fi_subcat\">sous-catégorie</a>.",
'clear' => "effacer",
'exactMatch' => "Concordance exacte",
'_reqLevel' => "Niveau requis",
'_reqLevel' => "Niveau requis : ",
// infobox
'unavailable' => "Non disponible aux joueurs",
@@ -106,12 +106,12 @@ $lang = array(
'langOnly' => "Cette page n'est disponible qu'en <b>%s</b> pour le moment.",
// calculators
'preset' => "Prédéterminée",
'preset' => "Prédéterminée : ",
'addWeight' => "Ajouter un autre facteur",
'createWS' => "Créer une échelle de valeurs",
'jcGemsOnly' => "Inclure les gemmes de <span%s>joaillier</span>",
'cappedHint' => 'Conseil: <a href="javascript:;" onclick="fi_presetDetails();">Enlever</a> un facteur pour les statistiques au maximum tel que le score de touche.',
'groupBy' => "Groupé par",
'groupBy' => "Groupé par : ",
'gb' => array(
["Aucun", "none"], ["Emplacement", "slot"], ["Niveau", "level"], ["Source", "source"]
),
@@ -345,7 +345,7 @@ $lang = array(
'reqLevel' => "Niveau %s requis",
'reqSkillLevel' => "Niveau de compétence requis",
'school' => "École",
'type' => "Type",
'type' => "Type : ",
'valueDelim' => " - ",
'pvp' => "JcJ",
@@ -2059,7 +2059,7 @@ $lang = array(
'refundable' => "Remboursable",
'noNeedRoll' => "Ne peut pas faire un jet de Besoin",
'atKeyring' => "Va dans le trousseau de clés",
'worth' => "Vaut",
'worth' => "Vaut : ",
'consumable' => "Consommable",
'nonConsumable' => "Non-consommable",
'accountWide' => "Portant sur le compte",
@@ -2068,17 +2068,17 @@ $lang = array(
'prospectable' => "Prospectable",
'disenchantable'=> "Desencantable",
'cantDisenchant'=> "Ne peut pas être désenchanté",
'repairCost' => "Cout de réparation",
'tool' => "Outil",
'repairCost' => "Cout de réparation : ",
'tool' => "Outil : ",
'cost' => "Coût",
'content' => "Contenu",
'_transfer' => 'Cet objet sera converti en <a href="?item=%d" class="q%d icontiny tinyspecial" style="background-image: url(STATIC_URL/images/wow/icons/tiny/%s.gif)">%s</a> si vous transférez en <span class="icon-%s">%s</span>.',
'_unavailable' => "Cet objet n'est pas disponible pour les joueurs.",
'_rndEnchants' => "Enchantements aléatoires",
'_chance' => "(%s%% de chance)",
'slot' => "Emplacement",
'_quality' => "Qualité",
'usableBy' => "Utilisable par",
'slot' => "Emplacement : ",
'_quality' => "Qualité : ",
'usableBy' => "Utilisable par : ",
'buyout' => "Vente immédiate",
'each' => "chacun",
'tabOther' => "Autre",
@@ -2110,7 +2110,7 @@ $lang = array(
'range' => ["Dégâts : %d - %d", "%d - %d points de dégâts (%s)", "+ %d - %d points de dégâts", "+%d - %d points de dégâts (%s)" ],
'ammo' => ["Ajoute %g dégâts par seconde", "Ajoute %g points de dégâts (%s) par seconde", "+ %g points de dégâts par seconde", "+ %g points de dégâts (%s) par seconde" ]
),
'gems' => "Gemmes",
'gems' => "Gemmes : ",
'socketBonus' => "Bonus de châsse: %s",
'socket' => array(
"Méta-châsse", "Châsse rouge", "Châsse jaune", "Châsse bleue", -1 => "Châsse prismatique"

View File

@@ -37,7 +37,7 @@ $lang = array(
'quickFacts' => "Краткая информация",
'screenshots' => "Изображения",
'videos' => "Видео",
'side' => "Сторона",
'side' => "Сторона: ",
'related' => "Дополнительная информация",
'contribute' => "Добавить",
// 'replyingTo' => "Ответ на комментарий от",
@@ -73,7 +73,7 @@ $lang = array(
'refineSearch' => 'Совет: Уточните поиск, добавив <a href="javascript:;" id="fi_subcat">подкатегорию</a>.',
'clear' => "Очистить",
'exactMatch' => "Полное совпадение",
'_reqLevel' => "Требуется уровень",
'_reqLevel' => "Требуется уровень: ",
// infobox
'unavailable' => "Недоступно игрокам",
@@ -106,12 +106,12 @@ $lang = array(
'langOnly' => "Эта страница доступна только на <b>%s</b> языке.",
// calculators
'preset' => "Готовая таблица",
'preset' => "Готовая таблица: ",
'addWeight' => "Добавить фильтр значимости",
'createWS' => "Отсортировать по значимости",
'jcGemsOnly' => "Использовать <span%s>ювелирские</span>",
'cappedHint' => 'Подсказка: <a href="javascript:;" onclick="fi_presetDetails();">Удалите</a> характеристики с капом (например, меткость).',
'groupBy' => "Группировать",
'groupBy' => "Группировать: ",
'gb' => array(
['Нет', 'none'], ['Слот', 'slot'], ['Уровень', 'level'], ['Источник', 'source']
),
@@ -345,7 +345,7 @@ $lang = array(
'reqLevel' => "Требуется уровень: %s",
'reqSkillLevel' => "Требуется уровень навыка",
'school' => "Школа",
'type' => "Тип",
'type' => "Тип: ",
'valueDelim' => " - ",
'pvp' => "PvP",
@@ -2059,7 +2059,7 @@ $lang = array(
'refundable' => "Подлежит возврату",
'noNeedRoll' => 'Нельзя говорить "Мне это нужно"',
'atKeyring' => "Может быть помещён в связку для ключей",
'worth' => "Деньги",
'worth' => "Деньги: ",
'consumable' => "Расходуется",
'nonConsumable' => "Не расходуется",
'accountWide' => "Привязано к учетной записи",
@@ -2068,17 +2068,17 @@ $lang = array(
'prospectable' => "Просеиваемое",
'disenchantable'=> "Распыляемый",
'cantDisenchant'=> "Нельзя распылить",
'repairCost' => "Цена починки",
'tool' => "Инструмент",
'repairCost' => "Цена починки: ",
'tool' => "Инструмент: ",
'cost' => "Цена",
'content' => "Материал",
'_transfer' => 'Этот предмет превратится в <a href="?item=%d" class="q%d icontiny tinyspecial" style="background-image: url(STATIC_URL/images/wow/icons/tiny/%s.gif)">%s</a>, если вы перейдете за <span class="icon-%s">%s</span>.',
'_unavailable' => "Этот предмет не доступен игрокам.",
'_rndEnchants' => "Случайные улучшения",
'_chance' => "(шанс %s%%)",
'slot' => "Слот",
'_quality' => "Качество",
'usableBy' => "Используется (кем)",
'slot' => "Слот: ",
'_quality' => "Качество: ",
'usableBy' => "Используется (кем): ",
'buyout' => "Цена выкупа",
'each' => "каждый",
'tabOther' => "Другое",
@@ -2111,7 +2111,7 @@ $lang = array(
'range' => ["Урон: %d - %d", "%d - %d ед. |3-6(%s)", "+ %d - %d ед. урона", "+%d - %d ед. урона (%s)" ],
'ammo' => ["Добавляет %g ед. урона в секунду", "Добавляет %g ед. урона (%s) в секунду", "+ ед. урона в секунду от боеприпасов (%g)", "+ %g %s ед. урона в секунду" ]
),
'gems' => "Самоцветы",
'gems' => "Самоцветы: ",
'socketBonus' => "При соответствии цвета: %s",
'socket' => array(
"Особое гнездо", "Красное гнездо", "Желтое гнездо", "Синее гнездо", -1 => "Бесцветное гнездо"

View File

@@ -37,7 +37,7 @@ $lang = array(
'quickFacts' => "相关信息",
'screenshots' => "屏幕截图",
'videos' => "视频",
'side' => "阵营",
'side' => "阵营",
'related' => "相关",
'contribute' => "贡献",
// 'replyingTo' => "The answer to a comment from",
@@ -73,7 +73,7 @@ $lang = array(
'refineSearch' => '提示:通过浏览 <a href="javascript:;" id="fi_subcat">子类别</a>搜索。',
'clear' => "清除",
'exactMatch' => "精确匹配",
'_reqLevel' => "要求等级",
'_reqLevel' => "要求等级",
// infobox
'unavailable' => "对玩家不可用", // alternative wording found: "No longer available to players" ... aw screw it <_<
@@ -106,12 +106,12 @@ $lang = array(
'langOnly' => "该页面仅以<b>%s</b>提供。",
// calculators
'preset' => "预设",
'preset' => "预设",
'addWeight' => "添加另一个权重",
'createWS' => "创建一个权重比例",
'jcGemsOnly' => "包含<span%s>JC-only</span>宝石",
'cappedHint' => '提示:<a href="javascript:;" onclick="fi_presetDetails();">移除</a> 命中等级等上限属性的权重。',
'groupBy' => "按组",
'groupBy' => "按组",
'gb' => array(
["", "none"], ["插槽", "slot"], ["等级", "level"], ["来源", "source"]
),
@@ -344,7 +344,7 @@ $lang = array(
'reqLevel' => "需要等级%s",
'reqSkillLevel' => "需要技能等级",
'school' => "类型",
'type' => "类型",
'type' => "类型",
'valueDelim' => "",
'pvp' => "PvP",
@@ -2058,7 +2058,7 @@ $lang = array(
'refundable' => "可退还的",
'noNeedRoll' => "无法需求掷骰",
'atKeyring' => "可以放在钥匙链",
'worth' => "价值",
'worth' => "价值",
'consumable' => "消耗品",
'nonConsumable' => "非消耗品",
'accountWide' => "账号共享",
@@ -2067,17 +2067,17 @@ $lang = array(
'prospectable' => "可选矿",
'disenchantable'=> "可分解",
'cantDisenchant'=> "无法分解",
'repairCost' => "修理费用",
'tool' => "工具",
'repairCost' => "修理费用",
'tool' => "工具",
'cost' => "花费",
'content' => "内容",
'_transfer' => '这个物品将被转换到<a href="?item=%d" class="q%d icontiny tinyspecial" style="background-image: url(STATIC_URL/images/wow/icons/tiny/%s.gif)">%s</a>,如果你转移到<span class="icon-%s">%s</span>。',
'_unavailable' => "这个物品对玩家不可用。",
'_rndEnchants' => "随机附魔",
'_chance' => "%s%%几率)",
'slot' => "装备部位",
'_quality' => "品质",
'usableBy' => "可用职业",
'slot' => "装备部位",
'_quality' => "品质",
'usableBy' => "可用职业",
'buyout' => "一口价",
'each' => "每个",
'tabOther' => "其他",
@@ -2109,7 +2109,7 @@ $lang = array(
'range' => ["%d - %d伤害", "%d - %d 点%s伤害", "+ %d - %d伤害", "+%d - %d 点%s伤害" ],
'ammo' => ["每秒伤害提高%g", "每秒增加%g点%s系伤害", "每秒伤害+%g", "每秒+%g点%s伤害" ]
),
'gems' => "宝石",
'gems' => "宝石",
'socketBonus' => "镶孔奖励:%s",
'socket' => array(
"多彩插槽", "红色插槽", "黄色插槽", "蓝色插槽", -1 => "棱彩插槽"

View File

@@ -101,7 +101,7 @@ CLISetup::registerSetup("build", new class extends SetupScript
if (!$itemQty || !$itemSpl || !isset($jsonBonus[$itemSpl]))
continue;
if ($x = $jsonBonus[$itemSpl]->toJson(Stat::FLAG_ITEM))
if ($x = $jsonBonus[$itemSpl]->toJson(Stat::FLAG_ITEM, false))
{
if (!isset($setbonus[$itemQty]))
$setbonus[$itemQty] = [];

View File

@@ -1283,7 +1283,8 @@ var g_item_subclasses = {
8: 'Verzauberkunstformel',
9: 'Angelbuch',
10: 'Juwelenschleifer-Vorlage',
11: 'Inschriften-Technik'
11: 'Inschriften-Technik',
12: 'Bergbauleitfäden'
},
11: {
2: 'Köcher',

View File

@@ -1330,7 +1330,8 @@ var g_item_subclasses = {
8: 'Enchanting Formula',
9: 'Fishing Book',
10: 'Jewelcrafting Design',
11: 'Inscription Technique'
11: 'Inscription Technique',
12: 'Mining Guides'
},
11: {
2: 'Quiver',

View File

@@ -1283,7 +1283,8 @@ var g_item_subclasses = {
8: 'Fórmula de encantamiento',
9: 'Libro de pesca',
10: 'Boceto de joyería',
11: 'Técnica de Inscripción'
11: 'Técnica de Inscripción',
12: 'Guías de minería'
},
11: {
2: 'Carcaj',

View File

@@ -1283,7 +1283,8 @@ var g_item_subclasses = {
8: 'Formule d\'enchantement',
9: 'Livre de pêche',
10: 'Dessin de joaillerie',
11: 'Technique de calligraphie'
11: 'Technique de calligraphie',
12: 'Guides de Minage'
},
11: {
2: 'Carquois',

View File

@@ -1283,7 +1283,8 @@ var g_item_subclasses = {
8: 'Зачаровывание',
9: 'Рыбная ловля',
10: 'Ювелирное дело',
11: 'Технология Начертания'
11: 'Технология Начертания',
12: 'Руководства по Шахтерскому делу'
},
11: {
2: 'Колчан',

View File

@@ -1330,6 +1330,7 @@ var g_item_subclasses = {
9: "钓鱼书籍",
10: "宝石加工设计",
11: "铭文技能",
12: "采矿指南"
},
11: {
2: '箭袋',

View File

@@ -1,5 +1,10 @@
<?php namespace Aowow; ?>
<?php
namespace Aowow\Template;
use \Aowow\Lang;
[$icName, $icStack, $hasBuff] = $this->tooltip;
?>
<div id="ic<?=$this->typeId; ?>" style="float: left"></div>
<div id="tt<?=$this->typeId; ?>" class="wowhead-tooltip" style="float: left; padding-top: 1px"></div>
<div style="clear: left"></div>
@@ -7,8 +12,6 @@
<div id="ks<?=$this->typeId; ?>" style="margin-left: 70px; margin-top: 4px;"></div>
<?php
$hasBuff = !empty($this->jsGlobals[Type::SPELL][2][$this->typeId]['buff']); // not set with items
if ($hasBuff):
?>
<h3><?=Lang::spell('_aura'); ?></h3>
@@ -25,7 +28,7 @@ endif;
?>
<script type="text/javascript">//<![CDATA[
$WH.ge('ic<?=$this->typeId; ?>').appendChild(Icon.create('<?=$this->headIcons[0]; ?>', 2, null, 0, <?=$this->headIcons[1]; ?>));
$WH.ge('ic<?=$this->typeId; ?>').appendChild(Icon.create('<?=$icName; ?>', 2, null, 0, <?=$icStack; ?>));
var
tt = $WH.ge('tt<?=$this->typeId; ?>'),
<?php if ($hasBuff): ?>

View File

@@ -1,7 +1,10 @@
<?php namespace Aowow; ?>
<?php
namespace Aowow\Template;
<?php $this->brick('header'); ?>
use \Aowow\Lang;
$this->brick('header');
?>
<div class="main" id="main">
<div class="main-precontents" id="main-precontents"></div>
<div class="main-contents" id="main-contents">
@@ -17,7 +20,7 @@
<div class="text">
<?php $this->brick('redButtons'); ?>
<h1><?=$this->name; ?></h1>
<h1><?=$this->h1; ?></h1>
<?php
if ($this->unavailable):
?>
@@ -29,18 +32,18 @@ endif;
$this->brick('tooltip');
$this->brick('article');
$this->brick('markup', ['markup' => $this->article]);
if (isset($this->map)):
echo " <h3>".Lang::item('vendorIn')."</h3>\n";
$this->brick('mapper');
endif;
if (!empty($this->transfer)):
if ($this->transfer):
echo " <div class=\"pad\"></div>\n ".$this->transfer."\n";
endif;
if (!empty($this->subItems)):
if ($this->subItems):
?>
<div class="clear"></div>
<h3><?=Lang::item('_rndEnchants'); ?></h3>
@@ -56,7 +59,7 @@ if (!empty($this->subItems)):
endforeach;
echo ' <li><div><span title="ID'.Lang::main('colon').$this->subItems['randIds'][$k].'" class="tip q'.$this->subItems['quality'].'">...'.$i['name'].'</span>';
echo ' <small class="q0">'.sprintf(Lang::item('_chance'), $i['chance']).'</small><br />'.implode(', ', $eText).'</div></li>';
echo ' <small class="q0">'.Lang::item('_chance', [$i['chance']]).'</small><br />'.implode(', ', $eText).'</div></li>';
endif;
endforeach;
?>
@@ -93,7 +96,7 @@ $this->brick('book');
</div>
<?php
$this->brick('lvTabs', ['relTabs' => true]);
$this->brick('lvTabs');
$this->brick('contribute');
?>

View File

@@ -1,10 +1,11 @@
<?php namespace Aowow; ?>
<?php
$this->brick('header');
$f = $this->filterObj->values // shorthand
?>
namespace Aowow\Template;
use Aowow\Lang;
$this->brick('header');
$f = $this->filter->values; // shorthand
?>
<div class="main" id="main">
<div class="main-precontents" id="main-precontents"></div>
<div class="main-contents" id="main-contents">
@@ -12,21 +13,24 @@ $f = $this->filterObj->values // shorthand
<?php
$this->brick('announcement');
$this->brick('pageTemplate', ['fiQuery' => $this->filterObj->query, 'fiMenuItem' => [0]]);
$this->brick('pageTemplate', ['fiQuery' => $this->filter->query, 'fiMenuItem' => [0]]);
?>
<div id="fi" style="display: <?=($this->filterObj->query ? 'block' : 'none'); ?>;">
<div id="fi" style="display: <?=($this->filter->query ? 'block' : 'none'); ?>;">
<form action="?filter=items<?=$this->subCat; ?>" method="post" name="fi" onsubmit="return fi_submit(this)" onreset="return fi_reset(this)">
<div class="text">
<?php
$this->brick('headIcons');
$this->brick('redButtons');
?>
<h1><?=$this->h1; ?></h1>
</div>
<div class="rightpanel">
<div style="float: left"><?=Lang::item('_quality').Lang::main('colon'); ?></div>
<div style="float: left"><?=Lang::item('_quality'); ?></div>
<small><a href="javascript:;" onclick="document.forms['fi'].elements['qu[]'].selectedIndex = -1; return false" onmousedown="return false"><?=Lang::main('clear'); ?></a></small>
<div class="clear"></div>
<select name="qu[]" size="7" multiple="multiple" class="rightselect" style="background-color: #181818">
<?php
foreach (Lang::item('quality') as $k => $str):
echo ' <option value="'.$k.'" class="q'.$k.'"'.(isset($f['qu']) && in_array($k, (array)$f['qu']) ? ' selected' : null).'>'.$str."</option>\n";
endforeach;
?>
<?=$this->makeOptionsList(Lang::item('quality'), $f['qu'], 28, fn($v, $k, &$e) => $e = ['class' => 'q'.$k]); ?>
</select>
</div>
@@ -34,15 +38,11 @@ endforeach;
if ($this->slotList):
?>
<div class="rightpanel2">
<div style="float: left"><?=Lang::item('slot').Lang::main('colon'); ?></div>
<div style="float: left"><?=Lang::item('slot'); ?></div>
<small><a href="javascript:;" onclick="document.forms['fi'].elements['sl[]'].selectedIndex = -1; return false" onmousedown="return false"><?=Lang::main('clear'); ?></a></small>
<div class="clear"></div>
<select name="sl[]" size="<?=min(count($this->slotList), 7); ?>" multiple="multiple" class="rightselect">
<?php
foreach ($this->slotList as $k => $str):
echo ' <option value="'.$k.'" '.(isset($f['sl']) && in_array($k, (array)$f['sl']) ? ' selected' : null).'>'.$str."</option>\n";
endforeach;
?>
<?=$this->makeOptionsList($this->slotList, $f['sl'], 28); ?>
</select>
</div>
<?php
@@ -51,63 +51,46 @@ endif;
if ($this->typeList):
?>
<div class="rightpanel2">
<div style="float: left"><?=Lang::game('type').Lang::main('colon'); ?></div>
<div style="float: left"><?=Lang::game('type'); ?></div>
<small><a href="javascript:;" onclick="document.forms['fi'].elements['ty[]'].selectedIndex = -1; return false" onmousedown="return false"><?=Lang::main('clear'); ?></a></small>
<div class="clear"></div>
<select name="ty[]" size="<?=min(count($this->typeList), 7); ?>" multiple="multiple" class="rightselect">
<?php
foreach ($this->typeList as $k => $str):
$selected = false;
if (isset($f['ty']) && in_array($k, (array)$f['ty'])):
$selected = true;
elseif (isset($this->category[1]) && $this->category[0] == 0 && $this->category[1] == $k):
$selected = true;
endif;
echo ' <option value="'.$k.'" '.( $selected ? ' selected' : null).'>'.(is_array($str) ? $str[0] : $str)."</option>\n";
endforeach;
?>
<?=$this->makeOptionsList($this->typeList, $f['ty'], 28, function($v, $k, &$e) {
if (($this->pageTemplate['breadcrumb'][2] ?? null) === 0 && ($this->pageTemplate['breadcrumb'][3] ?? null) === $k)
$e = ['selected' => 'selected']; // preselect type for consumables .. blegh >:(
return true;
}); ?>
</select>
</div>
<?php endif; ?>
<table>
<tr>
<td><?=Util::ucFirst(Lang::main('name')).Lang::main('colon'); ?></td>
<td colspan="2">&nbsp;<input type="text" name="na" size="30" <?=(isset($f['na']) ? 'value="'.Util::htmlEscape($f['na']).'" ' : null); ?>/></td>
<td><?=$this->ucFirst(Lang::main('name')).Lang::main('colon'); ?></td>
<td colspan="2">&nbsp;<input type="text" name="na" size="30" <?=($f['na'] ? 'value="'.$this->escHTML($f['na']).'" ' : ''); ?>/></td>
<td></td>
</tr><tr>
<td class="padded"><?=Lang::game('level').Lang::main('colon'); ?></td>
<td class="padded">&nbsp;<input type="text" name="minle" maxlength="3" class="smalltextbox2" <?=(isset($f['minle']) ? 'value="'.$f['minle'].'" ' : null); ?>/> - <input type="text" name="maxle" maxlength="3" class="smalltextbox2" <?=(isset($f['maxle']) ? 'value="'.$f['maxle'].'" ' : null); ?>/></td>
<td class="padded">&nbsp;<input type="text" name="minle" maxlength="3" class="smalltextbox2" <?=($f['minle'] ? 'value="'.$f['minle'].'" ' : ''); ?>/> - <input type="text" name="maxle" maxlength="3" class="smalltextbox2" <?=($f['maxle'] ? 'value="'.$f['maxle'].'" ' : ''); ?>/></td>
<td class="padded">
<table>
<tr>
<td>&nbsp;&nbsp;&nbsp;<?=Lang::main('_reqLevel').Lang::main('colon'); ?></td>
<td>&nbsp;<input type="text" name="minrl" maxlength="2" class="smalltextbox" <?=(isset($f['minrl']) ? 'value="'.$f['minrl'].'" ' : null); ?>/> - <input type="text" name="maxrl" maxlength="2" class="smalltextbox" <?=(isset($f['maxrl']) ? 'value="'.$f['maxrl'].'" ' : null); ?>/></td>
<td>&nbsp;&nbsp;&nbsp;<?=Lang::main('_reqLevel'); ?></td>
<td>&nbsp;<input type="text" name="minrl" maxlength="2" class="smalltextbox" <?=($f['minrl'] ? 'value="'.$f['minrl'].'" ' : ''); ?>/> - <input type="text" name="maxrl" maxlength="2" class="smalltextbox" <?=($f['maxrl'] ? 'value="'.$f['maxrl'].'" ' : ''); ?>/></td>
</tr>
</table>
</td>
<td></td>
</tr><tr>
<td class="padded"><?=Lang::item('usableBy').Lang::main('colon'); ?></td>
<td class="padded"><?=Lang::item('usableBy'); ?></td>
<td class="padded">&nbsp;<select name="si" style="margin-right: 0.5em">
<option></option>
<?php
foreach (Lang::game('si') as $k => $str):
echo ' <option value="'.$k.'"'.(isset($f['si']) && $k == $f['si'] ? ' selected' : null).'>'.$str."</option>\n";
endforeach;
?>
<?=$this->makeOptionsList(Lang::game('si'), $f['si'], 28); ?>
</select></td>
<td class="padded">
&nbsp;<select name="ub">
<option></option>
<?php
foreach (Lang::game('cl') as $k => $str):
if ($str):
echo ' <option value="'.$k.'"'.(isset($f['ub']) && $k == $f['ub'] ? ' selected' : null).'>'.$str."</option>\n";
endif;
endforeach;
?>
<?=$this->makeOptionsList(Lang::game('cl'), $f['ub'], 28); ?>
</select></td>
</td>
</tr>
@@ -117,7 +100,8 @@ endforeach;
<div class="padded2">
<div style="float: right"><?=Lang::main('refineSearch'); ?></div>
<?=Lang::main('match').Lang::main('colon'); ?><input type="radio" name="ma" value="" id="ma-0" <?=(!isset($f['ma']) ? 'checked="checked" ' : null); ?>/><label for="ma-0"><?=Lang::main('allFilter'); ?></label><input type="radio" name="ma" value="1" id="ma-1" <?=(isset($f['ma']) ? 'checked="checked" ' : null); ?>/><label for="ma-1"><?=Lang::main('oneFilter'); ?></label>
<?=Lang::main('match'); ?>
<input type="radio" name="ma" value="" id="ma-0" <?=(!$f['ma'] ? 'checked="checked" ' : ''); ?>/><label for="ma-0"><?=Lang::main('allFilter'); ?></label><input type="radio" name="ma" value="1" id="ma-1" <?=($f['ma'] ? 'checked="checked" ' : ''); ?>/><label for="ma-1"><?=Lang::main('oneFilter'); ?></label>
</div>
<div class="pad3"></div>
@@ -133,19 +117,17 @@ endforeach;
<table>
<tr>
<td><?=Lang::main('preset').Lang::main('colon'); ?></td>
<td><?=Lang::main('preset'); ?></td>
<td id="fi_presets"></td>
</tr>
<tr>
<td class="padded"><?=Lang::item('gems').Lang::main('colon'); ?></td>
<td class="padded"><?=Lang::item('gems'); ?></td>
<td class="padded">
<select name="gm">
<option<?=(!isset($f['gm']) ? ' selected' : null); ?>></option>
<option value="2"<?=(isset($f['gm']) && $f['gm'] == 2 ? ' selected' : null).'>'.Lang::item('quality', 2); ?></option>
<option value="3"<?=(isset($f['gm']) && $f['gm'] == 3 ? ' selected' : null).'>'.Lang::item('quality', 3); ?></option>
<option value="4"<?=(isset($f['gm']) && $f['gm'] == 4 ? ' selected' : null).'>'.Lang::item('quality', 4); ?></option>
<option<?=(!$f['gm'] ? ' selected' : ''); ?>></option>
<?=$this->makeOptionsList(Lang::item('quality'), $f['gm'], 40, fn($v, $k) => in_array($k, [ITEM_QUALITY_UNCOMMON, ITEM_QUALITY_RARE, ITEM_QUALITY_EPIC])); ?>
</select>
&nbsp; <input type="checkbox" name="jc" value="1" id="jc" <?=(isset($f['jc']) && $f['jc'] == 1 ? 'checked="checked" ' : null); ?>/><label for="jc"><?=sprintf(Lang::main('jcGemsOnly'), ' class="tip" onmouseover="$WH.Tooltip.showAtCursor(event, LANG.tooltip_jconlygems, 0, 0, \'q\')" onmousemove="$WH.Tooltip.cursorUpdate(event)" onmouseout="$WH.Tooltip.hide()"'); ?></label>
&nbsp; <input type="checkbox" name="jc" value="1" id="jc" <?=($f['jc'] && $f['jc'] == 1 ? 'checked="checked" ' : ''); ?>/><label for="jc"><?=sprintf(Lang::main('jcGemsOnly'), ' class="tip" onmouseover="$WH.Tooltip.showAtCursor(event, LANG.tooltip_jconlygems, 0, 0, \'q\')" onmousemove="$WH.Tooltip.cursorUpdate(event)" onmouseout="$WH.Tooltip.hide()"'); ?></label>
</td>
</tr>
</table>
@@ -159,16 +141,8 @@ endforeach;
<div class="clear"></div>
<div class="padded">
<?php
echo Lang::main('groupBy').Lang::main('colon')."\n";
foreach (Lang::main('gb') as $k => $str):
if ($k):
echo ' <input type="radio" name="gb" value="'.$k.'" id="gb-'.$str[1].'"'.(!empty($f['gb']) && $f['gb'] == $k ? ' checked="checked"' : null).'/><label for="gb-'.$str[1].'">'.$str[0]."</label>\n";
else:
echo ' <input type="radio" name="gb" value="" id="gb-'.$str[1].'"'.(empty($f['gb']) ? ' checked="checked"' : null).'/><label for="gb-'.$str[1].'">'.$str[0]."</label>\n";
endif;
endforeach;
?>
<?=Lang::main('groupBy')."\n"; ?>
<?=$this->makeRadiosList('gb', Lang::main('gb'), $f['gb'] ?? '', 24, fn($v, &$k) => ($k = $k ?: '') || 1); ?>
</div>
<div class="clear"></div>
@@ -178,7 +152,7 @@ endforeach;
<input type="reset" value="<?=Lang::main('resetForm'); ?>" />
</div>
<input type="hidden" name="upg"<?=($f['upg'] ? ' value="'.implode(':', $f['upg']).'"' : ''); ?>/>
<input type="hidden" name="upg" value ="<?=($f['upg'] ? implode(':', $f['upg']) : ''); ?>" />
<div class="pad"></div>
@@ -186,7 +160,7 @@ endforeach;
<div class="pad"></div>
</div>
<?php $this->brick('filter'); ?>
<?=$this->renderFilter(12); ?>
<?php $this->brick('lvTabs'); ?>