protected function generateContent() { $this->addJS('?data=zones&locale=' . User::$localeId . '&t=' . $_SESSION['dataKey']); $_cat = $this->subject->getField('typeCat'); $redButtons = array(BUTTON_LINKS => ['color' => 'ff71d5ff', 'linkId' => Util::$typeStrings[TYPE_SPELL] . ':' . $this->typeId], BUTTON_VIEW3D => false, BUTTON_WOWHEAD => true); /***********/ /* Infobox */ /***********/ $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); // level if (!in_array($_cat, [-5, -6])) { if ($_ = $this->subject->getField('talentLevel')) { $infobox[] = in_array($_cat, [-2, 7, -13]) ? sprintf(Lang::game('reqLevel'), $_) : Lang::game('level') . Lang::main('colon') . $_; } else { if ($_ = $this->subject->getField('spellLevel')) { $infobox[] = in_array($_cat, [-2, 7, -13]) ? sprintf(Lang::game('reqLevel'), $_) : Lang::game('level') . Lang::main('colon') . $_; } } } // races if ($_ = Lang::getRaceString($this->subject->getField('reqRaceMask'), $__, $jsg, $n, false)) { if ($_ != Lang::game('ra', 0)) { $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') . $_; } // spell focus if ($_ = $this->subject->getField('spellFocusObject')) { $bar = DB::Aowow()->selectRow('SELECT * FROM ?_spellfocusobject WHERE id = ?d', $_); $focus = new GameObjectList(array(['spellFocusId', $_], 1)); $infobox[] = Lang::game('requires2') . ' ' . ($focus->error ? Util::localizedString($bar, 'name') : '[url=?object=' . $focus->id . ']' . Util::localizedString($bar, 'name') . '[/url]'); } // primary & secondary trades if (in_array($_cat, [9, 11])) { // skill if ($_ = $this->subject->getField('skillLines')[0]) { $rSkill = new SkillList(array(['id', $_])); if (!$rSkill->error) { $this->extendGlobalData($rSkill->getJSGlobals()); $bar = sprintf(Lang::game('requires'), ' [skill=' . $rSkill->id . ']'); if ($_ = $this->subject->getField('learnedAt')) { $bar .= ' (' . $_ . ')'; } $infobox[] = $bar; } } // specialization if ($_ = $this->subject->getField('reqSpellId')) { $rSpell = new SpellList(array(['id', $_])); if (!$rSpell->error) { $this->extendGlobalData($rSpell->getJSGlobals()); $infobox[] = Lang::game('requires2') . ' [spell=' . $rSpell->id . '][/li]'; } } // difficulty if ($_ = $this->subject->getColorsForCurrent()) { $bar = []; for ($i = 0; $i < 4; $i++) { if ($_[$i]) { $bar[] = '[color=r' . ($i + 1) . ']' . $_[$i] . '[/color]'; } } $infobox[] = Lang::game('difficulty') . Lang::main('colon') . implode(' ', $bar); } } // accquisition.. 10: starter spell; 7: discovery if (isset($this->subject->sources[$this->subject->id][10])) { $infobox[] = Lang::spell('starter'); } else { if (isset($this->subject->sources[$this->subject->id][7])) { $infobox[] = Lang::spell('discovered'); } } // training cost if ($cost = $this->subject->getField('trainingCost')) { $infobox[] = Lang::spell('trainingCost') . Lang::main('colon') . '[money=' . $cost . '][/li]'; } // used in mode foreach ($this->difficulties as $n => $id) { if ($id == $this->typeId) { // "Mode" seems to be multilingual acceptable $infobox[] = 'Mode' . Lang::main('colon') . Lang::game('modes', $n); } } $effects = $this->createEffects($infobox, $redButtons); // spell script if (User::isInGroup(U_GROUP_STAFF)) { if ($_ = DB::World()->selectCell('SELECT ScriptName FROM spell_script_names WHERE ABS(spell_id) = ?d', $this->firstRank)) { $infobox[] = 'Script' . Lang::main('colon') . $_; } } $infobox = $infobox ? '[ul][li]' . implode('[/li][li]', $infobox) . '[/li][/ul]' : ''; // append glyph symbol if available $glyphId = 0; for ($i = 1; $i < 4; $i++) { if ($this->subject->getField('effect' . $i . 'Id') == 74) { $glyphId = $this->subject->getField('effect' . $i . 'MiscValue'); } } if ($_ = DB::Aowow()->selectCell('SELECT si.iconString FROM ?_glyphproperties gp JOIN ?_icons si ON gp.iconId = si.id WHERE gp.spellId = ?d { OR gp.id = ?d }', $this->typeId, $glyphId ?: DBSIMPLE_SKIP)) { if (file_exists('static/images/wow/Interface/Spellbook/' . $_ . '.png')) { $infobox .= '[img src=' . STATIC_URL . '/images/wow/Interface/Spellbook/' . $_ . '.png border=0 float=center margin=15]'; } } /****************/ /* Main Content */ /****************/ $this->reagents = $this->createReagentList(); $this->scaling = $this->createScalingData(); $this->items = $this->createRequiredItems(); $this->tools = $this->createTools(); $this->effects = $effects; $this->infobox = $infobox; $this->powerCost = $this->subject->createPowerCostForCurrent(); $this->castTime = $this->subject->createCastTimeForCurrent(false, false); $this->name = $this->subject->getField('name', true); $this->headIcons = [$this->subject->getField('iconString'), $this->subject->getField('stackAmount')]; $this->level = $this->subject->getField('spellLevel'); $this->rangeName = $this->subject->getField('rangeText', true); $this->range = $this->subject->getField('rangeMaxHostile'); $this->gcd = Util::formatTime($this->subject->getField('startRecoveryTime')); $this->gcdCat = null; // todo (low): nyi; find out how this works [n/a; normal; ..] $this->school = [Util::asHex($this->subject->getField('schoolMask')), Lang::getMagicSchools($this->subject->getField('schoolMask'))]; $this->dispel = $this->subject->getField('dispelType') ? Lang::game('dt', $this->subject->getField('dispelType')) : null; $this->mechanic = $this->subject->getField('mechanic') ? Lang::game('me', $this->subject->getField('mechanic')) : null; $this->unavailable = $this->subject->getField('cuFlags') & CUSTOM_UNAVAILABLE; $this->redButtons = $redButtons; // minRange exists.. prepend if ($_ = $this->subject->getField('rangeMinHostile')) { $this->range = $_ . ' - ' . $this->range; } if ($this->subject->getField('attributes2') & 0x80000) { $this->stances = Lang::getStances($this->subject->getField('stanceMask')); } if (($_ = $this->subject->getField('recoveryTime')) && $_ > 0) { $this->cooldown = Util::formatTime($_); } if (($_ = $this->subject->getField('duration')) && $_ > 0) { $this->duration = Util::formatTime($_); } // factionchange-equivalent if ($pendant = DB::World()->selectCell('SELECT IF(horde_id = ?d, alliance_id, -horde_id) FROM player_factionchange_spells WHERE alliance_id = ?d OR horde_id = ?d', $this->typeId, $this->typeId, $this->typeId)) { $altSpell = new SpellList(array(['id', abs($pendant)])); if (!$altSpell->error) { $this->transfer = sprintf(Lang::spell('_transfer'), $altSpell->id, 1, $altSpell->getField('iconString'), $altSpell->getField('name', true), $pendant > 0 ? 'alliance' : 'horde', $pendant > 0 ? Lang::game('si', 1) : Lang::game('si', 2)); } } /**************/ /* Extra Tabs */ /**************/ $j = [null, 'A', 'B', 'C']; // tab: abilities [of shapeshift form] for ($i = 1; $i < 4; $i++) { if ($this->subject->getField('effect' . $i . 'AuraId') != 36) { continue; } $formSpells = DB::Aowow()->selectRow('SELECT spellId1, spellId2, spellId3, spellId4, spellId5, spellId6, spellId7, spellId8 FROM ?_shapeshiftforms WHERE id = ?d', $this->subject->getField('effect' . $i . 'MiscValue')); if (!$formSpells) { continue; } $abilities = new SpellList(array(['id', $formSpells])); if (!$abilities->error) { if (!$abilities->hasSetFields(['skillLines'])) { $abH = "\$['skill']"; } $this->lvTabs[] = array('file' => 'spell', 'data' => $abilities->getListviewData(), 'params' => array('id' => 'controlledabilities', 'name' => '$LANG.tab_controlledabilities', 'visibleCols' => "\$['level']", 'hiddenCols' => isset($abH) ? $abH : null)); $this->extendGlobalData($abilities->getJSGlobals(GLOBALINFO_SELF)); } } // tab: modifies $this $sub = ['OR']; $conditions = [['s.typeCat', [0, -9, -8], '!'], ['s.spellFamilyId', $this->subject->getField('spellFamilyId')], &$sub]; for ($i = 1; $i < 4; $i++) { // Flat Mods (107), Pct Mods (108), No Reagent Use (256) .. include dummy..? (4) if (!in_array($this->subject->getField('effect' . $i . 'AuraId'), [107, 108, 256, 286])) { continue; } $m1 = $this->subject->getField('effect1SpellClassMask' . $j[$i]); $m2 = $this->subject->getField('effect2SpellClassMask' . $j[$i]); $m3 = $this->subject->getField('effect3SpellClassMask' . $j[$i]); if (!$m1 && !$m2 && !$m3) { continue; } $sub[] = ['s.spellFamilyFlags1', $m1, '&']; $sub[] = ['s.spellFamilyFlags2', $m2, '&']; $sub[] = ['s.spellFamilyFlags3', $m3, '&']; } if (count($sub) > 1) { $modSpells = new SpellList($conditions); if (!$modSpells->error) { if (!$modSpells->hasSetFields(['skillLines'])) { $msH = "\$['skill']"; } $this->lvTabs[] = array('file' => 'spell', 'data' => $modSpells->getListviewData(), 'params' => array('id' => 'modifies', 'name' => '$LANG.tab_modifies', 'visibleCols' => "\$['level']", 'hiddenCols' => isset($msH) ? $msH : null)); $this->extendGlobalData($modSpells->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); } } // tab: modified by $this $sub = ['OR']; $conditions = [['s.spellFamilyId', $this->subject->getField('spellFamilyId')], &$sub]; for ($i = 1; $i < 4; $i++) { $m1 = $this->subject->getField('spellFamilyFlags1'); $m2 = $this->subject->getField('spellFamilyFlags2'); $m3 = $this->subject->getField('spellFamilyFlags3'); if (!$m1 && !$m2 && !$m3) { continue; } $sub[] = array('AND', ['s.effect' . $i . 'AuraId', [107, 108, 256, 286]], ['OR', ['s.effect1SpellClassMask' . $j[$i], $m1, '&'], ['s.effect2SpellClassMask' . $j[$i], $m2, '&'], ['s.effect3SpellClassMask' . $j[$i], $m3, '&']]); } if (count($sub) > 1) { $modsSpell = new SpellList($conditions); if (!$modsSpell->error) { if (!$modsSpell->hasSetFields(['skillLines'])) { $mbH = "\$['skill']"; } $this->lvTabs[] = array('file' => 'spell', 'data' => $modsSpell->getListviewData(), 'params' => array('id' => 'modified-by', 'name' => '$LANG.tab_modifiedby', 'visibleCols' => "\$['level']", 'hiddenCols' => isset($mbH) ? $mbH : null)); $this->extendGlobalData($modsSpell->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); } } // tab: see also $conditions = array(['s.schoolMask', $this->subject->getField('schoolMask')], ['s.effect1Id', $this->subject->getField('effect1Id')], ['s.effect2Id', $this->subject->getField('effect2Id')], ['s.effect3Id', $this->subject->getField('effect3Id')], ['s.id', $this->subject->id, '!'], ['s.name_loc' . User::$localeId, $this->subject->getField('name', true)]); $saSpells = new SpellList($conditions); if (!$saSpells->error) { $data = $saSpells->getListviewData(); if ($this->difficulties) { $saE = '$[Listview.extraCols.mode]'; foreach ($data as $id => &$d) { $d['modes'] = ['mode' => 0]; if ($this->difficulties[0] == $id) { if (!$this->difficulties[2] && !$this->difficulties[3]) { $d['modes']['mode'] |= 0x2; } else { $d['modes']['mode'] |= 0x8; } } if ($this->difficulties[1] == $id) { if (!$this->difficulties[2] && !$this->difficulties[3]) { $d['modes']['mode'] |= 0x1; } else { $d['modes']['mode'] |= 0x10; } } if ($this->difficulties[2] == $id) { // b0100000 $d['modes']['mode'] |= 0x20; } if ($this->difficulties[3] == $id) { // b1000000 $d['modes']['mode'] |= 0x40; } } } if (!$saSpells->hasSetFields(['skillLines'])) { $saH = "\$['skill']"; } $this->lvTabs[] = array('file' => 'spell', 'data' => $data, 'params' => array('id' => 'see-also', 'name' => '$LANG.tab_seealso', 'visibleCols' => "\$['level']", 'extraCols' => isset($saE) ? $saE : null, 'hiddenCols' => isset($saH) ? $saH : null)); $this->extendGlobalData($saSpells->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); } // tab: used by - itemset $conditions = array('OR', ['spell1', $this->subject->id], ['spell2', $this->subject->id], ['spell3', $this->subject->id], ['spell4', $this->subject->id], ['spell5', $this->subject->id], ['spell6', $this->subject->id], ['spell7', $this->subject->id], ['spell8', $this->subject->id]); $ubSets = new ItemsetList($conditions); if (!$ubSets->error) { $this->lvTabs[] = array('file' => 'itemset', 'data' => $ubSets->getListviewData(), 'params' => array('id' => 'used-by-itemset', 'name' => '$LANG.tab_usedby')); $this->extendGlobalData($ubSets->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); } // tab: used by - item $conditions = array('OR', ['AND', ['spellTrigger1', 6, '!'], ['spellId1', $this->subject->id]], ['AND', ['spellTrigger2', 6, '!'], ['spellId2', $this->subject->id]], ['AND', ['spellTrigger3', 6, '!'], ['spellId3', $this->subject->id]], ['AND', ['spellTrigger4', 6, '!'], ['spellId4', $this->subject->id]], ['AND', ['spellTrigger5', 6, '!'], ['spellId5', $this->subject->id]]); $ubItems = new ItemList($conditions); if (!$ubItems->error) { $this->lvTabs[] = array('file' => 'item', 'data' => $ubItems->getListviewData(), 'params' => array('id' => 'used-by-item', 'name' => '$LANG.tab_usedby')); $this->extendGlobalData($ubItems->getJSGlobals(GLOBALINFO_SELF)); } // tab: used by - object $conditions = array('OR', ['onUseSpell', $this->subject->id], ['onSuccessSpell', $this->subject->id], ['auraSpell', $this->subject->id], ['triggeredSpell', $this->subject->id]); $ubObjects = new GameObjectList($conditions); if (!$ubObjects->error) { $this->lvTabs[] = array('file' => 'object', 'data' => $ubObjects->getListviewData(), 'params' => array('id' => 'used-by-object', 'name' => '$LANG.tab_usedby')); $this->extendGlobalData($ubObjects->getJSGlobals()); } // tab: criteria of $conditions = array(['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL]], ['ac.value1', $this->typeId]); $coAchievemnts = new AchievementList($conditions); if (!$coAchievemnts->error) { $this->lvTabs[] = array('file' => 'achievement', 'data' => $coAchievemnts->getListviewData(), 'params' => array('id' => 'criteria-of', 'name' => '$LANG.tab_criteriaof')); $this->extendGlobalData($coAchievemnts->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); } // tab: contains // spell_loot_template & skill_extra_item_template $extraItem = DB::World()->selectRow('SELECT * FROM skill_extra_item_template WHERE spellid = ?d', $this->subject->id); $spellLoot = new Loot(); if ($spellLoot->getByContainer(LOOT_SPELL, $this->subject->id) || $extraItem) { $this->extendGlobalData($spellLoot->jsGlobals); $lv = $spellLoot->getResult(); $extraCols = $spellLoot->extraCols; $extraCols[] = 'Listview.extraCols.percent'; if ($extraItem && $this->subject->canCreateItem()) { $foo = $this->subject->relItems->getListviewData(); for ($i = 1; $i < 4; $i++) { if (($bar = $this->subject->getField('effect' . $i . 'CreateItemId')) && isset($foo[$bar])) { $lv[$bar] = $foo[$bar]; $lv[$bar]['percent'] = $extraItem['additionalCreateChance']; $lv[$bar]['condition'][0][$this->typeId][] = [[CND_SPELL, $extraItem['requiredSpecialization']]]; $this->extendGlobalIds(TYPE_SPELL, $extraItem['requiredSpecialization']); $extraCols[] = 'Listview.extraCols.condition'; if ($max = $extraItem['additionalMaxNum']) { $lv[$bar]['mincount'] = 1; $lv[$bar]['maxcount'] = $max; } break; // skill_extra_item_template can only contain 1 item } } } $this->lvTabs[] = array('file' => 'item', 'data' => $lv, 'params' => array('name' => '$LANG.tab_contains', 'id' => 'contains', 'hiddenCols' => "\$['side', 'slot', 'source', 'reqlevel']", 'extraCols' => '$[' . implode(', ', $extraCols) . ']')); } // tab: exclusive with if ($this->firstRank) { $linkedSpells = DB::World()->selectCol('SELECT IF(sg2.spell_id < 0, sg2.id, sg2.spell_id) AS ARRAY_KEY, IF(sg2.spell_id < 0, sg2.spell_id, sr.stack_rule) FROM spell_group sg1 JOIN spell_group sg2 ON (sg1.id = sg2.id OR sg1.id = -sg2.spell_id) AND sg1.spell_id != sg2.spell_id LEFT JOIN spell_group_stack_rules sr ON sg1.id = sr.group_id WHERE sg1.spell_id = ?d', $this->firstRank); if ($linkedSpells) { $extraSpells = []; foreach ($linkedSpells as $k => $v) { if ($v > 0) { continue; } $extraSpells += DB::World()->selectCol('SELECT sg2.spell_id AS ARRAY_KEY, sr.stack_rule FROM spell_group sg1 JOIN spell_group sg2 ON sg2.id = -sg1.spell_id AND sg2.spell_id != ?d LEFT JOIN spell_group_stack_rules sr ON sg1.id = sr.group_id WHERE sg1.id = ?d', $this->firstRank, $k); unset($linkedSpells[$k]); } $groups = $linkedSpells + $extraSpells; $stacks = new SpellList(array(['s.id', array_keys($groups)])); if (!$stacks->error) { $data = $stacks->getListviewData(); foreach ($data as $k => $d) { $data[$k]['stackRule'] = $groups[$k]; } if (!$stacks->hasSetFields(['skillLines'])) { $sH = "\$['skill']"; } $this->lvTabs[] = array('file' => 'spell', 'data' => $data, 'params' => array('id' => 'spell-group-stack', 'name' => 'Stack Group', 'visibleCols' => "\$['stackRules']", 'hiddenCols' => isset($sH) ? $sH : null)); $this->extendGlobalData($stacks->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); } } } // tab: linked with $rows = DB::World()->select(' SELECT spell_trigger AS `trigger`, spell_effect AS effect, type, IF(ABS(spell_effect) = ?d, ABS(spell_trigger), ABS(spell_effect)) AS related FROM spell_linked_spell WHERE ABS(spell_effect) = ?d OR ABS(spell_trigger) = ?d', $this->typeId, $this->typeId, $this->typeId); $related = []; foreach ($rows as $row) { $related[] = $row['related']; } if ($related) { $linked = new SpellList(array(['s.id', $related])); } if (isset($linked) && !$linked->error) { $lv = $linked->getListviewData(); $data = []; foreach ($rows as $r) { foreach ($lv as $dk => $d) { if ($r['related'] != $dk) { continue; } $lv[$dk]['linked'] = [$r['trigger'], $r['effect'], $r['type']]; $data[] = $lv[$dk]; break; } } $this->lvTabs[] = array('file' => 'spell', 'data' => $data, 'params' => array('id' => 'spell-link', 'name' => 'Linked with', 'hiddenCols' => "\$['skill', 'name']", 'visibleCols' => "\$['linkedTrigger', 'linkedEffect']")); $this->extendGlobalData($linked->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); } // tab: triggered by $conditions = array('OR', ['AND', ['OR', ['effect1Id', SpellList::$effects['trigger']], ['effect1AuraId', SpellList::$auras['trigger']]], ['effect1TriggerSpell', $this->subject->id]], ['AND', ['OR', ['effect2Id', SpellList::$effects['trigger']], ['effect2AuraId', SpellList::$auras['trigger']]], ['effect2TriggerSpell', $this->subject->id]], ['AND', ['OR', ['effect3Id', SpellList::$effects['trigger']], ['effect3AuraId', SpellList::$auras['trigger']]], ['effect3TriggerSpell', $this->subject->id]]); $trigger = new SpellList($conditions); if (!$trigger->error) { $this->lvTabs[] = array('file' => 'spell', 'data' => $trigger->getListviewData(), 'params' => array('id' => 'triggered-by', 'name' => '$LANG.tab_triggeredby')); $this->extendGlobalData($trigger->getJSGlobals(GLOBALINFO_SELF)); } // tab: used by - creature // SMART_SCRIPT_TYPE_CREATURE = 0; SMART_ACTION_CAST = 11; SMART_ACTION_ADD_AURA = 75; SMART_ACTION_INVOKER_CAST = 85; SMART_ACTION_CROSS_CAST = 86 $conditions = array('OR', ['spell1', $this->typeId], ['spell2', $this->typeId], ['spell3', $this->typeId], ['spell4', $this->typeId], ['spell5', $this->typeId], ['spell6', $this->typeId], ['spell7', $this->typeId], ['spell8', $this->typeId]); if ($_ = DB::World()->selectCol('SELECT entryOrGUID FROM smart_scripts WHERE entryorguid > 0 AND source_type = 0 AND action_type IN (11, 75, 85, 86) AND action_param1 = ?d', $this->typeId)) { $conditions[] = ['id', $_]; } $ubCreature = new CreatureList($conditions); if (!$ubCreature->error) { $this->lvTabs[] = array('file' => 'creature', 'data' => $ubCreature->getListviewData(), 'params' => array('id' => 'used-by-npc', 'name' => '$LANG.tab_usedby')); $this->extendGlobalData($ubCreature->getJSGlobals(GLOBALINFO_SELF)); } // tab: zone if ($areas = DB::World()->select('SELECT * FROM spell_area WHERE spell = ?d', $this->typeId)) { $zones = new ZoneList(array(['id', array_column($areas, 'area')])); if (!$zones->error) { $lvZones = $zones->getListviewData(); $this->extendGlobalData($zones->getJSGlobals()); $lv = []; $parents = []; $extra = false; foreach ($areas as $a) { if (empty($lvZones[$a['area']])) { continue; } $condition = []; if ($a['aura_spell']) { $this->extendGlobalIds(TYPE_SPELL, abs($a['aura_spell'])); $condition[0][$this->typeId][] = [[$a['aura_spell'] > 0 ? CND_AURA : -CND_AURA, abs($a['aura_spell'])]]; } if ($a['quest_start']) { $this->extendGlobalIds(TYPE_QUEST, $a['quest_start']); $group = []; for ($i = 0; $i < 7; $i++) { if (!($a['quest_start_status'] & 1 << $i)) { continue; } if ($i == 0) { $group[] = [CND_QUEST_NONE, $a['quest_start']]; } else { if ($i == 1) { $group[] = [CND_QUEST_COMPLETE, $a['quest_start']]; } else { if ($i == 3) { $group[] = [CND_QUESTTAKEN, $a['quest_start']]; } else { if ($i == 6) { $group[] = [CND_QUESTREWARDED, $a['quest_start']]; } } } } } if ($group) { $condition[0][$this->typeId][] = $group; } } if ($a['quest_end'] && $a['quest_end'] != $a['quest_start']) { $this->extendGlobalIds(TYPE_QUEST, $a['quest_end']); $group = []; for ($i = 0; $i < 7; $i++) { if (!($a['quest_end_status'] & 1 << $i)) { continue; } if ($i == 0) { $group[] = [-CND_QUEST_NONE, $a['quest_end']]; } else { if ($i == 1) { $group[] = [-CND_QUEST_COMPLETE, $a['quest_end']]; } else { if ($i == 3) { $group[] = [-CND_QUESTTAKEN, $a['quest_end']]; } else { if ($i == 6) { $group[] = [-CND_QUESTREWARDED, $a['quest_end']]; } } } } } if ($group) { $condition[0][$this->typeId][] = $group; } } if ($a['racemask']) { $foo = []; for ($i = 0; $i < 11; $i++) { if ($a['racemask'] & 1 << $i) { $foo[] = $i + 1; } } $this->extendGlobalIds(TYPE_RACE, $foo); $condition[0][$this->typeId][] = [[CND_RACE, $a['racemask']]]; } if ($a['gender'] != 2) { // 2: both $condition[0][$this->typeId][] = [[CND_GENDER, $a['gender'] + 1]]; } $row = $lvZones[$a['area']]; if ($condition) { $extra = true; $row = array_merge($row, ['condition' => $condition]); } // merge subzones, into one row, if: conditions match && parentZone is shared if ($p = $zones->getEntry($a['area'])['parentArea']) { $parents[] = $p; $row['parentArea'] = $p; $row['subzones'] = [$a['area']]; } else { $row['parentArea'] = 0; } $set = false; foreach ($lv as &$v) { if ($v['parentArea'] != $row['parentArea'] && $v['id'] != $row['parentArea']) { continue; } if (empty($v['condition']) xor empty($row['condition'])) { continue; } if (!empty($row['condition']) && !empty($v['condition']) && $v['condition'] != $row['condition']) { continue; } if (!$row['parentArea'] && $v['id'] != $row['parentArea']) { continue; } $set = true; $v['subzones'][] = $row['id']; break; } // add self as potential subzone; IF we are a parentZone without added children, we get filtered in JScript if (!$set) { $row['subzones'] = [$row['id']]; $lv[] = $row; } } // overwrite lvData with parent-lvData (condition and subzones are kept) if ($parents) { $parents = (new ZoneList(array(['id', $parents])))->getListviewData(); foreach ($lv as &$_) { if (isset($parents[$_['parentArea']])) { $_ = array_merge($_, $parents[$_['parentArea']]); } } } $this->lvTabs[] = array('file' => 'zone', 'data' => $lv, 'params' => array('extraCols' => $extra ? '$[Listview.extraCols.condition]' : null, 'hiddenCols' => $extra ? "\$['instancetype']" : null)); } } // tab: teaches if ($ids = Util::getTaughtSpells($this->subject)) { $teaches = new SpellList(array(['id', $ids])); if (!$teaches->error) { $this->extendGlobalData($teaches->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); $vis = ['level', 'schools']; $hid = []; if (!$teaches->hasSetFields(['skillLines'])) { $hid[] = 'skill'; } foreach ($teaches->iterate() as $__) { if (!$teaches->canCreateItem()) { continue; } $vis[] = 'reagents'; break; } $this->lvTabs[] = array('file' => 'spell', 'data' => $teaches->getListviewData(), 'params' => array('id' => 'teaches-spell', 'name' => '$LANG.tab_teaches', 'visibleCols' => '$' . Util::toJSON($vis), 'hiddenCols' => $hid ? '$' . Util::toJSON($hid) : null)); } } // tab: taught by npc (source:6 => trainer) if (!empty($this->subject->sources[$this->typeId][6])) { $src = $this->subject->sources[$this->typeId][6]; $list = []; if (count($src) == 1 && $src[0] == 1) { $tt = null; // Professions if (in_array($_cat, [9, 11]) && isset(Util::$trainerTemplates[TYPE_SKILL][$this->subject->getField('skillLines')[0]])) { $tt = Util::$trainerTemplates[TYPE_SKILL][$this->subject->getField('skillLines')[0]]; } else { if ($_cat == 7 && $this->subject->getField('reqClassMask')) { $clId = log($this->subject->getField('reqClassMask'), 2) + 1; if (intVal($clId) == $clId) { // only one class was set, so float == int if (isset(Util::$trainerTemplates[TYPE_CLASS][$clId])) { $tt = Util::$trainerTemplates[TYPE_CLASS][$clId]; } } } } if ($tt) { $list = DB::World()->selectCol('SELECT DISTINCT ID FROM npc_trainer WHERE SpellID IN (?a) AND ID < 200000', $tt); } else { $mask = 0; foreach (Util::$skillLineMask[-3] as $idx => $pair) { if ($pair[1] == $this->typeId) { $mask |= 1 << $idx; } } $list = DB::World()->selectCol(' SELECT IF(t1.ID > 200000, t2.ID, t1.ID) FROM npc_trainer t1 LEFT JOIN npc_trainer t2 ON t2.SpellID = -t1.ID WHERE t1.SpellID = ?d', $this->typeId); } } else { if ($src) { $list = array_values($src); } } if ($list) { $tbTrainer = new CreatureList(array(CFG_SQL_LIMIT_NONE, ['ct.id', $list], ['s.guid', NULL, '!'], ['ct.npcflag', 0x10, '&'])); if (!$tbTrainer->error) { $this->extendGlobalData($tbTrainer->getJSGlobals()); $this->lvTabs[] = array('file' => 'creature', 'data' => $tbTrainer->getListviewData(), 'params' => array('id' => 'taught-by-npc', 'name' => '$LANG.tab_taughtby')); } } } // tab: taught by spell $conditions = array('OR', ['AND', ['effect1Id', SpellList::$effects['teach']], ['effect1TriggerSpell', $this->subject->id]], ['AND', ['effect2Id', SpellList::$effects['teach']], ['effect2TriggerSpell', $this->subject->id]], ['AND', ['effect3Id', SpellList::$effects['teach']], ['effect3TriggerSpell', $this->subject->id]]); $tbSpell = new SpellList($conditions); $tbsData = []; if (!$tbSpell->error) { $tbsData = $tbSpell->getListviewData(); $this->lvTabs[] = array('file' => 'spell', 'data' => $tbsData, 'params' => array('id' => 'taught-by-spell', 'name' => '$LANG.tab_taughtby')); $this->extendGlobalData($tbSpell->getJSGlobals(GLOBALINFO_SELF)); } // tab: taught by quest $conditions = ['OR', ['sourceSpellId', $this->typeId], ['rewardSpell', $this->typeId]]; if ($tbsData) { $conditions[] = ['rewardSpell', array_keys($tbsData)]; if (User::isInGroup(U_GROUP_EMPLOYEE)) { $conditions[] = ['rewardSpellCast', array_keys($tbsData)]; } } if (User::isInGroup(U_GROUP_EMPLOYEE)) { $conditions[] = ['rewardSpellCast', $this->typeId]; } $tbQuest = new QuestList($conditions); if (!$tbQuest->error) { $this->lvTabs[] = array('file' => 'quest', 'data' => $tbQuest->getListviewData(), 'params' => array('id' => 'reward-from-quest', 'name' => '$LANG.tab_rewardfrom')); $this->extendGlobalData($tbQuest->getJSGlobals()); } // tab: taught by item (i'd like to precheck $this->subject->sources, but there is no source:item only complicated crap like "drop" and "vendor") $conditions = array('OR', ['AND', ['spellTrigger1', 6], ['spellId1', $this->subject->id]], ['AND', ['spellTrigger2', 6], ['spellId2', $this->subject->id]], ['AND', ['spellTrigger3', 6], ['spellId3', $this->subject->id]], ['AND', ['spellTrigger4', 6], ['spellId4', $this->subject->id]], ['AND', ['spellTrigger5', 6], ['spellId5', $this->subject->id]]); $tbItem = new ItemList($conditions); if (!$tbItem->error) { $this->lvTabs[] = array('file' => 'item', 'data' => $tbItem->getListviewData(), 'params' => array('id' => 'taught-by-item', 'name' => '$LANG.tab_taughtby')); $this->extendGlobalData($tbItem->getJSGlobals(GLOBALINFO_SELF)); } // tab: enchantments $conditions = array('OR', ['AND', ['type1', [1, 3, 7]], ['object1', $this->typeId]], ['AND', ['type2', [1, 3, 7]], ['object2', $this->typeId]], ['AND', ['type3', [1, 3, 7]], ['object3', $this->typeId]]); $enchList = new EnchantmentList($conditions); if (!$enchList->error) { $this->lvTabs[] = array('file' => 'enchantment', 'data' => $enchList->getListviewData(), 'params' => []); $this->extendGlobalData($enchList->getJSGlobals()); } // find associated NPC, Item and merge results // taughtbypets (unused..?) // taughtbyquest (usually the spell casted as quest reward teaches something; exclude those seplls from taughtBySpell) // taughtbytrainers // taughtbyitem // tab: conditions $sc = Util::getServerConditions([CND_SRC_SPELL_LOOT_TEMPLATE, CND_SRC_SPELL_IMPLICIT_TARGET, CND_SRC_SPELL, CND_SRC_SPELL_CLICK_EVENT, CND_SRC_VEHICLE_SPELL, CND_SRC_SPELL_PROC], null, $this->typeId); if (!empty($sc[0])) { $this->extendGlobalData($sc[1]); $tab = "<script type=\"text/javascript\">\n" . "var markup = ConditionList.createTab(" . Util::toJSON($sc[0]) . ");\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')); } }
private function _searchTalent($cndBase) { $result = []; $cnd = array_merge($cndBase, array(['s.typeCat', [-7, -2]], $this->createLookup())); $talents = new SpellList($cnd); if ($data = $talents->getListviewData()) { if ($this->searchMask & SEARCH_TYPE_REGULAR) { $this->extendGlobalData($talents->getJSGlobals()); } $vis = ['level', 'singleclass', 'schools']; if ($talents->hasSetFields(['reagent1'])) { $vis[] = 'reagents'; } if ($this->searchMask & SEARCH_TYPE_OPEN) { foreach ($talents->iterate() as $__) { $data[$talents->id]['param1'] = strToLower($talents->getField('iconString')); $data[$talents->id]['param2'] = $talents->ranks[$talents->id]; } } $result = array('type' => TYPE_SPELL, 'appendix' => ' (Talent)', 'matches' => $talents->getMatches(), 'file' => SpellList::$brickFile, 'data' => $data, 'params' => ['id' => 'talents', 'name' => '$LANG.tab_talents', 'visibleCols' => '$' . Util::toJSON($vis)]); if ($talents->getMatches() > $this->maxResults) { $result['params']['note'] = sprintf(Util::$tryNarrowingString, 'LANG.lvnote_talentsfound', $talents->getMatches(), $this->maxResults); $result['params']['_truncated'] = 1; } if (isset($result['params']['note'])) { $result['params']['note'] .= ' + LANG.dash + $WH.sprintf(LANG.lvnote_filterresults, \'?spells=-2&filter=na=' . urlencode($this->search) . '\')'; } else { $result['params']['note'] = '$$WH.sprintf(LANG.lvnote_filterresults, \'?spells=-2&filter=na=' . urlencode($this->search) . '\')'; } } return $result; }
protected function generateContent() { $this->addJS('?data=zones&locale=' . User::$localeId . '&t=' . $_SESSION['dataKey']); $_itemId = $this->subject->getField('itemId'); /***********/ /* Infobox */ /**********/ $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); if ($this->typeId == 103) { // Arena Points $infobox[] = Lang::currency('cap') . Lang::main('colon') . '10\'000'; } else { if ($this->typeId == 104) { // Honor $infobox[] = Lang::currency('cap') . Lang::main('colon') . '75\'000'; } } /****************/ /* Main Content */ /****************/ $this->infobox = $infobox ? '[ul][li]' . implode('[/li][li]', $infobox) . '[/li][/ul]' : null; $this->name = $this->subject->getField('name', true); $this->headIcons = $this->typeId == 104 ? ['inv_bannerpvp_02', 'inv_bannerpvp_01'] : [$this->subject->getField('iconString')]; $this->redButtons = array(BUTTON_WOWHEAD => true, BUTTON_LINKS => true); /**************/ /* Extra Tabs */ /**************/ if ($this->typeId != 103 && $this->typeId != 104) { // tabs: this currency is contained in.. $lootTabs = new Loot(); if ($lootTabs->getByItem($_itemId)) { $this->extendGlobalData($lootTabs->jsGlobals); foreach ($lootTabs->iterate() as $tab) { $this->lvTabs[] = array('file' => $tab[0], 'data' => $tab[1], 'params' => ['name' => $tab[2], 'id' => $tab[3], 'extraCols' => $tab[4] ? '$[' . implode(', ', array_unique($tab[4])) . ']' : null, 'hiddenCols' => $tab[5] ? '$[' . implode(', ', array_unique($tab[5])) . ']' : null, 'visibleCols' => $tab[6] ? '$' . Util::toJSON(array_unique($tab[6])) : null]); } } // tab: sold by $itemObj = new ItemList(array(['id', $_itemId])); if (!empty($itemObj->getExtendedCost()[$_itemId])) { $vendors = $itemObj->getExtendedCost()[$_itemId]; $this->extendGlobalData($itemObj->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); $soldBy = new CreatureList(array(['id', array_keys($vendors)])); if (!$soldBy->error) { $sbData = $soldBy->getListviewData(); $extraCols = ['Listview.extraCols.stock', "Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')", 'Listview.extraCols.cost']; $holidays = []; foreach ($sbData as $k => &$row) { $items = []; $tokens = []; foreach ($vendors[$k] as $id => $qty) { if (is_string($id)) { continue; } if ($id > 0) { $tokens[] = [$id, $qty]; } else { if ($id < 0) { $items[] = [-$id, $qty]; } } } if ($vendors[$k]['event']) { if (count($extraCols) == 3) { // not already pushed $extraCols[] = 'Listview.extraCols.condition'; } $this->extendGlobalIds(TYPE_WORLDEVENT, $vendors[$k]['event']); $row['condition'][0][$this->typeId][] = [[CND_ACTIVE_EVENT, $vendors[$k]['event']]]; } $row['stock'] = $vendors[$k]['stock']; $row['stack'] = $itemObj->getField('buyCount'); $row['cost'] = array($itemObj->getField('buyPrice'), $items ? $items : null, $tokens ? $tokens : null); } $this->lvTabs[] = array('file' => 'creature', 'data' => $sbData, 'params' => ['name' => '$LANG.tab_soldby', 'id' => 'sold-by-npc', 'extraCols' => '$[' . implode(', ', $extraCols) . ']', 'hiddenCols' => "\$['level', 'type']"]); } } } // tab: created by (spell) [for items its handled in Loot::getByContainer()] if ($this->typeId == 104) { $createdBy = new SpellList(array(['effect1Id', 45], ['effect2Id', 45], ['effect3Id', 45], 'OR')); if (!$createdBy->error) { $this->extendGlobalData($createdBy->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); if ($createdBy->hasSetFields(['reagent1'])) { $visCols = ['reagents']; } $this->lvTabs[] = array('file' => 'spell', 'data' => $createdBy->getListviewData(), 'params' => ['name' => '$LANG.tab_createdby', 'id' => 'created-by', 'visibleCols' => isset($visCols) ? '$' . Util::toJSON($visCols) : null]); } } // tab: currency for if ($this->typeId == 103) { $n = '?items&filter=cr=145;crs=1;crv=0'; $w = 'reqArenaPoints > 0'; } else { if ($this->typeId == 104) { $n = '?items&filter=cr=144;crs=1;crv=0'; $w = 'reqHonorPoints > 0'; } else { $n = in_array($this->typeId, [42, 61, 81, 241, 121, 122, 123, 125, 126, 161, 201, 101, 102, 221, 301, 341]) ? '?items&filter=cr=158;crs=' . $_itemId . ';crv=0' : null; $w = 'reqItemId1 = ' . $_itemId . ' OR reqItemId2 = ' . $_itemId . ' OR reqItemId3 = ' . $_itemId . ' OR reqItemId4 = ' . $_itemId . ' OR reqItemId5 = ' . $_itemId; } } $xCosts = DB::Aowow()->selectCol('SELECT id FROM ?_itemextendedcost WHERE ' . $w); $boughtBy = $xCosts ? DB::World()->selectCol('SELECT item FROM npc_vendor WHERE extendedCost IN (?a) UNION SELECT item FROM game_event_npc_vendor WHERE extendedCost IN (?a)', $xCosts, $xCosts) : []; if ($boughtBy) { $boughtBy = new ItemList(array(['id', $boughtBy])); if (!$boughtBy->error) { if ($boughtBy->getMatches() <= CFG_SQL_LIMIT_DEFAULT) { $n = null; } $this->lvTabs[] = array('file' => 'item', 'data' => $boughtBy->getListviewData(ITEMINFO_VENDOR, [TYPE_CURRENCY => $this->typeId]), 'params' => ['name' => '$LANG.tab_currencyfor', 'id' => 'currency-for', 'extraCols' => "\$[Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')]", 'note' => $n ? sprintf(Util::$filterResultString, $n) : null]); $this->extendGlobalData($boughtBy->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); } } }
protected function generateContent() { $conditions = []; $visibleCols = []; $hiddenCols = []; $tabData = ['data' => []]; // the next lengthy ~250 lines determine $conditions and lvParams if ($this->category) { switch ($this->category[0]) { case -2: // Character Talents $this->filter['classPanel'] = true; array_push($visibleCols, 'singleclass', 'level', 'schools', 'tier'); $conditions[] = ['s.typeCat', -2]; // i will NOT redefine those class2skillId ... reusing if (isset($this->category[2])) { $conditions[] = ['s.skillLine1', $this->category[2]]; } else { if (isset($this->category[1])) { $conditions[] = ['s.skillLine1', $this->validCats[-2][$this->category[1]]]; } } break; case -3: // Pet Spells array_push($visibleCols, 'level', 'schools'); $conditions[] = ['s.typeCat', -3]; if (isset($this->category[1])) { $xCond = null; for ($i = -2; $i < 0; $i++) { foreach (Util::$skillLineMask[$i] as $idx => $pair) { if ($pair[1] == $this->category[1]) { $xCond = ['AND', ['s.skillLine1', $i], ['s.skillLine2OrMask', 1 << $idx, '&']]; break; } } } $conditions[] = ['OR', $xCond, ['s.skillLine1', $this->category[1]], ['AND', ['s.skillLine1', 0, '>'], ['s.skillLine2OrMask', $this->category[1]]]]; } else { $conditions[] = ['OR', ['s.skillLine1', [-1, -2]], ['s.skillLine1', $this->validCats[-3]], ['AND', ['s.skillLine1', 0, '>'], ['s.skillLine2OrMask', $this->validCats[-3]]]]; } break; case -4: // Racials array_push($visibleCols, 'classes'); $conditions[] = ['s.typeCat', -4]; break; case -8: // NPC-Spells // NPC-Spells case -9: // GM Spells array_push($visibleCols, 'level'); case -5: // Mounts // Mounts case -6: // Companions $conditions[] = ['s.typeCat', $this->category[0]]; break; case -7: // Pet Talents array_push($visibleCols, 'level', 'tier'); $conditions[] = ['s.typeCat', -7]; if (isset($this->category[1])) { switch ($this->category[1]) { case 409: // Tenacity $conditions[] = ['s.cuFlags', SPELL_CU_PET_TALENT_TYPE1, '&']; $url = '?pets=1'; break; case 410: // Cunning $conditions[] = ['s.cuFlags', SPELL_CU_PET_TALENT_TYPE2, '&']; $url = '?pets=2'; break; case 411: // Ferocity $conditions[] = ['s.cuFlags', SPELL_CU_PET_TALENT_TYPE0, '&']; $url = '?pets=0'; break; } $tabData['note'] = '$$WH.sprintf(LANG.lvnote_pettalents, "' . $url . '")'; } $tabData['_petTalents'] = 1; // not conviced, this is correct, but .. it works break; case -11: // Proficiencies ... the subIds are actually SkillLineCategories if (!isset($this->category[1]) || $this->category[1] != 10) { array_push($visibleCols, 'classes'); } $conditions[] = ['s.typeCat', -11]; if (isset($this->category[1])) { if ($this->category[1] == 6) { // todo (med): we know Weapon(6) includes spell Shoot(3018), that has a mask; but really, ANY proficiency or petSkill should be in that mask so there is no need to differenciate $conditions[] = ['OR', ['s.skillLine1', SpellList::$skillLines[$this->category[1]]], ['s.skillLine1', -3]]; } else { $conditions[] = ['s.skillLine1', SpellList::$skillLines[$this->category[1]]]; } } break; case -13: // Glyphs $this->filter['classPanel'] = true; $this->filter['glyphPanel'] = true; array_push($visibleCols, 'singleclass', 'glyphtype'); $conditions[] = ['s.typeCat', -13]; if (isset($this->category[1])) { $conditions[] = ['s.reqClassMask', 1 << $this->category[1] - 1, '&']; } break; case 7: // Abilities $this->filter['classPanel'] = true; array_push($visibleCols, 'level', 'singleclass', 'schools'); $conditions[] = ['s.typeCat', [7, -2]]; $conditions[] = [['s.cuFlags', SPELL_CU_TRIGGERED | SPELL_CU_TALENT, '&'], 0]; // Runeforging listed multiple times, exclude from explicit skill-listing // if (isset($this->category[1]) && $this->category[1] == 6 && isset($this->category[2]) && $this->category[2] != 776) // $conditions[] = [['s.attributes0', 0x80, '&'], 0]; // else // $conditions[] = [ // [['s.attributes0', 0x80, '&'], 0], // ~SPELL_ATTR0_HIDDEN_CLIENTSIDE // ['s.attributes0', 0x20, '&'], // SPELL_ATTR0_TRADESPELL (DK: Runeforging) // 'OR' // ]; if (isset($this->category[2])) { $conditions[] = ['OR', ['s.skillLine1', $this->category[2]], ['AND', ['s.skillLine1', 0, '>'], ['s.skillLine2OrMask', $this->category[2]]]]; } else { if (isset($this->category[1])) { $conditions[] = ['OR', ['s.skillLine1', $this->validCats[7][$this->category[1]]], ['AND', ['s.skillLine1', 0, '>'], ['s.skillLine2OrMask', $this->validCats[7][$this->category[1]]]]]; } } break; case 9: // Secondary Skills array_push($visibleCols, 'source'); $conditions[] = ['s.typeCat', 9]; if (isset($this->category[1])) { $conditions[] = ['OR', ['s.skillLine1', $this->category[1]], ['AND', ['s.skillLine1', 0, '>'], ['s.skillLine2OrMask', $this->category[1]]]]; if (!empty($this->shortFilter[$this->category[1]])) { $sf = $this->shortFilter[$this->category[1]]; $txt = ''; if ($sf[0] && $sf[1]) { $txt = sprintf(Lang::spell('relItems', 'crafted'), $sf[0]) . Lang::spell('relItems', 'link') . sprintf(Lang::spell('relItems', 'recipes'), $sf[1]); } else { if ($sf[0]) { $txt = sprintf(Lang::spell('relItems', 'crafted'), $sf[0]); } else { if ($sf[1]) { $txt = sprintf(Lang::spell('relItems', 'recipes'), $sf[1]); } } } $note = Lang::spell('cat', $this->category[0], $this->category[1]); if (is_array($note)) { $note = $note[0]; } $tabData['note'] = sprintf(Lang::spell('relItems', 'base'), $txt, $note); $tabData['sort'] = ['skill', 'name']; } } break; case 11: // Professions array_push($visibleCols, 'source'); $conditions[] = ['s.typeCat', 11]; if (isset($this->category[2])) { if ($this->category[2] == 9787) { // general weaponsmithing $conditions[] = ['s.reqSpellId', [9787, 17039, 17040, 17041]]; } else { $conditions[] = ['s.reqSpellId', $this->category[2]]; } } else { if (isset($this->category[1])) { $conditions[] = ['s.skillLine1', $this->category[1]]; } } if (isset($this->category[1])) { $conditions[] = ['s.skillLine1', $this->category[1]]; if (!empty($this->shortFilter[$this->category[1]])) { $sf = $this->shortFilter[$this->category[1]]; $txt = ''; if ($sf[0] && $sf[1]) { $txt = sprintf(Lang::spell('relItems', 'crafted'), $sf[0]) . Lang::spell('relItems', 'link') . sprintf(Lang::spell('relItems', 'recipes'), $sf[1]); } else { if ($sf[0]) { $txt = sprintf(Lang::spell('relItems', 'crafted'), $sf[0]); } else { if ($sf[1]) { $txt = sprintf(Lang::spell('relItems', 'recipes'), $sf[1]); } } } $note = Lang::spell('cat', $this->category[0], $this->category[1]); if (is_array($note)) { $note = $note[0]; } $tabData['note'] = sprintf(Lang::spell('relItems', 'base'), $txt, $note); $tabData['sort'] = ['skill', 'name']; } } break; case 0: // misc. Spells & triggered player abilities array_push($visibleCols, 'level'); $conditions[] = ['OR', ['s.typeCat', 0], ['AND', ['s.cuFlags', SPELL_CU_TRIGGERED, '&'], ['s.typeCat', [7, -2]]]]; break; } } if (!User::isInGroup(U_GROUP_EMPLOYEE)) { $conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0]; } if ($_ = $this->filterObj->getConditions()) { $conditions[] = $_; } $spells = new SpellList($conditions); $this->extendGlobalData($spells->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); $tabData['data'] = array_values($spells->getListviewData()); // recreate form selection $this->filter = array_merge($this->filterObj->getForm('form'), $this->filter); $this->filter['query'] = isset($_GET['filter']) ? $_GET['filter'] : NULL; $this->filter['fi'] = $this->filterObj->getForm(); if (!empty($this->filter['fi']['extraCols'])) { $tabData['extraCols'] = '$fi_getExtraCols(fi_extraCols, 0, 0)'; } // create note if search limit was exceeded; overwriting 'note' is intentional if ($spells->getMatches() > CFG_SQL_LIMIT_DEFAULT) { $tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_spellsfound', $spells->getMatches(), CFG_SQL_LIMIT_DEFAULT); $tabData['_truncated'] = 1; } if ($this->filterObj->error) { $tabData['_errors'] = 1; } // add source to cols if explicitly searching for it if ($_ = $this->filterObj->getForm('setCriteria', true)) { if (in_array(9, $_['cr']) && !in_array('source', $visibleCols)) { $visibleCols[] = 'source'; } } $mask = $spells->hasSetFields(['reagent1', 'skillLines', 'trainingCost', 'reqClassMask']); if ($mask & 0x1) { $visibleCols[] = 'reagents'; } if (!($mask & 0x2) && $this->category && !in_array($this->category[0], [9, 11])) { $hiddenCols[] = 'skill'; } if ($mask & 0x4) { $visibleCols[] = 'trainingcost'; } if ($mask & 0x8 && !in_array('singleclass', $visibleCols)) { $visibleCols[] = 'singleclass'; } if ($visibleCols) { $tabData['visibleCols'] = $visibleCols; } if ($hiddenCols) { $tabData['hiddenCols'] = $hiddenCols; } $this->lvTabs[] = ['spell', $tabData]; // sort for dropdown-menus Lang::sort('game', 'ra'); Lang::sort('game', 'cl'); Lang::sort('game', 'sc'); Lang::sort('game', 'me'); }
private function _searchTalent($cndBase) { $cnd = array_merge($cndBase, array(['s.typeCat', [-7, -2]], $this->createLookup())); $talents = new SpellList($cnd); if ($data = $talents->getListviewData()) { if ($this->searchMask & SEARCH_TYPE_REGULAR) { $this->extendGlobalData($talents->getJSGlobals()); } $vis = ['level', 'singleclass', 'schools']; if ($talents->hasSetFields(['reagent1'])) { $vis[] = 'reagents'; } $osInfo = [TYPE_SPELL, ' (Talent)', $talents->getMatches(), [], []]; $result = array('data' => array_values($data), 'id' => 'talents', 'name' => '$LANG.tab_talents', 'visibleCols' => $vis); if ($this->searchMask & SEARCH_TYPE_OPEN) { foreach ($talents->iterate() as $id => $__) { $osInfo[3][$id] = strToLower($talents->getField('iconString')); $osInfo[4][$id] = $talents->ranks[$talents->id]; } } if ($talents->getMatches() > $this->maxResults) { $result['note'] = sprintf(Util::$tryNarrowingString, 'LANG.lvnote_talentsfound', $talents->getMatches(), $this->maxResults); $result['_truncated'] = 1; } if (isset($result['note'])) { $result['note'] .= ' + LANG.dash + $WH.sprintf(LANG.lvnote_filterresults, \'?spells=-2&filter=na=' . urlencode($this->search) . '\')'; } else { $result['note'] = '$$WH.sprintf(LANG.lvnote_filterresults, \'?spells=-2&filter=na=' . urlencode($this->search) . '\')'; } return ['spell', $result, null, $osInfo]; } return false; }
public function getByItem($entry, $maxResults = CFG_SQL_LIMIT_DEFAULT, $lootTableList = []) { $this->entry = intVal($entry); if (!$this->entry) { return false; } // [fileName, tabData, tabName, tabId, extraCols, hiddenCols, visibleCols] $tabsFinal = array(['item', [], '$LANG.tab_containedin', 'contained-in-item', [], [], []], ['item', [], '$LANG.tab_disenchantedfrom', 'disenchanted-from', [], [], []], ['item', [], '$LANG.tab_prospectedfrom', 'prospected-from', [], [], []], ['item', [], '$LANG.tab_milledfrom', 'milled-from', [], [], []], ['creature', [], '$LANG.tab_droppedby', 'dropped-by', [], [], []], ['creature', [], '$LANG.tab_pickpocketedfrom', 'pickpocketed-from', [], [], []], ['creature', [], '$LANG.tab_skinnedfrom', 'skinned-from', [], [], []], ['creature', [], '$LANG.tab_minedfromnpc', 'mined-from-npc', [], [], []], ['creature', [], '$LANG.tab_salvagedfrom', 'salvaged-from', [], [], []], ['creature', [], '$LANG.tab_gatheredfromnpc', 'gathered-from-npc', [], [], []], ['quest', [], '$LANG.tab_rewardfrom', 'reward-from-quest', [], [], []], ['zone', [], '$LANG.tab_fishedin', 'fished-in-zone', [], [], []], ['object', [], '$LANG.tab_containedin', 'contained-in-object', [], [], []], ['object', [], '$LANG.tab_minedfrom', 'mined-from-object', [], [], []], ['object', [], '$LANG.tab_gatheredfrom', 'gathered-from-object', [], [], []], ['object', [], '$LANG.tab_fishedin', 'fished-in-object', [], [], []], ['spell', [], '$LANG.tab_createdby', 'created-by', [], [], []], ['achievement', [], '$LANG.tab_rewardfrom', 'reward-from-achievement', [], [], []]); $refResults = []; $chanceMods = []; $query = 'SELECT lt1.entry AS ARRAY_KEY, IF(lt1.reference = 0, lt1.item, lt1.reference) AS item, lt1.chance, SUM(IF(lt2.chance = 0, 1, 0)) AS nZeroItems, SUM(lt2.chance) AS sumChance, IF(lt1.groupid > 0, 1, 0) AS isGrouped, IF(lt1.reference = 0, lt1.mincount, 1) AS min, IF(lt1.reference = 0, lt1.maxcount, 1) AS max, IF(lt1.reference > 0, lt1.maxcount, 1) AS multiplier FROM ?# lt1 LEFT JOIN ?# lt2 ON lt1.entry = lt2.entry AND lt1.groupid = lt2.groupid WHERE %s GROUP BY lt2.entry, lt2.groupid'; $calcChance = function ($refs, $parents = []) use(&$chanceMods) { $retData = []; $retKeys = []; foreach ($refs as $rId => $ref) { // check for possible database inconsistencies if (!$ref['chance'] && !$ref['isGrouped']) { Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: ungrouped Item/Ref ' . $ref['item'] . ' has 0% chance assigned!'); } if ($ref['isGrouped'] && $ref['sumChance'] > 100) { Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: group with Item/Ref ' . $ref['item'] . ' has ' . number_format($ref['sumChance'], 2) . '% total chance! Some items cannot drop!'); } if ($ref['isGrouped'] && $ref['sumChance'] >= 100 && !$ref['chance']) { Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: Item/Ref ' . $ref['item'] . ' with adaptive chance cannot drop. Group already at 100%!'); } $chance = abs($ref['chance'] ?: (100 - $ref['sumChance']) / $ref['nZeroItems']) / 100; // apply inherited chanceMods if (isset($chanceMods[$ref['item']])) { $chance *= $chanceMods[$ref['item']][0]; $chance = 1 - pow(1 - $chance, $chanceMods[$ref['item']][1]); } // save chance for parent-ref $chanceMods[$rId] = [$chance, $ref['multiplier']]; // refTemplate doesn't point to a new ref -> we are done if (!in_array($rId, $parents)) { $data = array('percent' => $chance, 'stack' => [$ref['min'], $ref['max']], 'count' => 1); if ($_ = self::createStack($ref)) { $data['pctstack'] = $_; } // sort highest chances first $i = 0; for (; $i < count($retData); $i++) { if ($retData[$i]['percent'] < $data['percent']) { break; } } array_splice($retData, $i, 0, [$data]); array_splice($retKeys, $i, 0, [$rId]); } } return array_combine($retKeys, $retData); }; /* get references containing the item */ $newRefs = DB::World()->select(sprintf($query, 'lt1.item = ?d AND lt1.reference = 0'), LOOT_REFERENCE, LOOT_REFERENCE, $this->entry); while ($newRefs) { $curRefs = $newRefs; $newRefs = DB::World()->select(sprintf($query, 'lt1.reference IN (?a)'), LOOT_REFERENCE, LOOT_REFERENCE, array_keys($curRefs)); $refResults += $calcChance($curRefs, array_column($newRefs, 'item')); } /* search the real loot-templates for the itemId and gathered refds */ for ($i = 1; $i < count($this->lootTemplates); $i++) { if ($lootTableList && !in_array($this->lootTemplates[$i], $lootTableList)) { continue; } $result = $calcChance(DB::World()->select(sprintf($query, '{lt1.reference IN (?a) OR }(lt1.reference = 0 AND lt1.item = ?d)'), $this->lootTemplates[$i], $this->lootTemplates[$i], $refResults ? array_keys($refResults) : DBSIMPLE_SKIP, $this->entry)); // do not skip here if $result is empty. Additional loot for spells and quest is added separately // format for actual use foreach ($result as $k => $v) { unset($result[$k]); $v['percent'] = round($v['percent'] * 100, 3); $result[abs($k)] = $v; } // cap fetched entries to the sql-limit to guarantee, that the highest chance items get selected first // screws with GO-loot and skinnig-loot as these templates are shared for several tabs (fish, herb, ore) (herb, ore, leather) $ids = array_slice(array_keys($result), 0, $maxResults); switch ($this->lootTemplates[$i]) { case LOOT_CREATURE: $field = 'lootId'; $tabId = 4; break; case LOOT_PICKPOCKET: $field = 'pickpocketLootId'; $tabId = 5; break; case LOOT_SKINNING: $field = 'skinLootId'; $tabId = -6; break; // assigned later // assigned later case LOOT_PROSPECTING: $field = 'id'; $tabId = 2; break; case LOOT_MILLING: $field = 'id'; $tabId = 3; break; case LOOT_ITEM: $field = 'id'; $tabId = 0; break; case LOOT_DISENCHANT: $field = 'disenchantId'; $tabId = 1; break; case LOOT_FISHING: $field = 'id'; $tabId = 11; break; // subAreas are currently ignored // subAreas are currently ignored case LOOT_GAMEOBJECT: if (!$ids) { continue 2; } $srcObj = new GameObjectList(array(['lootId', $ids])); if ($srcObj->error) { continue 2; } $srcData = $srcObj->getListviewData(); foreach ($srcObj->iterate() as $__id => $curTpl) { switch ($curTpl['typeCat']) { case 25: $tabId = 15; break; // fishing node // fishing node case -3: $tabId = 14; break; // herb // herb case -4: $tabId = 13; break; // vein // vein default: $tabId = 12; break; // general chest loot } $tabsFinal[$tabId][1][] = array_merge($srcData[$srcObj->id], $result[$srcObj->getField('lootId')]); $tabsFinal[$tabId][4][] = 'Listview.extraCols.percent'; if ($tabId != 15) { $tabsFinal[$tabId][6][] = 'skill'; } } continue 2; case LOOT_MAIL: // quest part $conditions = array(['rewardChoiceItemId1', $this->entry], ['rewardChoiceItemId2', $this->entry], ['rewardChoiceItemId3', $this->entry], ['rewardChoiceItemId4', $this->entry], ['rewardChoiceItemId5', $this->entry], ['rewardChoiceItemId6', $this->entry], ['rewardItemId1', $this->entry], ['rewardItemId2', $this->entry], ['rewardItemId3', $this->entry], ['rewardItemId4', $this->entry], 'OR'); if ($ids) { $conditions[] = ['rewardMailTemplateId', $ids]; } $srcObj = new QuestList($conditions); if (!$srcObj->error) { self::storeJSGlobals($srcObj->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS)); $srcData = $srcObj->getListviewData(); foreach ($srcObj->iterate() as $_) { $tabsFinal[10][1][] = array_merge($srcData[$srcObj->id], empty($result[$srcObj->id]) ? ['percent' => -1] : $result[$srcObj->id]); } } // achievement part $conditions = array(['itemExtra', $this->entry]); if ($ar = DB::World()->selectCol('SELECT entry FROM achievement_reward WHERE item = ?d{ OR mailTemplate IN (?a)}', $this->entry, $ids ?: DBSIMPLE_SKIP)) { array_push($conditions, ['id', $ar], 'OR'); } $srcObj = new AchievementList($conditions); if (!$srcObj->error) { self::storeJSGlobals($srcObj->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS)); $srcData = $srcObj->getListviewData(); foreach ($srcObj->iterate() as $_) { $tabsFinal[17][1][] = array_merge($srcData[$srcObj->id], empty($result[$srcObj->id]) ? ['percent' => -1] : $result[$srcObj->id]); } $tabsFinal[17][5][] = 'rewards'; $tabsFinal[17][6][] = 'category'; } continue 2; case LOOT_SPELL: $conditions = array('OR', ['AND', ['effect1CreateItemId', $this->entry], ['OR', ['effect1Id', SpellList::$effects['itemCreate']], ['effect1AuraId', SpellList::$auras['itemCreate']]]], ['AND', ['effect2CreateItemId', $this->entry], ['OR', ['effect2Id', SpellList::$effects['itemCreate']], ['effect2AuraId', SpellList::$auras['itemCreate']]]], ['AND', ['effect3CreateItemId', $this->entry], ['OR', ['effect3Id', SpellList::$effects['itemCreate']], ['effect3AuraId', SpellList::$auras['itemCreate']]]]); if ($ids) { $conditions[] = ['id', $ids]; } $srcObj = new SpellList($conditions); if (!$srcObj->error) { self::storeJSGlobals($srcObj->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); $srcData = $srcObj->getListviewData(); if (!empty($result)) { $tabsFinal[16][4][] = 'Listview.extraCols.percent'; } if ($srcObj->hasSetFields(['reagent1'])) { $tabsFinal[16][6][] = 'reagents'; } foreach ($srcObj->iterate() as $_) { $tabsFinal[16][1][] = array_merge($srcData[$srcObj->id], empty($result[$srcObj->id]) ? ['percent' => -1] : $result[$srcObj->id]); } } continue 2; } if (!$ids) { continue; } switch ($tabsFinal[abs($tabId)][0]) { case 'creature': // new CreatureList // new CreatureList case 'item': // new ItemList // new ItemList case 'zone': // new ZoneList $oName = ucFirst($tabsFinal[abs($tabId)][0]) . 'List'; $srcObj = new $oName(array([$field, $ids])); if (!$srcObj->error) { $srcData = $srcObj->getListviewData(); self::storeJSGlobals($srcObj->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); foreach ($srcObj->iterate() as $curTpl) { if ($tabId < 0 && $curTpl['typeFlags'] & NPC_TYPEFLAG_HERBLOOT) { $tabId = 9; } else { if ($tabId < 0 && $curTpl['typeFlags'] & NPC_TYPEFLAG_ENGINEERLOOT) { $tabId = 8; } else { if ($tabId < 0 && $curTpl['typeFlags'] & NPC_TYPEFLAG_MININGLOOT) { $tabId = 7; } else { if ($tabId < 0) { $tabId = abs($tabId); } } } } // general case (skinning) $tabsFinal[$tabId][1][] = array_merge($srcData[$srcObj->id], $result[$srcObj->getField($field)]); $tabsFinal[$tabId][4][] = 'Listview.extraCols.percent'; } } break; } } $this->results = $tabsFinal; return true; }
protected function generateContent() { $this->addJS('?data=weight-presets.zones&locale=' . User::$localeId . '&t=' . $_SESSION['dataKey']); $_flags = $this->subject->getField('flags'); $_slot = $this->subject->getField('slot'); $_class = $this->subject->getField('class'); $_subClass = $this->subject->getField('subClass'); $_bagFamily = $this->subject->getField('bagFamily'); $_model = $this->subject->getField('displayId'); $_visSlots = array(INVTYPE_HEAD, INVTYPE_SHOULDERS, INVTYPE_BODY, INVTYPE_CHEST, INVTYPE_WAIST, INVTYPE_LEGS, INVTYPE_FEET, INVTYPE_WRISTS, INVTYPE_HANDS, INVTYPE_WEAPON, INVTYPE_SHIELD, INVTYPE_RANGED, INVTYPE_CLOAK, INVTYPE_2HWEAPON, INVTYPE_TABARD, INVTYPE_ROBE, INVTYPE_WEAPONMAINHAND, INVTYPE_WEAPONOFFHAND, INVTYPE_HOLDABLE, INVTYPE_THROWN, INVTYPE_RANGEDRIGHT); /***********/ /* Infobox */ /***********/ $infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags')); // itemlevel if (in_array($_class, [ITEM_CLASS_ARMOR, ITEM_CLASS_WEAPON, ITEM_CLASS_AMMUNITION]) || $this->subject->getField('gemEnchantmentId')) { $infobox[] = Lang::game('level') . Lang::main('colon') . $this->subject->getField('itemLevel'); } // account-wide if ($_flags & ITEM_FLAG_ACCOUNTBOUND) { $infobox[] = Lang::item('accountWide'); } // side if ($si = $this->subject->json[$this->typeId]['side']) { if ($si != 3) { $infobox[] = Lang::main('side') . Lang::main('colon') . '[span class=icon-' . ($si == 1 ? 'alliance' : 'horde') . ']' . Lang::game('si', $si) . '[/span]'; } } // consumable / not consumable if (!$_slot) { $hasUse = false; for ($i = 1; $i < 6; $i++) { if ($this->subject->getField('spellId' . $i) <= 0 || in_array($this->subject->getField('spellTrigger' . $i), [1, 2])) { continue; } $hasUse = true; if ($this->subject->getField('spellCharges' . $i) >= 0) { continue; } $tt = '[tooltip=tooltip_consumedonuse]' . Lang::item('consumable') . '[/tooltip]'; break; } if ($hasUse) { $infobox[] = isset($tt) ? $tt : '[tooltip=tooltip_notconsumedonuse]' . Lang::item('nonConsumable') . '[/tooltip]'; } } // related holiday if ($hId = $this->subject->getField('holidayId')) { if ($hName = DB::Aowow()->selectRow('SELECT * FROM ?_holidays WHERE id = ?d', $hId)) { $infobox[] = Lang::game('eventShort') . Lang::main('colon') . '[url=?event=' . $hId . ']' . Util::localizedString($hName, 'name') . '[/url]'; } } // tool if ($tId = $this->subject->getField('totemCategory')) { if ($tName = DB::Aowow()->selectRow('SELECT * FROM ?_totemcategory WHERE id = ?d', $tId)) { $infobox[] = Lang::item('tool') . Lang::main('colon') . '[url=?items&filter=cr=91;crs=' . $tId . ';crv=0]' . Util::localizedString($tName, 'name') . '[/url]'; } } // extendedCost if (!empty($this->subject->getExtendedCost([], $_reqRating)[$this->subject->id])) { $vendors = $this->subject->getExtendedCost()[$this->subject->id]; $each = $this->subject->getField('stackable') > 1 ? '[color=q0] (' . Lang::item('each') . ')[/color]' : null; $handled = []; $costList = []; foreach ($vendors as $npcId => $data) { $tokens = []; $currency = []; if (!is_array($data)) { continue; } foreach ($data as $c => $qty) { if (is_string($c)) { unset($data[$c]); // unset miscData to prevent having two vendors /w the same cost being cached, because of different stock or rating-requirements continue; } if ($c < 0) { // currency items (and honor or arena) $currency[] = -$c . ',' . $qty; } else { if ($c > 0) { // plain items (item1,count1,item2,count2,...) $tokens[$c] = $c . ',' . $qty; } } } // display every cost-combination only once if (in_array(md5(serialize($data)), $handled)) { continue; } $handled[] = md5(serialize($data)); $cost = isset($data[0]) ? '[money=' . $data[0] : '[money'; if ($tokens) { $cost .= ' items=' . implode(',', $tokens); } if ($currency) { $cost .= ' currency=' . implode(',', $currency); } $cost .= ']'; $costList[] = $cost; } if (count($costList) == 1) { $infobox[] = Lang::item('cost') . Lang::main('colon') . $costList[0] . $each; } else { if (count($costList) > 1) { $infobox[] = Lang::item('cost') . $each . Lang::main('colon') . '[ul][li]' . implode('[/li][li]', $costList) . '[/li][/ul]'; } } if ($_reqRating) { $res = []; $i = 0; $len = 0; $parts = explode(' ', str_replace('<br>', ' ', sprintf(Lang::item('reqRating', $_reqRating[1]), $_reqRating[0]))); foreach ($parts as $p) { $res[$i][] = $p; $len += mb_strlen($p) + 1; if ($len < 30) { continue; } $len = 0; $i++; } foreach ($res as &$r) { $r = implode(' ', $r); } $infobox[] = implode('[br]', $res); } } // repair cost if ($_ = $this->subject->getField('repairPrice')) { $infobox[] = Lang::item('repairCost') . Lang::main('colon') . '[money=' . $_ . ']'; } // avg auction buyout if (in_array($this->subject->getField('bonding'), [0, 2, 3])) { if ($_ = Util::getBuyoutForItem($this->typeId)) { $infobox[] = '[tooltip=tooltip_buyoutprice]' . Lang::item('buyout.') . '[/tooltip]' . Lang::main('colon') . '[money=' . $_ . ']' . $each; } } // avg money contained if ($_flags & ITEM_FLAG_OPENABLE) { if ($_ = intVal(($this->subject->getField('minMoneyLoot') + $this->subject->getField('maxMoneyLoot')) / 2)) { $infobox[] = Lang::item('worth') . Lang::main('colon') . '[tooltip=tooltip_avgmoneycontained][money=' . $_ . '][/tooltip]'; } } // if it goes into a slot it may be disenchanted if ($_slot && $_class != ITEM_CLASS_CONTAINER) { if ($this->subject->getField('disenchantId')) { $_ = $this->subject->getField('requiredDisenchantSkill'); if ($_ < 1) { // these are some items, that never went live .. extremely rough emulation here $_ = intVal($this->subject->getField('itemLevel') / 7.5) * 25; } $infobox[] = Lang::item('disenchantable') . ' ([tooltip=tooltip_reqenchanting]' . $_ . '[/tooltip])'; } else { $infobox[] = Lang::item('cantDisenchant'); } } if ($_flags & ITEM_FLAG_MILLABLE && $this->subject->getField('requiredSkill') == 773) { $infobox[] = Lang::item('millable') . ' ([tooltip=tooltip_reqinscription]' . $this->subject->getField('requiredSkillRank') . '[/tooltip])'; } if ($_flags & ITEM_FLAG_PROSPECTABLE && $this->subject->getField('requiredSkill') == 755) { $infobox[] = Lang::item('prospectable') . ' ([tooltip=tooltip_reqjewelcrafting]' . $this->subject->getField('requiredSkillRank') . '[/tooltip])'; } if ($_flags & ITEM_FLAG_DEPRECATED) { $infobox[] = '[tooltip=tooltip_deprecated]' . Lang::item('deprecated') . '[/tooltip]'; } if ($_flags & ITEM_FLAG_NO_EQUIPCD) { $infobox[] = '[tooltip=tooltip_noequipcooldown]' . Lang::item('noEquipCD') . '[/tooltip]'; } if ($_flags & ITEM_FLAG_PARTYLOOT) { $infobox[] = '[tooltip=tooltip_partyloot]' . Lang::item('partyLoot') . '[/tooltip]'; } if ($_flags & ITEM_FLAG_REFUNDABLE) { $infobox[] = '[tooltip=tooltip_refundable]' . Lang::item('refundable') . '[/tooltip]'; } if ($_flags & ITEM_FLAG_SMARTLOOT) { $infobox[] = '[tooltip=tooltip_smartloot]' . Lang::item('smartLoot') . '[/tooltip]'; } if ($_flags & ITEM_FLAG_INDESTRUCTIBLE) { $infobox[] = Lang::item('indestructible'); } if ($_flags & ITEM_FLAG_USABLE_ARENA) { $infobox[] = Lang::item('useInArena'); } if ($_flags & ITEM_FLAG_USABLE_SHAPED) { $infobox[] = Lang::item('useInShape'); } // cant roll need if ($this->subject->getField('flagsExtra') & 0x100) { $infobox[] = '[tooltip=tooltip_cannotrollneed]' . Lang::item('noNeedRoll') . '[/tooltip]'; } // fits into keyring if ($_bagFamily & 0x100) { $infobox[] = Lang::item('atKeyring'); } /****************/ /* Main Content */ /****************/ $_cu = in_array($_class, [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]) || $this->subject->getField('gemEnchantmentId'); $this->headIcons = [$this->subject->getField('iconString'), $this->subject->getField('stackable')]; $this->infobox = $infobox ? '[ul][li]' . implode('[/li][li]', $infobox) . '[/li][/ul]' : null; $this->tooltip = $this->subject->renderTooltip(true); $this->redButtons = array(BUTTON_WOWHEAD => true, BUTTON_LINKS => ['color' => 'ff' . Util::$rarityColorStings[$this->subject->getField('quality')], 'linkId' => 'item:' . $this->typeId . ':0:0:0:0:0:0:0:0'], BUTTON_VIEW3D => in_array($_slot, $_visSlots) && $_model ? ['displayId' => $this->subject->getField('displayId'), 'slot' => $_slot, 'type' => TYPE_ITEM, 'typeId' => $this->typeId] : false, BUTTON_COMPARE => $_cu, BUTTON_EQUIP => in_array($_class, [ITEM_CLASS_WEAPON, ITEM_CLASS_ARMOR]), BUTTON_UPGRADE => $_cu ? ['class' => $_class, 'slot' => $_slot] : false); // availablility $this->disabled = false; // todo (med): get itemSources (which are not yet in DB :x) or // pageText if ($next = $this->subject->getField('pageTextId')) { $this->addJS('Book.js'); $this->addCSS(['path' => 'Book.css']); while ($next) { $row = DB::World()->selectRow('SELECT *, text as Text_loc0 FROM page_text pt LEFT JOIN locales_page_text lpt ON pt.entry = lpt.entry WHERE pt.entry = ?d', $next); $next = $row['next_page']; $this->pageText[] = Util::parseHtmlText(Util::localizedString($row, 'Text')); } } // subItems $this->subject->initSubItems(); if (!empty($this->subject->subItems[$this->typeId])) { uaSort($this->subject->subItems[$this->typeId], function ($a, $b) { return strcmp($a['name'], $b['name']); }); $this->subItems = array('data' => array_values($this->subject->subItems[$this->typeId]), 'quality' => $this->subject->getField('quality')); // merge identical stats and names for normal users (e.g. spellPower of a specific school became generel spellPower with 3.0) if (!User::isInGroup(U_GROUP_EMPLOYEE)) { for ($i = 1; $i < count($this->subItems['data']); $i++) { $prev =& $this->subItems['data'][$i - 1]; $cur =& $this->subItems['data'][$i]; if ($prev['jsonequip'] == $cur['jsonequip'] && $prev['name'] == $cur['name']) { $prev['chance'] += $cur['chance']; array_splice($this->subItems['data'], $i, 1); $i = 1; } } } } // factionchange-equivalent if ($pendant = DB::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'), $altItem->id, $altItem->getField('quality'), $altItem->getField('iconString'), $altItem->getField('name', true), $pendant > 0 ? 'alliance' : 'horde', $pendant > 0 ? Lang::game('si', 1) : Lang::game('si', 2)); } } /**************/ /* Extra Tabs */ /**************/ // tabs: this item is contained in.. $lootTabs = new Loot(); $createdBy = []; if ($lootTabs->getByItem($this->typeId)) { $this->extendGlobalData($lootTabs->jsGlobals); foreach ($lootTabs->iterate() as $idx => $tab) { if (!$tab[1]) { continue; } if ($idx == 16) { $createdBy = array_column($tab[1], 'id'); } $this->lvTabs[] = array('file' => $tab[0], 'data' => $tab[1], 'params' => ['name' => $tab[2], 'id' => $tab[3], 'extraCols' => $tab[4] ? '$[' . implode(', ', array_unique($tab[4])) . ']' : null, 'hiddenCols' => $tab[5] ? '$ ' . Util::toJSON(array_unique($tab[5])) : null, 'visibleCols' => $tab[6] ? '$' . Util::toJSON(array_unique($tab[6])) : null]); } } // tabs: this item contains.. $sourceFor = array([LOOT_ITEM, $this->subject->id, '$LANG.tab_contains', 'contains', ['Listview.extraCols.percent'], [], []], [LOOT_PROSPECTING, $this->subject->id, '$LANG.tab_prospecting', 'prospecting', ['Listview.extraCols.percent'], ['side', 'slot', 'reqlevel'], []], [LOOT_MILLING, $this->subject->id, '$LANG.tab_milling', 'milling', ['Listview.extraCols.percent'], ['side', 'slot', 'reqlevel'], []], [LOOT_DISENCHANT, $this->subject->getField('disenchantId'), '$LANG.tab_disenchanting', 'disenchanting', ['Listview.extraCols.percent'], ['side', 'slot', 'reqlevel'], []]); $reqQuest = []; foreach ($sourceFor as $sf) { $lootTab = new Loot(); if ($lootTab->getByContainer($sf[0], $sf[1])) { $this->extendGlobalData($lootTab->jsGlobals); $sf[4] = array_merge($sf[4], $lootTab->extraCols); foreach ($lootTab->iterate() as $lv) { if (!$lv['quest']) { continue; } $sf[4] = array_merge($sf[4], ['Listview.extraCols.condition']); $reqQuest[$lv['id']] = 0; $lv['condition'][0][$this->typeId][] = [[CND_QUESTTAKEN, &$reqQuest[$lv['id']]]]; } $this->lvTabs[] = array('file' => 'item', 'data' => $lootTab->getResult(), 'params' => ['name' => $sf[2], 'id' => $sf[3], 'extraCols' => $sf[4] ? "\$[" . implode(', ', array_unique($sf[4])) . "]" : null, 'hiddenCols' => $sf[5] ? "\$" . Util::toJSON($sf[5]) : null, 'visibleCols' => $sf[6] ? '$' . Util::toJSON($sf[6]) : null]); } } if ($reqIds = array_keys($reqQuest)) { $conditions = array('OR', ['reqSourceItemId1', $reqIds], ['reqSourceItemId2', $reqIds], ['reqSourceItemId3', $reqIds], ['reqSourceItemId4', $reqIds], ['reqItemId1', $reqIds], ['reqItemId2', $reqIds], ['reqItemId3', $reqIds], ['reqItemId4', $reqIds], ['reqItemId5', $reqIds], ['reqItemId6', $reqIds]); $reqQuests = new QuestList($conditions); $reqQuests->getJSGlobals(GLOBALINFO_SELF); foreach ($reqQuests->iterate() as $qId => $__) { if (empty($reqQuests->requires[$qId][TYPE_ITEM])) { continue; } foreach ($reqIds as $rId) { if (in_array($rId, $reqQuests->requires[$qId][TYPE_ITEM])) { $reqQuest[$rId] = $reqQuests->id; } } } } // tab: container can contain if ($this->subject->getField('slots') > 0) { $contains = new ItemList(array(['bagFamily', $_bagFamily, '&'], ['slots', 1, '<'], CFG_SQL_LIMIT_NONE)); if (!$contains->error) { $this->extendGlobalData($contains->getJSGlobals(GLOBALINFO_SELF)); $hCols = ['side']; if (!$contains->hasSetFields(['slot'])) { $hCols[] = 'slot'; } $this->lvTabs[] = array('file' => 'item', 'data' => $contains->getListviewData(), 'params' => ['name' => '$LANG.tab_cancontain', 'id' => 'can-contain', 'hiddenCols' => '$' . Util::toJSON($hCols)]); } } else { if ($_bagFamily != 0x100) { $contains = new ItemList(array(['bagFamily', $_bagFamily, '&'], ['slots', 0, '>'], CFG_SQL_LIMIT_NONE)); if (!$contains->error) { $this->extendGlobalData($contains->getJSGlobals(GLOBALINFO_SELF)); $this->lvTabs[] = array('file' => 'item', 'data' => $contains->getListviewData(), 'params' => ['name' => '$LANG.tab_canbeplacedin', 'id' => 'can-be-placed-in', 'hiddenCols' => "\$['side']"]); } } } // tab: criteria of $conditions = array(['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM, ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM, ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM, ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM]], ['ac.value1', $this->typeId]); $criteriaOf = new AchievementList($conditions); if (!$criteriaOf->error) { $this->extendGlobalData($criteriaOf->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS)); $hCols = []; if (!$criteriaOf->hasSetFields(['reward_loc0'])) { $hCols = ['rewards']; } $this->lvTabs[] = array('file' => 'achievement', 'data' => $criteriaOf->getListviewData(), 'params' => ['name' => '$LANG.tab_criteriaof', 'id' => 'criteria-of', 'visibleCols' => "\$['category']", 'hiddenCols' => '$' . Util::toJSON($hCols)]); } // tab: reagent for $conditions = array('OR', ['reagent1', $this->typeId], ['reagent2', $this->typeId], ['reagent3', $this->typeId], ['reagent4', $this->typeId], ['reagent5', $this->typeId], ['reagent6', $this->typeId], ['reagent7', $this->typeId], ['reagent8', $this->typeId]); $reagent = new SpellList($conditions); if (!$reagent->error) { $this->extendGlobalData($reagent->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); $this->lvTabs[] = array('file' => 'spell', 'data' => $reagent->getListviewData(), 'params' => ['name' => '$LANG.tab_reagentfor', 'id' => 'reagent-for', 'visibleCols' => "\$['reagents']"]); } // tab: unlocks (object or item) $lockIds = DB::Aowow()->selectCol('SELECT id FROM ?_lock WHERE (type1 = 1 AND properties1 = ?d) OR (type2 = 1 AND properties2 = ?d) OR (type3 = 1 AND properties3 = ?d) OR (type4 = 1 AND properties4 = ?d) OR (type5 = 1 AND properties5 = ?d)', $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId); if ($lockIds) { // objects $lockedObj = new GameObjectList(array(['lockId', $lockIds])); if (!$lockedObj->error) { $this->lvTabs[] = array('file' => 'object', 'data' => $lockedObj->getListviewData(), 'params' => ['name' => '$LANG.tab_unlocks', 'id' => 'unlocks-object']); } // items (generally unused. It's the spell on the item, that unlocks stuff) $lockedItm = new ItemList(array(['lockId', $lockIds])); if (!$lockedItm->error) { $this->extendGlobalData($lockedItm->getJSGlobals(GLOBALINFO_SELF)); $this->lvTabs[] = array('file' => 'item', 'data' => $lockedItm->getListviewData(), 'params' => ['name' => '$LANG.tab_unlocks', 'id' => 'unlocks-item']); } } // tab: see also $conditions = array(['id', $this->typeId, '!'], ['OR', ['name_loc' . User::$localeId, $this->subject->getField('name', true)], ['AND', ['class', $_class], ['subClass', $_subClass], ['slot', $_slot], ['itemLevel', $this->subject->getField('itemLevel') - 15, '>'], ['itemLevel', $this->subject->getField('itemLevel') + 15, '<'], ['quality', $this->subject->getField('quality')], ['requiredClass', $this->subject->getField('requiredClass')]]]); $saItems = new ItemList($conditions); if (!$saItems->error) { $this->extendGlobalData($saItems->getJSGlobals(GLOBALINFO_SELF)); $this->lvTabs[] = array('file' => 'item', 'data' => $saItems->getListviewData(), 'params' => ['name' => '$LANG.tab_seealso', 'id' => 'see-also']); } // tab: starts (quest) if ($qId = $this->subject->getField('startQuest')) { $starts = new QuestList(array(['id', $qId])); if (!$starts->error) { $this->extendGlobalData($starts->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS)); $this->lvTabs[] = array('file' => 'quest', 'data' => $starts->getListviewData(), 'params' => ['name' => '$LANG.tab_starts', 'id' => 'starts-quest']); } } // tab: objective of (quest) $conditions = array('OR', ['reqItemId1', $this->typeId], ['reqItemId2', $this->typeId], ['reqItemId3', $this->typeId], ['reqItemId4', $this->typeId], ['reqItemId5', $this->typeId], ['reqItemId6', $this->typeId]); $objective = new QuestList($conditions); if (!$objective->error) { $this->extendGlobalData($objective->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS)); $this->lvTabs[] = array('file' => 'quest', 'data' => $objective->getListviewData(), 'params' => ['name' => '$LANG.tab_objectiveof', 'id' => 'objective-of-quest']); } // tab: provided for (quest) $conditions = array('OR', ['sourceItemId', $this->typeId], ['reqSourceItemId1', $this->typeId], ['reqSourceItemId2', $this->typeId], ['reqSourceItemId3', $this->typeId], ['reqSourceItemId4', $this->typeId]); $provided = new QuestList($conditions); if (!$provided->error) { $this->extendGlobalData($provided->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS)); $this->lvTabs[] = array('file' => 'quest', 'data' => $provided->getListviewData(), 'params' => ['name' => '$LANG.tab_providedfor', 'id' => 'provided-for-quest']); } // tab: same model as // todo (low): should also work for creatures summoned by item if (($model = $this->subject->getField('model')) && $_slot) { $sameModel = new ItemList(array(['model', $model], ['id', $this->typeId, '!'], ['slot', $_slot])); if (!$sameModel->error) { $this->extendGlobalData($sameModel->getJSGlobals(GLOBALINFO_SELF)); $this->lvTabs[] = array('file' => 'genericmodel', 'data' => $sameModel->getListviewData(ITEMINFO_MODEL), 'params' => ['name' => '$LANG.tab_samemodelas', 'id' => 'same-model-as', 'genericlinktype' => 'item']); } } // tab: sold by if (!empty($this->subject->getExtendedCost()[$this->subject->id])) { $vendors = $this->subject->getExtendedCost()[$this->subject->id]; $soldBy = new CreatureList(array(['id', array_keys($vendors)])); if (!$soldBy->error) { $sbData = $soldBy->getListviewData(); $this->extendGlobalData($soldBy->getJSGlobals(GLOBALINFO_SELF)); $extraCols = ['Listview.extraCols.stock', "Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')", 'Listview.extraCols.cost']; $holidays = []; foreach ($sbData as $k => &$row) { $currency = []; $tokens = []; foreach ($vendors[$k] as $id => $qty) { if (is_string($id)) { continue; } if ($id > 0) { $tokens[] = [$id, $qty]; } else { if ($id < 0) { $currency[] = [-$id, $qty]; } } } if ($currency) { $this->extendGlobalIds(TYPE_CURRENCY, array_column($currency, 0)); } if ($tokens) { $this->extendGlobalIds(TYPE_ITEM, array_column($tokens, 0)); } $row['stock'] = $vendors[$k]['stock']; $row['cost'] = [empty($vendors[$k][0]) ? 0 : $vendors[$k][0]]; if ($e = $vendors[$k]['event']) { if (count($extraCols) == 3) { $extraCols[] = 'Listview.extraCols.condition'; } $this->extendGlobalIds(TYPE_WORLDEVENT, $e); $row['condition'][0][$this->typeId][] = [[CND_ACTIVE_EVENT, $e]]; } if ($currency || $tokens) { // fill idx:3 if required $row['cost'][] = $currency; } if ($tokens) { $row['cost'][] = $tokens; } if ($x = $this->subject->getField('buyPrice')) { $row['buyprice'] = $x; } if ($x = $this->subject->getField('sellPrice')) { $row['sellprice'] = $x; } if ($x = $this->subject->getField('buyCount')) { $row['stack'] = $x; } } $this->lvTabs[] = array('file' => 'creature', 'data' => $sbData, 'params' => ['name' => '$LANG.tab_soldby', 'id' => 'sold-by-npc', 'extraCols' => '$[' . implode(', ', $extraCols) . ']', 'hiddenCols' => "\$['level', 'type']"]); } } // tab: currency for // some minor trickery: get arenaPoints(43307) and honorPoints(43308) directly if ($this->typeId == 43307) { $n = '?items&filter=cr=145;crs=1;crv=0'; $w = 'reqArenaPoints > 0'; } else { if ($this->typeId == 43308) { $n = '?items&filter=cr=144;crs=1;crv=0'; $w = 'reqHonorPoints > 0'; } else { $n = in_array($this->typeId, [42, 61, 81, 241, 121, 122, 123, 125, 126, 161, 201, 101, 102, 221, 301, 341]) ? '?items&filter=cr=158;crs=' . $this->typeId . ';crv=0' : null; $w = 'reqItemId1 = ' . $this->typeId . ' OR reqItemId2 = ' . $this->typeId . ' OR reqItemId3 = ' . $this->typeId . ' OR reqItemId4 = ' . $this->typeId . ' OR reqItemId5 = ' . $this->typeId; } } $xCosts = DB::Aowow()->selectCol('SELECT id FROM ?_itemextendedcost WHERE ' . $w); $boughtBy = $xCosts ? DB::World()->selectCol('SELECT item FROM npc_vendor WHERE extendedCost IN (?a) UNION SELECT item FROM game_event_npc_vendor WHERE extendedCost IN (?a)', $xCosts, $xCosts) : null; if ($boughtBy) { $boughtBy = new ItemList(array(['id', $boughtBy])); if (!$boughtBy->error) { if ($boughtBy->getMatches() <= CFG_SQL_LIMIT_DEFAULT) { $n = null; } $iCur = new CurrencyList(array(['itemId', $this->typeId])); $filter = $iCur->error ? [TYPE_ITEM => $this->typeId] : [TYPE_CURRENCY => $iCur->id]; $this->lvTabs[] = array('file' => 'item', 'data' => $boughtBy->getListviewData(ITEMINFO_VENDOR, $filter), 'params' => ['name' => '$LANG.tab_currencyfor', 'id' => 'currency-for', 'extraCols' => "\$[Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack'), Listview.extraCols.cost]", 'note' => $n ? sprintf(Util::$filterResultString, $n) : null]); $this->extendGlobalData($boughtBy->getJSGlobals(GLOBALINFO_ANY)); } } // tab: teaches $ids = $indirect = []; for ($i = 1; $i < 6; $i++) { if ($this->subject->getField('spellTrigger' . $i) == 6) { $ids[] = $this->subject->getField('spellId' . $i); } else { if ($this->subject->getField('spellTrigger' . $i) == 0 && $this->subject->getField('spellId' . $i) > 0) { $indirect[] = $this->subject->getField('spellId' . $i); } } } // taught indirectly if ($indirect) { $indirectSpells = new SpellList(array(['id', $indirect])); foreach ($indirectSpells->iterate() as $__) { if ($_ = $indirectSpells->canTeachSpell()) { foreach ($_ as $idx) { $ids[] = $indirectSpells->getField('effect' . $idx . 'TriggerSpell'); } } } $ids = array_merge($ids, Util::getTaughtSpells($indirect)); } if ($ids) { $taughtSpells = new SpellList(array(['id', $ids])); if (!$taughtSpells->error) { $this->extendGlobalData($taughtSpells->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED)); $visCols = ['level', 'schools']; if ($taughtSpells->hasSetFields(['reagent1'])) { $visCols[] = 'reagents'; } $this->lvTabs[] = array('file' => 'spell', 'data' => $taughtSpells->getListviewData(), 'params' => ['name' => '$LANG.tab_teaches', 'id' => 'teaches', 'visibleCols' => '$' . Util::toJSON($visCols)]); } } // tab: Shared cooldown $cdCats = []; for ($i = 1; $i < 6; $i++) { if ($this->subject->getField('spellId' . $i) > 0 && $this->subject->getField('spellCategory' . $i) > 0) { $cdCats[] = $this->subject->getField('spellCategory' . $i); } } if ($cdCats) { $conditions = array('OR', ['spellCategory1', $cdCats], ['spellCategory2', $cdCats], ['spellCategory3', $cdCats], ['spellCategory4', $cdCats], ['spellCategory5', $cdCats]); $cdItems = new ItemList($conditions); if (!$cdItems->error) { $this->lvTabs[] = array('file' => 'item', 'data' => $cdItems->getListviewData(), 'params' => ['name' => '$LANG.tab_sharedcooldown', 'id' => 'shared-cooldown']); $this->extendGlobalData($cdItems->getJSGlobals(GLOBALINFO_SELF)); } } // // todo - tab: taught by // use var $createdBy to find source of this spell // id: 'taught-by-X', // name: LANG.tab_taughtby }