public function renderTooltip($interactive = false, $subOf = 0, $enhance = []) { if ($this->error) { return; } $_name = $this->getField('name', true); $_reqLvl = $this->curTpl['requiredLevel']; $_quality = $this->curTpl['quality']; $_flags = $this->curTpl['flags']; $_class = $this->curTpl['class']; $_subClass = $this->curTpl['subClass']; $_slot = $this->curTpl['slot']; $causesScaling = false; if (!empty($enhance['r'])) { if ($this->getRandEnchantForItem($enhance['r'])) { $_name .= ' ' . Util::localizedString($this->enhanceR, 'name'); $randEnchant = ''; for ($i = 1; $i < 6; $i++) { if ($this->enhanceR['enchantId' . $i] <= 0) { continue; } $enchant = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantment WHERE Id = ?d', $this->enhanceR['enchantId' . $i]); if ($this->enhanceR['allocationPct' . $i] > 0) { $amount = intVal($this->enhanceR['allocationPct' . $i] * $this->generateEnchSuffixFactor()); $randEnchant .= '<span>' . str_replace('$i', $amount, Util::localizedString($enchant, 'name')) . '</span><br />'; } else { $randEnchant .= '<span>' . Util::localizedString($enchant, 'name') . '</span><br />'; } } } else { unset($enhance['r']); } } if (isset($enhance['s']) && !in_array($_slot, [INVTYPE_WRISTS, INVTYPE_WAIST, INVTYPE_HANDS])) { unset($enhance['s']); } // IMPORTAT: DO NOT REMOVE THE HTML-COMMENTS! THEY ARE REQUIRED TO UPDATE THE TOOLTIP CLIENTSIDE $x = ''; // upper table: stats if (!$subOf) { $x .= '<table><tr><td>'; } // name; quality if ($subOf) { $x .= '<span class="q' . $_quality . '"><a href="?item=' . $this->id . '">' . $_name . '</a></span>'; } else { $x .= '<b class="q' . $_quality . '">' . $_name . '</b>'; } // heroic tag if ($_flags & ITEM_FLAG_HEROIC && $_quality == ITEM_QUALITY_EPIC) { $x .= '<br /><span class="q2">' . Lang::item('heroic') . '</span>'; } // requires map (todo: reparse ?_zones for non-conflicting data; generate Link to zone) if ($_ = $this->curTpl['map']) { $map = DB::Aowow()->selectRow('SELECT * FROM ?_zones WHERE mapId = ?d LIMIT 1', $_); $x .= '<br /><a href="?zone=' . $_ . '" class="q1">' . Util::localizedString($map, 'name') . '</a>'; } // requires area if ($this->curTpl['area']) { $area = DB::Aowow()->selectRow('SELECT * FROM ?_zones WHERE Id=?d LIMIT 1', $this->curTpl['area']); $x .= '<br />' . Util::localizedString($area, 'name'); } // conjured if ($_flags & ITEM_FLAG_CONJURED) { $x .= '<br />' . Lang::item('conjured'); } // bonding if ($_flags & ITEM_FLAG_ACCOUNTBOUND) { $x .= '<br /><!--bo-->' . Lang::item('bonding', 0); } else { if ($this->curTpl['bonding']) { $x .= '<br /><!--bo-->' . Lang::item('bonding', $this->curTpl['bonding']); } } // unique || unique-equipped || unique-limited if ($this->curTpl['maxCount'] > 0) { $x .= '<br />' . Lang::item('unique'); if ($this->curTpl['maxCount'] > 1) { $x .= ' (' . $this->curTpl['maxCount'] . ')'; } } else { if ($_flags & ITEM_FLAG_UNIQUEEQUIPPED) { $x .= '<br />' . Lang::item('uniqueEquipped'); } else { if ($this->curTpl['itemLimitCategory']) { $limit = DB::Aowow()->selectRow("SELECT * FROM ?_itemlimitcategory WHERE id = ?", $this->curTpl['itemLimitCategory']); $x .= '<br />' . ($limit['isGem'] ? Lang::item('uniqueEquipped') : Lang::item('unique')) . Lang::main('colon') . Util::localizedString($limit, 'name') . ' (' . $limit['count'] . ')'; } } } // max duration if ($dur = $this->curTpl['duration']) { $x .= "<br />" . Lang::game('duration') . Lang::main('colon') . Util::formatTime(abs($dur) * 1000) . ($this->curTpl['flagsCustom'] & 0x1 ? ' (' . Lang::item('realTime') . ')' : null); } // required holiday if ($eId = $this->curTpl['eventId']) { if ($hName = DB::Aowow()->selectRow('SELECT h.* FROM ?_holidays h JOIN ?_events e ON e.holidayId = h.id WHERE e.id = ?d', $eId)) { $x .= '<br />' . sprintf(Lang::game('requires'), '<a href="' . $eId . '" class="q1">' . Util::localizedString($hName, 'name') . '</a>'); } } // item begins a quest if ($this->curTpl['startQuest']) { $x .= '<br /><a class="q1" href="?quest=' . $this->curTpl['startQuest'] . '">' . Lang::item('startQuest') . '</a>'; } // containerType (slotCount) if ($this->curTpl['slots'] > 0) { $fam = $this->curTpl['bagFamily'] ? log($this->curTpl['bagFamily'], 2) + 1 : 0; // word order differs <_< if (in_array(User::$localeId, [LOCALE_FR, LOCALE_ES, LOCALE_RU])) { $x .= '<br />' . sprintf(Lang::item('bagSlotString'), Lang::item('bagFamily', $fam), $this->curTpl['slots']); } else { $x .= '<br />' . sprintf(Lang::item('bagSlotString'), $this->curTpl['slots'], Lang::item('bagFamily', $fam)); } } if (in_array($_class, [ITEM_CLASS_ARMOR, ITEM_CLASS_WEAPON, ITEM_CLASS_AMMUNITION])) { $x .= '<table width="100%"><tr>'; // Class if ($_slot) { $x .= '<td>' . Lang::item('inventoryType', $_slot) . '</td>'; } // Subclass if ($_class == ITEM_CLASS_ARMOR && $_subClass > 0) { $x .= '<th><!--asc' . $_subClass . '-->' . Lang::item('armorSubClass', $_subClass) . '</th>'; } else { if ($_class == ITEM_CLASS_WEAPON) { $x .= '<th>' . Lang::item('weaponSubClass', $_subClass) . '</th>'; } else { if ($_class == ITEM_CLASS_AMMUNITION) { $x .= '<th>' . Lang::item('projectileSubClass', $_subClass) . '</th>'; } } } $x .= '</tr></table>'; } else { if ($_slot && $_class != ITEM_CLASS_CONTAINER) { // yes, slot can occur on random items and is then also displayed <_< .. excluding Bags >_> $x .= '<br />' . Lang::item('inventoryType', $_slot) . '<br />'; } else { $x .= '<br />'; } } // Weapon/Ammunition Stats (not limited to weapons (see item:1700)) $speed = $this->curTpl['delay'] / 1000; $dmgmin1 = $this->curTpl['dmgMin1'] + $this->curTpl['dmgMin2']; $dmgmax1 = $this->curTpl['dmgMax1'] + $this->curTpl['dmgMax2']; $dps = $speed ? ($dmgmin1 + $dmgmax1) / (2 * $speed) : 0; if ($_class == ITEM_CLASS_AMMUNITION && $dmgmin1 && $dmgmax1) { $x .= Lang::item('addsDps') . ' ' . number_format(($dmgmin1 + $dmgmax1) / 2, 1) . ' ' . Lang::item('dps2') . '<br />'; } else { if ($dps) { if ($_class == ITEM_CLASS_WEAPON) { $x .= '<table width="100%"><tr>'; $x .= '<td><!--dmg-->' . sprintf($this->curTpl['dmgType1'] ? Lang::item('damageMagic') : Lang::item('damagePhys'), $this->curTpl['dmgMin1'] . ' - ' . $this->curTpl['dmgMax1'], Lang::game('sc', $this->curTpl['dmgType1'])) . '</td>'; $x .= '<th>' . Lang::item('speed') . ' <!--spd-->' . number_format($speed, 2) . '</th>'; // do not use localized format here! $x .= '</tr></table>'; } else { $x .= '<!--dmg-->' . sprintf($this->curTpl['dmgType1'] ? Lang::item('damageMagic') : Lang::item('damagePhys'), $this->curTpl['dmgMin1'] . ' - ' . $this->curTpl['dmgMax1'], Lang::game('sc', $this->curTpl['dmgType1'])) . '<br />'; } // secondary damage is set if ($this->curTpl['dmgMin2']) { $x .= '+' . sprintf($this->curTpl['dmgType2'] ? Lang::item('damageMagic') : Lang::item('damagePhys'), $this->curTpl['dmgMin2'] . ' - ' . $this->curTpl['dmgMax2'], Lang::game('sc', $this->curTpl['dmgType2'])) . '<br />'; } if ($_class == ITEM_CLASS_WEAPON) { $x .= '<!--dps-->(' . number_format($dps, 1) . ' ' . Lang::item('dps') . ')<br />'; } // do not use localized format here! // display FeralAttackPower if set if ($fap = $this->getFeralAP()) { $x .= '<span class="c11"><!--fap-->(' . $fap . ' ' . Lang::item('fap') . ')</span><br />'; } } } // Armor if ($_class == ITEM_CLASS_ARMOR && $this->curTpl['armorDamageModifier'] > 0) { $spanI = 'class="q2"'; if ($interactive) { $spanI = 'class="q2 tip" onmouseover="$WH.Tooltip.showAtCursor(event, $WH.sprintf(LANG.tooltip_armorbonus, ' . $this->curTpl['armorDamageModifier'] . '), 0, 0, \'q\')" onmousemove="$WH.Tooltip.cursorUpdate(event)" onmouseout="$WH.Tooltip.hide()"'; } $x .= '<span ' . $spanI . '><!--addamr' . $this->curTpl['armorDamageModifier'] . '--><span>' . sprintf(Lang::item('armor'), intVal($this->curTpl['armor'] + $this->curTpl['armorDamageModifier'])) . '</span></span><br />'; } else { if ($this->curTpl['armor'] + $this->curTpl['armorDamageModifier'] > 0) { $x .= '<span><!--amr-->' . sprintf(Lang::item('armor'), intVal($this->curTpl['armor'] + $this->curTpl['armorDamageModifier'])) . '</span><br />'; } } // Block if ($this->curTpl['block']) { $x .= '<span>' . sprintf(Lang::item('block'), $this->curTpl['block']) . '</span><br />'; } // Item is a gem (don't mix with sockets) if ($geId = $this->curTpl['gemEnchantmentId']) { $gemEnch = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantment WHERE id = ?d', $geId); $x .= '<span class="q1"><a href="?enchantment=' . $geId . '">' . Util::localizedString($gemEnch, 'name') . '</a></span><br />'; // 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; } switch ($gemCnd['comparator' . $i]) { case 2: // requires less <color> than (<value> || <comparecolor>) gems // requires less <color> than (<value> || <comparecolor>) gems case 5: // requires at least <color> than (<value> || <comparecolor>) gems $sp = (int) $gemCnd['value' . $i] > 1; $x .= '<span class="q0">' . Lang::achievement('reqNumCrt') . ' ' . sprintf(Lang::item('gemConditions', $gemCnd['comparator' . $i], $sp), $gemCnd['value' . $i], Lang::item('gemColors', $gemCnd['color' . $i] - 1)) . '</span><br />'; break; case 3: // requires more <color> than (<value> || <comparecolor>) gems $x .= '<span class="q0">' . Lang::achievement('reqNumCrt') . ' ' . sprintf(Lang::item('gemConditions', 3), Lang::item('gemColors', $gemCnd['color' . $i] - 1), Lang::item('gemColors', $gemCnd['cmpColor' . $i] - 1)) . '</span><br />'; break; } } } } } // Random Enchantment - if random enchantment is set, prepend stats from it if ($this->curTpl['randomEnchant'] && !isset($enhance['r'])) { $x .= '<span class="q2">' . Lang::item('randEnchant') . '</span><br />'; } else { if (isset($enhance['r'])) { $x .= $randEnchant; } } // itemMods (display stats and save ratings for later use) for ($j = 1; $j <= 10; $j++) { $type = $this->curTpl['statType' . $j]; $qty = $this->curTpl['statValue' . $j]; if (!$qty || $type <= 0) { continue; } // base stat if ($type >= ITEM_MOD_AGILITY && $type <= ITEM_MOD_STAMINA) { $x .= '<span><!--stat' . $type . '-->' . ($qty > 0 ? '+' : '-') . abs($qty) . ' ' . Lang::item('statType', $type) . '</span><br />'; } else { // rating with % for reqLevel $green[] = $this->parseRating($type, $qty, $interactive, $causesScaling); } } // magic resistances foreach (Util::$resistanceFields as $j => $rowName) { if ($rowName && $this->curTpl[$rowName] != 0) { $x .= '+' . $this->curTpl[$rowName] . ' ' . Lang::game('resistances', $j) . '<br />'; } } // Enchantment if (isset($enhance['e'])) { if ($enchText = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantment WHERE Id = ?', $enhance['e'])) { $x .= '<span class="q2"><!--e-->' . Util::localizedString($enchText, 'name') . '</span><br />'; } else { unset($enhance['e']); $x .= '<!--e-->'; } } else { // enchantment placeholder $x .= '<!--e-->'; } // Sockets w/ Gems if (!empty($enhance['g'])) { $gems = DB::Aowow()->select(' SELECT it.id AS ARRAY_KEY, ic.iconString, ae.*, it.gemColorMask AS colorMask FROM ?_items it JOIN ?_itemenchantment ae ON ae.id = it.gemEnchantmentId JOIN ?_icons ic ON ic.id = -it.displayId WHERE it.id IN (?a)', $enhance['g']); foreach ($enhance['g'] as $k => $v) { if ($v && !in_array($v, array_keys($gems))) { // 0 is valid unset($enhance['g'][$k]); } } } else { $enhance['g'] = []; } // zero fill empty sockets $sockCount = isset($enhance['s']) ? 1 : 0; if (!empty($this->json[$this->id]['nsockets'])) { $sockCount += $this->json[$this->id]['nsockets']; } while ($sockCount > count($enhance['g'])) { $enhance['g'][] = 0; } $enhance['g'] = array_reverse($enhance['g']); $hasMatch = 1; // fill native sockets for ($j = 1; $j <= 3; $j++) { if (!$this->curTpl['socketColor' . $j]) { continue; } for ($i = 0; $i < 4; $i++) { if ($this->curTpl['socketColor' . $j] & 1 << $i) { $colorId = $i; } } $pop = array_pop($enhance['g']); $col = $pop ? 1 : 0; $hasMatch &= $pop ? $gems[$pop]['colorMask'] & 1 << $colorId ? 1 : 0 : 0; $icon = $pop ? sprintf(Util::$bgImagePath['tiny'], STATIC_URL, strtolower($gems[$pop]['iconString'])) : null; $text = $pop ? Util::localizedString($gems[$pop], 'name') : Lang::item('socket', $colorId); if ($interactive) { $x .= '<a href="?items=3&filter=cr=81;crs=' . ($colorId + 1) . ';crv=0" class="socket-' . Util::$sockets[$colorId] . ' q' . $col . '" ' . $icon . '>' . $text . '</a><br />'; } else { $x .= '<span class="socket-' . Util::$sockets[$colorId] . ' q' . $col . '" ' . $icon . '>' . $text . '</span><br />'; } } // fill extra socket if (isset($enhance['s'])) { $pop = array_pop($enhance['g']); $col = $pop ? 1 : 0; $icon = $pop ? sprintf(Util::$bgImagePath['tiny'], STATIC_URL, strtolower($gems[$pop]['iconString'])) : null; $text = $pop ? Util::localizedString($gems[$pop], 'name') : Lang::item('socket', -1); if ($interactive) { $x .= '<a href="?items=3&filter=cr=81;crs=5;crv=0" class="socket-prismatic q' . $col . '" ' . $icon . '>' . $text . '</a><br />'; } else { $x .= '<span class="socket-prismatic q' . $col . '" ' . $icon . '>' . $text . '</span><br />'; } } else { // prismatic socket placeholder $x .= '<!--ps-->'; } if ($_ = $this->curTpl['socketBonus']) { $sbonus = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantment WHERE Id = ?d', $_); $x .= '<span class="q' . ($hasMatch ? '2' : '0') . '">' . Lang::item('socketBonus') . Lang::main('colon') . '<a href="?enchantment=' . $_ . '">' . Util::localizedString($sbonus, 'name') . '</a></span><br />'; } // durability if ($dur = $this->curTpl['durability']) { $x .= Lang::item('durability') . ' ' . $dur . ' / ' . $dur . '<br />'; } // required classes if ($classes = Lang::getClassString($this->curTpl['requiredClass'], $jsg, $__)) { foreach ($jsg as $js) { if (empty($this->jsGlobals[TYPE_CLASS][$js])) { $this->jsGlobals[TYPE_CLASS][$js] = $js; } } $x .= Lang::game('classes') . Lang::main('colon') . $classes . '<br />'; } // required races if ($races = Lang::getRaceString($this->curTpl['requiredRace'], $__, $jsg, $__)) { foreach ($jsg as $js) { if (empty($this->jsGlobals[TYPE_RACE][$js])) { $this->jsGlobals[TYPE_RACE][$js] = $js; } } if ($races != Lang::game('ra', 0)) { // not "both", but display combinations like: troll, dwarf $x .= Lang::game('races') . Lang::main('colon') . $races . '<br />'; } } // required honorRank (not used anymore) if ($rhr = $this->curTpl['requiredHonorRank']) { $x .= sprintf(Lang::game('requires'), Lang::game('pvpRank', $rhr)) . '<br />'; } // required CityRank..? // what the f.. // required level if ($_flags & ITEM_FLAG_ACCOUNTBOUND && $_quality == ITEM_QUALITY_HEIRLOOM) { $x .= sprintf(Lang::game('reqLevelHlm'), ' 1' . Lang::game('valueDelim') . MAX_LEVEL . ' (' . ($interactive ? sprintf(Util::$changeLevelString, MAX_LEVEL) : '<!--lvl-->' . MAX_LEVEL) . ')') . '<br />'; } else { if ($_reqLvl > 1) { $x .= sprintf(Lang::game('reqLevel'), $_reqLvl) . '<br />'; } } // required arena team rating / personal rating / todo (low): sort out what kind of rating if (!empty($this->getExtendedCost([], $reqRating)[$this->id]) && $reqRating) { $x .= sprintf(Lang::item('reqRating', $reqRating[1]), $reqRating[0]) . '<br />'; } // item level if (in_array($_class, [ITEM_CLASS_ARMOR, ITEM_CLASS_WEAPON])) { $x .= Lang::item('itemLevel') . ' ' . $this->curTpl['itemLevel'] . '<br />'; } // required skill if ($reqSkill = $this->curTpl['requiredSkill']) { $_ = '<a class="q1" href="?skill=' . $reqSkill . '">' . SkillList::getName($reqSkill) . '</a>'; if ($this->curTpl['requiredSkillRank'] > 0) { $_ .= ' (' . $this->curTpl['requiredSkillRank'] . ')'; } $x .= sprintf(Lang::game('requires'), $_) . '<br />'; } // required spell if ($reqSpell = $this->curTpl['requiredSpell']) { $x .= Lang::game('requires2') . ' <a class="q1" href="?spell=' . $reqSpell . '">' . SpellList::getName($reqSpell) . '</a><br />'; } // required reputation w/ faction if ($reqFac = $this->curTpl['requiredFaction']) { $x .= sprintf(Lang::game('requires'), '<a class="q1" href=?faction="' . $reqFac . '">' . FactionList::getName($reqFac) . '</a> - ' . Lang::game('rep', $this->curTpl['requiredFactionRank'])) . '<br />'; } // locked or openable if ($locks = Lang::getLocks($this->curTpl['lockId'], true)) { $x .= '<span class="q0">' . Lang::item('locked') . '<br />' . implode('<br />', $locks) . '</span><br />'; } else { if ($this->curTpl['flags'] & ITEM_FLAG_OPENABLE) { $x .= '<span class="q2">' . Lang::item('openClick') . '</span><br />'; } } // upper table: done if (!$subOf) { $x .= '</td></tr></table>'; } // spells on item if (!$this->canTeachSpell()) { $itemSpellsAndTrigger = []; for ($j = 1; $j <= 5; $j++) { if ($this->curTpl['spellId' . $j] > 0) { $cd = $this->curTpl['spellCooldown' . $j]; if ($cd < $this->curTpl['spellCategoryCooldown' . $j]) { $cd = $this->curTpl['spellCategoryCooldown' . $j]; } $cd = $cd < 5000 ? null : ' (' . sprintf(Lang::game('cooldown'), Util::formatTime($cd)) . ')'; $itemSpellsAndTrigger[$this->curTpl['spellId' . $j]] = [$this->curTpl['spellTrigger' . $j], $cd]; } } if ($itemSpellsAndTrigger) { $cooldown = ''; $itemSpells = new SpellList(array(['s.id', array_keys($itemSpellsAndTrigger)])); foreach ($itemSpells->iterate() as $__) { if ($parsed = $itemSpells->parseText('description', $_reqLvl > 1 ? $_reqLvl : MAX_LEVEL, false, $causesScaling)[0]) { if ($interactive) { $link = '<a href="?spell=' . $itemSpells->id . '">%s</a>'; $parsed = preg_replace_callback('/([^;]*)( <small>.*?<\\/small>)([^&]*)/i', function ($m) use($link) { $m[1] = $m[1] ? sprintf($link, $m[1]) : ''; $m[3] = $m[3] ? sprintf($link, $m[3]) : ''; return $m[1] . $m[2] . $m[3]; }, $parsed, -1, $nMatches); if (!$nMatches) { $parsed = sprintf($link, $parsed); } } $green[] = Lang::item('trigger', $itemSpellsAndTrigger[$itemSpells->id][0]) . $parsed . $itemSpellsAndTrigger[$itemSpells->id][1]; } } } } // lower table (ratings, spells, ect) if (!$subOf) { $x .= '<table><tr><td>'; } if (isset($green)) { foreach ($green as $j => $bonus) { if ($bonus) { $x .= '<span class="q2">' . $bonus . '</span><br />'; } } } // Item Set $pieces = []; if ($setId = $this->getField('itemset')) { // while Ids can technically be used multiple times the only difference in data are the items used. So it doesn't matter what we get $itemset = new ItemsetList(array(['id', $setId])); if (!$itemset->error && $itemset->pieceToSet) { $pieces = DB::Aowow()->select(' SELECT b.id AS ARRAY_KEY, b.name_loc0, b.name_loc2, b.name_loc3, b.name_loc6, b.name_loc8, GROUP_CONCAT(a.id SEPARATOR \':\') AS equiv FROM ?_items a, ?_items b WHERE a.slotBak = b.slotBak AND a.itemset = b.itemset AND b.id IN (?a) GROUP BY b.id;', array_keys($itemset->pieceToSet)); foreach ($pieces as $k => &$p) { $p = '<span><!--si' . $p['equiv'] . '--><a href="?item=' . $k . '">' . Util::localizedString($p, 'name') . '</a></span>'; } $xSet = '<br /><span class="q"><a href="?itemset=' . $itemset->id . '" class="q">' . $itemset->getField('name', true) . '</a> (0/' . count($pieces) . ')</span>'; if ($skId = $itemset->getField('skillId')) { $xSet .= '<br />' . sprintf(Lang::game('requires'), '<a href="?skills=' . $skId . '" class="q1">' . SkillList::getName($skId) . '</a>'); if ($_ = $itemset->getField('skillLevel')) { $xSet .= ' (' . $_ . ')'; } $xSet .= '<br />'; } // list pieces $xSet .= '<div class="q0 indent">' . implode('<br />', $pieces) . '</div><br />'; // get bonuses $setSpellsAndIdx = []; for ($j = 1; $j <= 8; $j++) { if ($_ = $itemset->getField('spell' . $j)) { $setSpellsAndIdx[$_] = $j; } } $setSpells = []; if ($setSpellsAndIdx) { $boni = new SpellList(array(['s.id', array_keys($setSpellsAndIdx)])); foreach ($boni->iterate() as $__) { $setSpells[] = array('tooltip' => $boni->parseText('description', $_reqLvl > 1 ? $_reqLvl : MAX_LEVEL, false, $causesScaling)[0], 'entry' => $itemset->getField('spell' . $setSpellsAndIdx[$boni->id]), 'bonus' => $itemset->getField('bonus' . $setSpellsAndIdx[$boni->id])); } } // sort and list bonuses $xSet .= '<span class="q0">'; for ($i = 0; $i < count($setSpells); $i++) { for ($j = $i; $j < count($setSpells); $j++) { if ($setSpells[$j]['bonus'] >= $setSpells[$i]['bonus']) { continue; } $tmp = $setSpells[$i]; $setSpells[$i] = $setSpells[$j]; $setSpells[$j] = $tmp; } $xSet .= '<span>(' . $setSpells[$i]['bonus'] . ') ' . Lang::item('set') . ': <a href="?spell=' . $setSpells[$i]['entry'] . '">' . $setSpells[$i]['tooltip'] . '</a></span>'; if ($i < count($setSpells) - 1) { $xSet .= '<br />'; } } $xSet .= '</span>'; } } // recipes, vanity pets, mounts if ($this->canTeachSpell()) { $craftSpell = new SpellList(array(['s.id', intVal($this->curTpl['spellId2'])])); if (!$craftSpell->error) { $xCraft = ''; if ($desc = $this->getField('description', true)) { $x .= '<span class="q2">' . Lang::item('trigger', 0) . ' <a href="?spell=' . $this->curTpl['spellId2'] . '">' . $desc . '</a></span><br />'; } // recipe handling (some stray Techniques have subclass == 0), place at bottom of tooltipp if ($_class == ITEM_CLASS_RECIPE || $this->curTpl['bagFamily'] == 16) { $craftItem = new ItemList(array(['i.id', (int) $craftSpell->curTpl['effect1CreateItemId']])); if (!$craftItem->error) { if ($itemTT = $craftItem->renderTooltip($interactive, $this->id)) { $xCraft .= '<div><br />' . $itemTT . '</div>'; } $reagentItems = []; for ($i = 1; $i <= 8; $i++) { if ($rId = $craftSpell->getField('reagent' . $i)) { $reagentItems[$rId] = $craftSpell->getField('reagentCount' . $i); } } if (isset($xCraft) && $reagentItems) { $reagents = new ItemList(array(['i.id', array_keys($reagentItems)])); $reqReag = []; foreach ($reagents->iterate() as $__) { $reqReag[] = '<a href="?item=' . $reagents->id . '">' . $reagents->getField('name', true) . '</a> (' . $reagentItems[$reagents->id] . ')'; } $xCraft .= '<div class="q1 whtt-reagents"><br />' . Lang::game('requires2') . ' ' . implode(', ', $reqReag) . '</div>'; } } } } } // misc (no idea, how to organize the <br /> better) $xMisc = []; // itemset: pieces and boni if (isset($xSet)) { $xMisc[] = $xSet; } // funny, yellow text at the bottom, omit if we have a recipe if ($this->curTpl['description_loc0'] && !$this->canTeachSpell()) { $xMisc[] = '<span class="q">"' . $this->getField('description', true) . '"</span>'; } // readable if ($this->curTpl['pageTextId']) { $xMisc[] = '<span class="q2">' . Lang::item('readClick') . '</span>'; } // charges (i guess checking first spell is enough (single charges not shown)) if ($this->curTpl['spellCharges1'] > 1 || $this->curTpl['spellCharges1'] < -1) { $xMisc[] = '<span class="q1">' . abs($this->curTpl['spellCharges1']) . ' ' . Lang::item('charges') . '</span>'; } // list required reagents if (isset($xCraft)) { $xMisc[] = $xCraft; } if ($xMisc) { $x .= implode('<br />', $xMisc); } if ($sp = $this->curTpl['sellPrice']) { $x .= '<div class="q1 whtt-sellprice">' . Lang::item('sellPrice') . Lang::main('colon') . Util::formatMoney($sp) . '</div>'; } if (!$subOf) { $x .= '</td></tr></table>'; } // tooltip scaling if (!isset($xCraft)) { $link = [$subOf ? $subOf : $this->id, 1]; // itemId, scaleMinLevel if (isset($this->ssd[$this->id])) { array_push($link, $this->ssd[$this->id]['maxLevel'], $this->ssd[$this->id]['maxLevel'], $this->curTpl['scalingStatDistribution'], $this->curTpl['scalingStatValue']); } else { array_push($link, $causesScaling ? MAX_LEVEL : 1, $_reqLvl > 1 ? $_reqLvl : MAX_LEVEL); } $x .= '<!--?' . implode(':', $link) . '-->'; } return $x; }
<tr><th id="infobox-series"><?php echo $listTitle ?: Lang::achievement('series'); ?> </th></tr> <tr><td> <div class="infobox-spacer"></div> <table class="series"> <?php foreach ($list as $idx => $itr) { echo ' <tr><th>' . ($idx + 1) . '</th><td><div>'; $_ = array_keys($itr); $end = array_pop($_); foreach ($itr as $k => $i) { // itemItr switch ($i['side']) { case 1: $wrap = '<span class="icon-alliance-padded">%s</span>'; break; case 2: $wrap = '<span class="icon-horde">%s</span>'; break; default: $wrap = '%s'; break; } if ($i['typeId'] == $this->typeId) { echo sprintf($wrap, '<b>' . $i['name'] . '</b>'); } else { echo sprintf($wrap, '<a href="?' . $i['typeStr'] . '=' . $i['typeId'] . '">' . $i['name'] . '</a>'); } echo $end == $k ? null : '<br />';
protected function generateContent() { $_level = $this->subject->getField('level'); $_minLevel = $this->subject->getField('minLevel'); $_flags = $this->subject->getField('flags'); $_specialFlags = $this->subject->getField('specialFlags'); $_side = Util::sideByRaceMask($this->subject->getField('reqRaceMask')); /***********/ /* Infobox */ /***********/ $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); // event (todo: assign eventData) if ($_ = $this->subject->getField('eventId')) { $this->extendGlobalIds(TYPE_WORLDEVENT, $_); $infobox[] = Lang::game('eventShort') . Lang::main('colon') . '[event=' . $_ . ']'; } // level if ($_level > 0) { $infobox[] = Lang::game('level') . Lang::main('colon') . $_level; } // reqlevel if ($_minLevel) { $lvl = $_minLevel; if ($_ = $this->subject->getField('maxLevel')) { $lvl .= ' - ' . $_; } $infobox[] = sprintf(Lang::game('reqLevel'), $lvl); } // loremaster (i dearly hope those flags cover every case...) if ($this->subject->getField('zoneOrSortBak') > 0 && !$this->subject->isRepeatable()) { $conditions = array(['ac.type', ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE], ['ac.value1', $this->subject->getField('zoneOrSortBak')], ['a.faction', $_side, '&']); $loremaster = new AchievementList($conditions); $this->extendGlobalData($loremaster->getJSGlobals(GLOBALINFO_SELF)); switch ($loremaster->getMatches()) { case 0: break; case 1: $infobox[] = Lang::quest('loremaster') . Lang::main('colon') . '[achievement=' . $loremaster->id . ']'; break; default: $lm = Lang::quest('loremaster') . Lang::main('colon') . '[ul]'; foreach ($loremaster->iterate() as $id => $__) { $lm .= '[li][achievement=' . $id . '][/li]'; } $infobox[] = $lm . '[/ul]'; break; } } // type (maybe expand uppon?) $_ = []; if ($_flags & QUEST_FLAG_DAILY) { $_[] = Lang::quest('daily'); } else { if ($_flags & QUEST_FLAG_WEEKLY) { $_[] = Lang::quest('weekly'); } else { if ($_specialFlags & QUEST_FLAG_SPECIAL_MONTHLY) { $_[] = Lang::quest('monthly'); } } } if ($t = $this->subject->getField('type')) { $_[] = Lang::quest('questInfo', $t); } if ($_) { $infobox[] = Lang::game('type') . Lang::main('colon') . implode(' ', $_); } // side $_ = Lang::main('side') . Lang::main('colon'); switch ($_side) { case 3: $infobox[] = $_ . Lang::game('si', 3); break; case 2: $infobox[] = $_ . '[span class=icon-horde]' . Lang::game('si', 2) . '[/span]'; break; case 1: $infobox[] = $_ . '[span class=icon-alliance]' . Lang::game('si', 1) . '[/span]'; break; } // races if ($_ = Lang::getRaceString($this->subject->getField('reqRaceMask'), $__, $jsg, $n, false)) { $this->extendGlobalIds(TYPE_RACE, $jsg); $t = $n == 1 ? Lang::game('race') : Lang::game('races'); $infobox[] = Util::ucFirst($t) . Lang::main('colon') . $_; } // classes if ($_ = Lang::getClassString($this->subject->getField('reqClassMask'), $jsg, $n, false)) { $this->extendGlobalIds(TYPE_CLASS, $jsg); $t = $n == 1 ? Lang::game('class') : Lang::game('classes'); $infobox[] = Util::ucFirst($t) . Lang::main('colon') . $_; } // profession / skill if ($_ = $this->subject->getField('reqSkillId')) { $this->extendGlobalIds(TYPE_SKILL, $_); $sk = '[skill=' . $_ . ']'; if ($_ = $this->subject->getField('reqSkillPoints')) { $sk .= ' (' . $_ . ')'; } $infobox[] = Lang::quest('profession') . Lang::main('colon') . $sk; } // timer if ($_ = $this->subject->getField('timeLimit')) { $infobox[] = Lang::quest('timer') . Lang::main('colon') . Util::formatTime($_ * 1000); } $startEnd = DB::Aowow()->select('SELECT * FROM ?_quests_startend WHERE questId = ?d', $this->typeId); // start $start = '[icon name=quest_start' . ($this->subject->isDaily() ? '_daily' : '') . ']' . Lang::event('start') . Lang::main('colon') . '[/icon]'; $s = []; foreach ($startEnd as $se) { if ($se['method'] & 0x1) { $this->extendGlobalIds($se['type'], $se['typeId']); $s[] = ($s ? '[span=invisible]' . $start . '[/span] ' : $start . ' ') . '[' . Util::$typeStrings[$se['type']] . '=' . $se['typeId'] . ']'; } } if ($s) { $infobox[] = implode('[br]', $s); } // end $end = '[icon name=quest_end' . ($this->subject->isDaily() ? '_daily' : '') . ']' . Lang::event('end') . Lang::main('colon') . '[/icon]'; $e = []; foreach ($startEnd as $se) { if ($se['method'] & 0x2) { $this->extendGlobalIds($se['type'], $se['typeId']); $e[] = ($e ? '[span=invisible]' . $end . '[/span] ' : $end . ' ') . '[' . Util::$typeStrings[$se['type']] . '=' . $se['typeId'] . ']'; } } if ($e) { $infobox[] = implode('[br]', $e); } // Repeatable if ($_flags & QUEST_FLAG_REPEATABLE || $_specialFlags & QUEST_FLAG_SPECIAL_REPEATABLE) { $infobox[] = Lang::quest('repeatable'); } // sharable | not sharable $infobox[] = $_flags & QUEST_FLAG_SHARABLE ? Lang::quest('sharable') : Lang::quest('notSharable'); // Keeps you PvP flagged if ($this->subject->isPvPEnabled()) { $infobox[] = Lang::quest('keepsPvpFlag'); } // difficulty (todo (low): formula unclear. seems to be [minLevel,] -4, -2, (level), +3, +(9 to 15)) if ($_level > 0) { $_ = []; // red if ($_minLevel && $_minLevel < $_level - 4) { $_[] = '[color=q10]' . $_minLevel . '[/color]'; } // orange if (!$_minLevel || $_minLevel < $_level - 2) { $_[] = '[color=r1]' . (!$_ && $_minLevel > $_level - 4 ? $_minLevel : $_level - 4) . '[/color]'; } // yellow $_[] = '[color=r2]' . (!$_ && $_minLevel > $_level - 2 ? $_minLevel : $_level - 2) . '[/color]'; // green $_[] = '[color=r3]' . ($_level + 3) . '[/color]'; // grey (is about +/-1 level off) $_[] = '[color=r4]' . ($_level + 3 + ceil(12 * $_level / MAX_LEVEL)) . '[/color]'; if ($_) { $infobox[] = Lang::game('difficulty') . Lang::main('colon') . implode('[small] [/small]', $_); } } $this->infobox = '[ul][li]' . implode('[/li][li]', $infobox) . '[/li][/ul]'; /**********/ /* Series */ /**********/ // Quest Chain (are there cases where quests go in parallel?) $chain = array(array(array('side' => $_side, 'typeStr' => Util::$typeStrings[TYPE_QUEST], 'typeId' => $this->typeId, 'name' => $this->name, '_next' => $this->subject->getField('nextQuestIdChain')))); $_ = $chain[0][0]; while ($_) { if ($_ = DB::Aowow()->selectRow('SELECT id AS typeId, name_loc0, name_loc2, name_loc3, name_loc6, name_loc8, reqRaceMask FROM ?_quests WHERE nextQuestIdChain = ?d', $_['typeId'])) { $n = Util::localizedString($_, 'name'); array_unshift($chain, array(array('side' => Util::sideByRaceMask($_['reqRaceMask']), 'typeStr' => Util::$typeStrings[TYPE_QUEST], 'typeId' => $_['typeId'], 'name' => strlen($n) > 40 ? substr($n, 0, 40) . '…' : $n))); } } $_ = end($chain)[0]; while ($_) { if ($_ = DB::Aowow()->selectRow('SELECT id AS typeId, name_loc0, name_loc2, name_loc3, name_loc6, name_loc8, reqRaceMask, nextQuestIdChain AS _next FROM ?_quests WHERE id = ?d', $_['_next'])) { $n = Util::localizedString($_, 'name'); array_push($chain, array(array('side' => Util::sideByRaceMask($_['reqRaceMask']), 'typeStr' => Util::$typeStrings[TYPE_QUEST], 'typeId' => $_['typeId'], 'name' => strlen($n) > 40 ? substr($n, 0, 40) . '…' : $n, '_next' => $_['_next']))); } } if (count($chain) > 1) { $this->series[] = [$chain, null]; } // todo (low): sensibly merge the following lists into 'series' $listGen = function ($cnd) { $chain = []; $list = new QuestList($cnd); if ($list->error) { return null; } foreach ($list->iterate() as $id => $__) { $n = $list->getField('name', true); $chain[] = array(array('side' => Util::sideByRaceMask($list->getField('reqRaceMask')), 'typeStr' => Util::$typeStrings[TYPE_QUEST], 'typeId' => $id, 'name' => strlen($n) > 40 ? substr($n, 0, 40) . '…' : $n)); } return $chain; }; $extraLists = array(['reqQ', array('OR', ['AND', ['nextQuestId', $this->typeId], ['exclusiveGroup', 0, '<']], ['AND', ['id', $this->subject->getField('prevQuestId')], ['nextQuestIdChain', $this->typeId, '!']])], ['reqOneQ', array(['exclusiveGroup', 0, '>'], ['nextQuestId', $this->typeId])], ['opensQ', array('OR', ['AND', ['prevQuestId', $this->typeId], ['id', $this->subject->getField('nextQuestIdChain'), '!']], ['id', $this->subject->getField('nextQuestId')])], ['closesQ', array(['exclusiveGroup', 0, '!'], ['exclusiveGroup', $this->subject->getField('exclusiveGroup')], ['id', $this->typeId, '!'])], ['enablesQ', array(['prevQuestId', -$this->typeId])], ['enabledByQ', array(['id', -$this->subject->getField('prevQuestId')])]); foreach ($extraLists as $el) { if ($_ = $listGen($el[1])) { $this->series[] = [$_, sprintf(Util::$dfnString, Lang::quest($el[0] . 'Desc'), Lang::quest($el[0]))]; } } /*******************/ /* Objectives List */ /*******************/ $this->objectiveList = []; $this->providedItem = []; // gather ids for lookup $olItems = $olNPCs = $olGOs = $olFactions = []; // items $olItems[0] = array($this->subject->getField('sourceItemId'), $this->subject->getField('sourceItemCount'), false); for ($i = 1; $i < 7; $i++) { $id = $this->subject->getField('reqItemId' . $i); $qty = $this->subject->getField('reqItemCount' . $i); if (!$id || !$qty) { continue; } $olItems[$i] = [$id, $qty, $id == $olItems[0][0]]; } if ($ids = array_column($olItems, 0)) { $olItemData = new ItemList(array(['id', $ids])); $this->extendGlobalData($olItemData->getJSGlobals(GLOBALINFO_SELF)); $providedRequired = false; foreach ($olItems as $i => list($itemId, $qty, $provided)) { if (!$i || !$itemId || !in_array($itemId, $olItemData->getFoundIDs())) { continue; } if ($provided) { $providedRequired = true; } $this->objectiveList[] = array('typeStr' => Util::$typeStrings[TYPE_ITEM], 'id' => $itemId, 'name' => $olItemData->json[$itemId]['name'], 'qty' => $qty > 1 ? $qty : 0, 'quality' => 7 - $olItemData->json[$itemId]['quality'], 'extraText' => $provided ? ' (' . Lang::quest('provided') . ')' : ''); } // if providd item is not required by quest, list it below other requirements if (!$providedRequired && $olItems[0][0] && in_array($olItems[0][0], $olItemData->getFoundIDs())) { $this->providedItem = array('id' => $olItems[0][0], 'name' => $olItemData->json[$olItems[0][0]]['name'], 'qty' => $olItems[0][1] > 1 ? $olItems[0][1] : 0, 'quality' => 7 - $olItemData->json[$olItems[0][0]]['quality']); } } // creature or GO... for ($i = 1; $i < 5; $i++) { $id = $this->subject->getField('reqNpcOrGo' . $i); $qty = $this->subject->getField('reqNpcOrGoCount' . $i); $altTxt = $this->subject->getField('objectiveText' . $i, true); if ($id > 0 && $qty) { $olNPCs[$id] = [$qty, $altTxt, []]; } else { if ($id < 0 && $qty) { $olGOs[-$id] = [$qty, $altTxt]; } } } // .. creature kills if ($ids = array_keys($olNPCs)) { $olNPCData = new CreatureList(array('OR', ['id', $ids], ['killCredit1', $ids], ['killCredit2', $ids])); $this->extendGlobalData($olNPCData->getJSGlobals(GLOBALINFO_SELF)); // create proxy-references foreach ($olNPCData->iterate() as $id => $__) { if ($p = $olNPCData->getField('KillCredit1')) { if (isset($olNPCs[$p])) { $olNPCs[$p][2][$id] = $olNPCData->getField('name', true); } } if ($p = $olNPCData->getField('KillCredit2')) { if (isset($olNPCs[$p])) { $olNPCs[$p][2][$id] = $olNPCData->getField('name', true); } } } foreach ($olNPCs as $i => $pair) { if (!$i || !in_array($i, $olNPCData->getFoundIDs())) { continue; } $ol = array('typeStr' => Util::$typeStrings[TYPE_NPC], 'id' => $i, 'name' => $pair[1] ?: Util::localizedString($olNPCData->getEntry($i), 'name'), 'qty' => $pair[0] > 1 ? $pair[0] : 0, 'extraText' => $_specialFlags & QUEST_FLAG_SPECIAL_SPELLCAST || $pair[1] ? '' : ' ' . Lang::achievement('slain'), 'proxy' => $pair[2]); if ($pair[2]) { // has proxies assigned, add yourself as another proxy $ol['proxy'][$i] = Util::localizedString($olNPCData->getEntry($i), 'name'); } $this->objectiveList[] = $ol; } } // .. GO interactions if ($ids = array_keys($olGOs)) { $olGOData = new GameObjectList(array(['id', $ids])); $this->extendGlobalData($olGOData->getJSGlobals(GLOBALINFO_SELF)); foreach ($olNPCs as $i => $pair) { if (!$i || !in_array($i, $olGOData->getFoundIDs())) { continue; } $this->objectiveList[] = array('typeStr' => Util::$typeStrings[TYPE_OBJECT], 'id' => $i, 'name' => $pair[1] ?: Util::localizedString($olGOData->getEntry($i), 'name'), 'qty' => $pair[0] > 1 ? $pair[0] : 0); } } // reputation required for ($i = 1; $i < 3; $i++) { $id = $this->subject->getField('reqFactionId' . $i); $val = $this->subject->getField('reqFactionValue' . $i); if (!$id) { continue; } $olFactions[$id] = $val; } if ($ids = array_keys($olFactions)) { $olFactionsData = new FactionList(array(['id', $ids])); $this->extendGlobalData($olFactionsData->getJSGlobals(GLOBALINFO_SELF)); foreach ($olFactions as $i => $val) { if (!$i || !in_array($i, $olFactionsData->getFoundIDs())) { continue; } $this->objectiveList[] = array('typeStr' => Util::$typeStrings[TYPE_FACTION], 'id' => $i, 'name' => Util::localizedString($olFactionsData->getEntry($i), 'name'), 'qty' => sprintf(Util::$dfnString, $val . ' ' . Lang::achievement('points'), Lang::getReputationLevelForPoints($val)), 'extraText' => ''); } } // granted spell if ($_ = $this->subject->getField('sourceSpellId')) { $this->extendGlobalIds(TYPE_SPELL, $_); $this->objectiveList[] = array('typeStr' => Util::$typeStrings[TYPE_SPELL], 'id' => $_, 'name' => SpellList::getName($_), 'qty' => 0, 'extraText' => ' (' . Lang::quest('provided') . ')'); } // required money if ($this->subject->getField('rewardOrReqMoney') < 0) { $this->objectiveList[] = ['text' => Lang::quest('reqMoney') . Lang::main('colon') . Util::formatMoney(abs($this->subject->getField('rewardOrReqMoney')))]; } // required pvp kills if ($_ = $this->subject->getField('reqPlayerKills')) { $this->objectiveList[] = ['text' => Lang::quest('playerSlain') . ' (' . $_ . ')']; } /**********/ /* Mapper */ /**********/ $this->addJS('?data=zones&locale=' . User::$localeId . '&t=' . $_SESSION['dataKey']); /* TODO (GODDAMNIT): jeez.. */ // $startend + reqNpcOrGo[1-4] $this->map = null; // array( // 'data' => ['zone' => $this->typeId], // 'som' => Util::toJSON($som) // ); /****************/ /* Main Content */ /****************/ $this->gains = $this->createGains(); $this->mail = $this->createMail($maTab, $startEnd); $this->rewards = $this->createRewards(); $this->objectives = $this->subject->parseText('objectives', false); $this->details = $this->subject->parseText('details', false); $this->offerReward = $this->subject->parseText('offerReward', false); $this->requestItems = $this->subject->parseText('requestItems', false); $this->completed = $this->subject->parseText('completed', false); $this->end = $this->subject->parseText('end', false); $this->suggestedPl = $this->subject->getField('suggestedPlayers'); $this->unavailable = $_flags & QUEST_FLAG_UNAVAILABLE || $this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW; $this->redButtons = array(BUTTON_LINKS => ['color' => 'ffffff00', 'linkId' => 'quest:' . $this->typeId . ':' . $_level . ''], BUTTON_WOWHEAD => true); if ($maTab) { $this->lvTabs[] = $maTab; } // factionchange-equivalent if ($pendant = DB::World()->selectCell('SELECT IF(horde_id = ?d, alliance_id, -horde_id) FROM player_factionchange_quests WHERE alliance_id = ?d OR horde_id = ?d', $this->typeId, $this->typeId, $this->typeId)) { $altQuest = new QuestList(array(['id', abs($pendant)])); if (!$altQuest->error) { $this->transfer = sprintf(Lang::quest('_transfer'), $altQuest->id, $altQuest->getField('name', true), $pendant > 0 ? 'alliance' : 'horde', $pendant > 0 ? Lang::game('si', 1) : Lang::game('si', 2)); } } /**************/ /* Extra Tabs */ /**************/ // tab: see also $seeAlso = new QuestList(array(['name_loc' . User::$localeId, '%' . $this->name . '%'], ['id', $this->typeId, '!'])); if (!$seeAlso->error) { $this->extendGlobalData($seeAlso->getJSGlobals()); $this->lvTabs[] = array('file' => 'quest', 'data' => $seeAlso->getListviewData(), 'params' => array('name' => '$LANG.tab_seealso', 'id' => 'see-also')); } // tab: criteria of $criteriaOf = new AchievementList(array(['ac.type', ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST], ['ac.value1', $this->typeId])); if (!$criteriaOf->error) { $this->extendGlobalData($criteriaOf->getJSGlobals()); $this->lvTabs[] = array('file' => 'achievement', 'data' => $criteriaOf->getListviewData(), 'params' => array('name' => '$LANG.tab_criteriaof', 'id' => 'criteria-of')); } // tab: conditions $cnd = []; if ($_ = $this->subject->getField('reqMinRepFaction')) { $cnd[CND_SRC_QUEST_ACCEPT][$this->typeId][0][] = [CND_REPUTATION_RANK, $_, 1 << Util::getReputationLevelForPoints($this->subject->getField('reqMinRepValue'))]; $this->extendGlobalIds(TYPE_FACTION, $_); } if ($_ = $this->subject->getField('reqMaxRepFaction')) { $cnd[CND_SRC_QUEST_ACCEPT][$this->typeId][0][] = [-CND_REPUTATION_RANK, $_, 1 << Util::getReputationLevelForPoints($this->subject->getField('reqMaxRepValue'))]; $this->extendGlobalIds(TYPE_FACTION, $_); } $_ = Util::getServerConditions([CND_SRC_QUEST_ACCEPT, CND_SRC_QUEST_SHOW_MARK], null, $this->typeId); if (!empty($_[0])) { // awkward merger if (isset($_[0][CND_SRC_QUEST_ACCEPT][$this->typeId][0])) { if (isset($cnd[CND_SRC_QUEST_ACCEPT][$this->typeId][0])) { $cnd[CND_SRC_QUEST_ACCEPT][$this->typeId][0] = array_merge($cnd[CND_SRC_QUEST_ACCEPT][$this->typeId][0], $_[0][CND_SRC_QUEST_ACCEPT][$this->typeId][0]); } else { $cnd[CND_SRC_QUEST_ACCEPT] = $_[0][CND_SRC_QUEST_ACCEPT]; } } if (isset($_[0][CND_SRC_QUEST_SHOW_MARK])) { $cnd[CND_SRC_QUEST_SHOW_MARK] = $_[0][CND_SRC_QUEST_SHOW_MARK]; } $this->extendGlobalData($_[1]); } if ($cnd) { $tab = "<script type=\"text/javascript\">\n" . "var markup = ConditionList.createTab(" . Util::toJSON($cnd) . ");\n" . "Markup.printHtml(markup, 'tab-conditions', { allow: Markup.CLASS_STAFF })" . "</script>"; $this->lvTabs[] = array('file' => null, 'data' => $tab, 'params' => array('id' => 'conditions', 'name' => '$LANG.requires')); } }
?> </td> <td class="padded"> <select name="si"> <option></option> <?php foreach (Lang::game('si') as $i => $str) { if ($str) { echo ' <option value="' . $i . '" ' . (isset($f['si']) && $f['si'] == $i ? 'selected' : null) . '>' . $str . "</option>\n"; } } ?> </select> </td> <td class="padded"><table><tr> <td> <?php echo Lang::achievement('points') . Lang::main('colon'); ?> </td> <td> <input type="text" name="minpt" maxlength="2" class="smalltextbox" <?php echo isset($f['minpt']) ? 'value="' . $f['minpt'] . '"' : null; ?> /> - <input type="text" name="maxpt" maxlength="2" class="smalltextbox" <?php echo isset($f['maxpt']) ? 'value="' . $f['maxpt'] . '"' : null; ?> /></td> </tr></table></td> </tr> </table> <div id="fi_criteria" class="padded criteria"><div></div></div><div><a href="javascript:;" id="fi_addcriteria" onclick="fi_addCriterion(this); return false"><?php echo Lang::main('addFilter');
public function notFound() { if ($this->mode != CACHE_TYPE_TOOLTIP) { return parent::notFound(Lang::game('achievement'), Lang::achievement('notFound')); } header('Content-type: application/x-javascript; charset=utf-8'); echo $this->generateTooltip(true); exit; }
protected function generateContent() { /***********/ /* Infobox */ /***********/ $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); // reqLevel if ($_ = $this->subject->getField('requiredLevel')) { $infobox[] = sprintf(Lang::game('reqLevel'), $_); } // reqskill if ($_ = $this->subject->getField('skillLine')) { $this->extendGlobalIds(TYPE_SKILL, $_); $foo = sprintf(Lang::game('requires'), ' [skill=' . $_ . ']'); if ($_ = $this->subject->getField('skillLevel')) { $foo .= ' (' . $_ . ')'; } $infobox[] = $foo; } /****************/ /* Main Content */ /****************/ $this->infobox = $infobox ? '[ul][li]' . implode('[/li][li]', $infobox) . '[/li][/ul]' : null; $this->effects = []; // 3 effects for ($i = 1; $i < 4; $i++) { $_ty = $this->subject->getField('type' . $i); $_qty = $this->subject->getField('amount' . $i); $_obj = $this->subject->getField('object' . $i); switch ($_ty) { case 1: case 3: case 7: $sArr = $this->subject->getField('spells')[$i]; $spl = $this->subject->getRelSpell($sArr[0]); $this->effects[$i]['name'] = User::isInGroup(U_GROUP_EMPLOYEE) ? sprintf(Util::$dfnString, 'Type: ' . $_ty, Lang::item('trigger', $sArr[1])) : Lang::item('trigger', $sArr[1]); $this->effects[$i]['proc'] = $sArr[3]; $this->effects[$i]['value'] = $_qty ?: null; $this->effects[$i]['icon'] = array('name' => !$spl ? Util::ucFirst(Lang::game('spell')) . ' #' . $sArr[0] : Util::localizedString($spl, 'name'), 'id' => $sArr[0], 'count' => $sArr[2]); break; case 5: if ($_obj < 2) { // [mana, health] are on [0, 1] respectively and are expected on [1, 2] .. $_obj++; } // 0 is weaponDmg .. ehh .. i messed up somewhere $this->effects[$i]['tip'] = [$_obj, Util::$itemMods[$_obj]]; // DO NOT BREAK! // DO NOT BREAK! case 2: case 6: case 8: case 4: $this->effects[$i]['name'] = User::isInGroup(U_GROUP_EMPLOYEE) ? sprintf(Util::$dfnString, 'Type: ' . $_ty, Lang::enchantment('types', $_ty)) : Lang::enchantment('types', $_ty); $this->effects[$i]['value'] = $_qty; if ($_ty == 4) { $this->effects[$i]['name'] .= Lang::main('colon') . '(' . (User::isInGroup(U_GROUP_EMPLOYEE) ? sprintf(Util::$dfnString, 'Object: ' . $_obj, Lang::getMagicSchools(1 << $_obj)) : Lang::getMagicSchools(1 << $_obj)) . ')'; } } } // activation conditions if ($_ = $this->subject->getField('conditionId')) { $x = ''; if ($gemCnd = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantmentcondition WHERE id = ?d', $_)) { for ($i = 1; $i < 6; $i++) { if (!$gemCnd['color' . $i]) { continue; } $fiColors = function ($idx) { $foo = ''; switch ($idx) { case 2: $foo = '0:3:5'; break; // red // red case 3: $foo = '2:4:5'; break; // yellow // yellow case 4: $foo = '1:3:4'; break; // blue } return $foo; }; $bLink = $gemCnd['color' . $i] ? '<a href="?items=3&filter=ty=' . $fiColors($gemCnd['color' . $i]) . '">' . Lang::item('gemColors', $gemCnd['color' . $i] - 1) . '</a>' : ''; $cLink = $gemCnd['cmpColor' . $i] ? '<a href="?items=3&filter=ty=' . $fiColors($gemCnd['cmpColor' . $i]) . '">' . Lang::item('gemColors', $gemCnd['cmpColor' . $i] - 1) . '</a>' : ''; switch ($gemCnd['comparator' . $i]) { case 2: // requires less <color> than (<value> || <comparecolor>) gems // requires less <color> than (<value> || <comparecolor>) gems case 5: // requires at least <color> than (<value> || <comparecolor>) gems $sp = (int) $gemCnd['value' . $i] > 1; $x .= '<span class="q0">' . Lang::achievement('reqNumCrt') . ' ' . sprintf(Lang::item('gemConditions', $gemCnd['comparator' . $i], $sp), $gemCnd['value' . $i], $bLink) . '</span><br />'; break; case 3: // requires more <color> than (<value> || <comparecolor>) gems $link = '<a href="?items=3&filter=ty=' . $fiColors($gemCnd['cmpColor' . $i]) . '">' . Lang::item('gemColors', $gemCnd['cmpColor' . $i] - 1) . '</a>'; $x .= '<span class="q0">' . Lang::achievement('reqNumCrt') . ' ' . sprintf(Lang::item('gemConditions', 3), $bLink, $cLink) . '</span><br />'; break; } } } $this->activateCondition = $x; } /**************/ /* Extra Tabs */ /**************/ // used by gem $gemList = new ItemList(array(['gemEnchantmentId', $this->typeId])); if (!$gemList->error) { $this->lvTabs[] = ['item', array('data' => array_values($gemList->getListviewData()), 'name' => '$LANG.tab_usedby + \' \' + LANG.gems', 'id' => 'used-by-gem')]; $this->extendGlobalData($gemList->getJsGlobals()); } // used by socket bonus $socketsList = new ItemList(array(['socketBonus', $this->typeId])); if (!$socketsList->error) { $this->lvTabs[] = ['item', array('data' => array_values($socketsList->getListviewData()), 'name' => '$LANG.tab_usedby + \' \' + \'' . Lang::item('socketBonus') . '\'', 'id' => 'used-by-socketbonus')]; $this->extendGlobalData($socketsList->getJsGlobals()); } // used by spell // used by useItem $cnd = array('OR', ['AND', ['effect1Id', [53, 54, 156, 92]], ['effect1MiscValue', $this->typeId]], ['AND', ['effect2Id', [53, 54, 156, 92]], ['effect2MiscValue', $this->typeId]], ['AND', ['effect3Id', [53, 54, 156, 92]], ['effect3MiscValue', $this->typeId]]); $spellList = new SpellList($cnd); if (!$spellList->error) { $spellData = $spellList->getListviewData(); $this->extendGlobalData($spellList->getJsGlobals()); $spellIds = $spellList->getFoundIDs(); $conditions = array('OR', ['AND', ['spellTrigger1', [0, 5]], ['spellId1', $spellIds]], ['AND', ['spellTrigger2', [0, 5]], ['spellId2', $spellIds]], ['AND', ['spellTrigger3', [0, 5]], ['spellId3', $spellIds]], ['AND', ['spellTrigger4', [0, 5]], ['spellId4', $spellIds]], ['AND', ['spellTrigger5', [0, 5]], ['spellId5', $spellIds]]); $ubItems = new ItemList($conditions); if (!$ubItems->error) { $this->lvTabs[] = ['item', array('data' => array_values($ubItems->getListviewData()), 'name' => '$LANG.tab_usedby + \' \' + LANG.types[3][0]', 'id' => 'used-by-item')]; $this->extendGlobalData($ubItems->getJSGlobals(GLOBALINFO_SELF)); } // remove found spells if they are used by an item if (!$ubItems->error) { foreach ($spellList->iterate() as $sId => $__) { // if Perm. Enchantment has a createItem its a Scroll of Enchantment (display both) for ($i = 1; $i < 4; $i++) { if ($spellList->getField('effect' . $i . 'Id') == 53 && $spellList->getField('effect' . $i . 'CreateItemId')) { continue 2; } } foreach ($ubItems->iterate() as $__) { for ($i = 1; $i < 6; $i++) { if ($ubItems->getField('spellId' . $i) == $sId) { unset($spellData[$sId]); break 2; } } } } } $this->lvTabs[] = ['spell', array('data' => array_values($spellData), 'name' => '$LANG.tab_usedby + \' \' + LANG.types[6][0]', 'id' => 'used-by-spell')]; } // used by randomAttrItem $ire = DB::Aowow()->select('SELECT *, ABS(id) AS ARRAY_KEY FROM ?_itemrandomenchant WHERE enchantId1 = ?d OR enchantId2 = ?d OR enchantId3 = ?d OR enchantId4 = ?d OR enchantId5 = ?d', $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId); if ($ire) { if ($iet = DB::World()->select('SELECT entry AS ARRAY_KEY, ench, chance FROM item_enchantment_template WHERE ench IN (?a)', array_keys($ire))) { $randIds = []; // transform back to signed format foreach ($iet as $tplId => $data) { $randIds[$ire[$data['ench']]['id'] > 0 ? $tplId : -$tplId] = $ire[$data['ench']]['id']; } $randItems = new ItemList(array(CFG_SQL_LIMIT_NONE, ['randomEnchant', array_keys($randIds)])); if (!$randItems->error) { $data = $randItems->getListviewData(); foreach ($randItems->iterate() as $iId => $__) { $re = $randItems->getField('randomEnchant'); $data[$iId]['percent'] = $iet[abs($re)]['chance']; $data[$iId]['count'] = 1; // expected by js or the pct-col becomes unsortable $data[$iId]['rel'] = 'rand=' . $ire[$iet[abs($re)]['ench']]['id']; $data[$iId]['name'] .= ' ' . Util::localizedString($ire[$iet[abs($re)]['ench']], 'name'); } $this->lvTabs[] = ['item', array('data' => array_values($data), 'id' => 'used-by-rand', 'name' => '$LANG.tab_usedby + \' \' + \'' . Lang::item('_rndEnchants') . '\'', 'extraCols' => ['$Listview.extraCols.percent'])]; $this->extendGlobalData($randItems->getJSGlobals(GLOBALINFO_SELF)); } } } }
public function renderTooltip() { $criteria = $this->getCriteria(); $tmp = []; $rows = []; $i = 0; foreach ($criteria as $_row) { if ($i++ % 2) { $tmp[] = $_row; } else { $rows[] = $_row; } } if ($tmp) { $rows = array_merge($rows, $tmp); } $description = $this->getField('description', true); $name = $this->getField('name', true); $criteria = ''; $i = 0; foreach ($rows as $crt) { $obj = (int) $crt['value1']; $qty = (int) $crt['value2']; // we could show them, but the tooltips are cluttered if ($crt['completionFlags'] & ACHIEVEMENT_CRITERIA_FLAG_HIDDEN && User::$perms <= 0) { continue; } $crtName = Util::localizedString($crt, 'name'); switch ($crt['type']) { // link to title - todo (low): crosslink case ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE: $crtName = Util::ucFirst(Lang::game('title')) . Lang::main('colon') . $crtName; break; // link to quest // link to quest case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: if (!$crtName) { $crtName = QuestList::getName($obj); } break; // link to spell (/w icon) // link to spell (/w icon) case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET: case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2: case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL: case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: if (!$crtName) { $crtName = SpellList::getName($obj); } break; // link to item (/w icon) // link to item (/w icon) case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: if (!$crtName) { $crtName = ItemList::getName($obj); } break; // link to faction (/w target reputation) // link to faction (/w target reputation) case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION: if (!$crtName) { $crtName = FactionList::getName($obj); } break; } if ($crt['completionFlags'] & ACHIEVEMENT_CRITERIA_FLAG_MONEY_COUNTER) { $criteria .= '- ' . Util::jsEscape($crtName) . ' <span class="moneygold">' . number_format($crt['value2'] / 10000) . '</span><br />'; } else { $criteria .= '- ' . Util::jsEscape($crtName) . '<br />'; } if (++$i == round(count($rows) / 2)) { $criteria .= '</small></td><th class="q0" style="white-space: nowrap; text-align: left"><small>'; } } $x = '<table><tr><td><b class="q">'; $x .= Util::jsEscape($name); $x .= '</b></td></tr></table>'; if ($description || $criteria) { $x .= '<table><tr><td>'; } if ($description) { $x .= '<br />' . Util::jsEscape($description) . '<br />'; } if ($criteria) { $x .= '<br /><span class="q">' . Lang::achievement('criteria') . ':</span>'; $x .= '<table width="100%"><tr><td class="q0" style="white-space: nowrap"><small>' . $criteria . '</small></th></tr></table>'; } if ($description || $criteria) { $x .= '</td></tr></table>'; } return $x; }
echo '<tr><th' . (isset($cr['icon']) ? ' align="right" id="iconlist-icon' . $cr['icon'] . '"' : null) . '>'; if (!isset($cr['icon'])) { echo '<ul><li><var> </var></li></ul>'; } echo '</th><td>'; if (!empty($cr['link'])) { echo '<a href="' . $cr['link']['href'] . '"' . (isset($cr['link']['quality']) ? ' class="q' . $cr['link']['quality'] . '"' : null) . '>' . Util::htmlEscape($cr['link']['text']) . '</a>'; } if (!empty($cr['link']['count']) && $cr['link']['count'] > 1) { echo ' (' . $cr['link']['count'] . ')'; } if (isset($cr['extraText'])) { echo ' ' . $cr['extraText']; } if (User::isInGroup(U_GROUP_STAFF)) { echo ' <small title="' . Lang::achievement('criteriaType') . ' ' . $cr['type'] . '" class="q0">[' . $cr['id'] . ']</small>'; } echo '</td></tr>'; // every odd number of elements if ($i + 1 == round(count($this->criteria['data']) / 2)) { echo '</table></div><div style="float: left"><table class="iconlist">'; } } ?> </table> </div> <script type="text/javascript">//<![CDATA[ <?php foreach ($this->criteria['icons'] as $k => $ic) { echo ' $WH.ge(\'iconlist-icon' . $ic['itr'] . '\').appendChild(' . $ic['type'] . '.createIcon(' . $ic['id'] . ', 0, ' . (!empty($ic['count']) ? $ic['count'] : 0) . "));\n";
$this->brick('infobox'); ?> <div class="text"> <?php $this->brick('headIcons'); $this->brick('redButtons'); ?> <h1><?php echo $this->name; ?> </h1> <?php echo $this->description; echo '<h3>' . Lang::achievement('criteria') . ($this->criteria['reqQty'] ? ' – <small><b>' . Lang::achievement('reqNumCrt') . ' ' . $this->criteria['reqQty'] . ' ' . Lang::achievement('outOf') . ' ' . count($this->criteria['data']) . '</b></small>' : null) . "</h3>\n"; ?> <div style="float: left; margin-right: 25px"> <table class="iconlist"> <?php foreach ($this->criteria['data'] as $i => $cr) { echo '<tr><th' . (isset($cr['icon']) ? ' align="right" id="iconlist-icon' . $cr['icon'] . '"' : null) . '>'; if (!isset($cr['icon'])) { echo '<ul><li><var> </var></li></ul>'; } echo '</th><td><span class="tip" title="ID' . Lang::main('colon') . $cr['id'] . '">'; if (!empty($cr['link'])) { echo '<a href="' . $cr['link']['href'] . '"' . (isset($cr['link']['quality']) ? ' class="q' . $cr['link']['quality'] . '"' : null) . '>' . Util::htmlEscape($cr['link']['text']) . '</a>'; }