mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
removing smarty - part V
- added ObjectPage and ObjectsPage - moved loot-related functions from Util to own class - moved template-related functions from Util to GenericPage - removed redundancies from user class - enabled cache (may need some tweaking but it finally works as it should) - some bugfixes
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,6 +1,6 @@
|
||||
# smarty cache
|
||||
/cache/*.tmp
|
||||
/cache/*.php
|
||||
# cache
|
||||
/cache/template/*
|
||||
/cache/alphaMaps/*.png
|
||||
|
||||
# generated files
|
||||
/static/js/profile_all.js
|
||||
|
||||
1
cache/data/index.html
vendored
1
cache/data/index.html
vendored
@@ -1 +0,0 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
||||
1
cache/images/index.html
vendored
1
cache/images/index.html
vendored
@@ -1 +0,0 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
||||
@@ -25,12 +25,11 @@ define('TYPE_RACE', 14);
|
||||
define('TYPE_SKILL', 15);
|
||||
define('TYPE_CURRENCY', 17);
|
||||
|
||||
define('CACHETYPE_PAGE', 0);
|
||||
define('CACHETYPE_TOOLTIP', 1);
|
||||
define('CACHETYPE_BUFF', 2); // only used by spells obviously
|
||||
define('CACHETYPE_NONE', 0); // page will not be cached
|
||||
define('CACHETYPE_PAGE', 1);
|
||||
define('CACHETYPE_TOOLTIP', 2);
|
||||
define('CACHETYPE_SEARCH', 3);
|
||||
define('CACHETYPE_XML', 4); // only used by items
|
||||
define('CACHETYPE_NONE', 5); // page will not be cached
|
||||
|
||||
define('SEARCH_TYPE_REGULAR', 0x10000000);
|
||||
define('SEARCH_TYPE_OPEN', 0x20000000);
|
||||
|
||||
@@ -7,13 +7,14 @@ if (!defined('AOWOW_REVISION'))
|
||||
trait DetailPage
|
||||
{
|
||||
protected $hasComContent = true;
|
||||
protected $category = null; // not used on detail pages
|
||||
|
||||
function generateCacheKey($cacheType, $params = '-1')
|
||||
private $subject = null; // so it will not get cached
|
||||
|
||||
function generateCacheKey()
|
||||
{
|
||||
$key = [$cacheType, $this->type, '-1', $params];
|
||||
|
||||
if ($this->isLocalized)
|
||||
$key[] = User::$localeId;
|
||||
// mode, type, typeId, localeId, category, filter
|
||||
$key = [$this->mode, $this->type, $this->typeId, User::$localeId, '-1', '-1'];
|
||||
|
||||
return implode('_', $key);
|
||||
}
|
||||
@@ -23,15 +24,19 @@ trait DetailPage
|
||||
trait ListPage
|
||||
{
|
||||
protected $category = null;
|
||||
protected $validCats = [];
|
||||
protected $typeId = 0;
|
||||
protected $filter = [];
|
||||
|
||||
function generateCacheKey($cacheType)
|
||||
function generateCacheKey()
|
||||
{
|
||||
$key = [$cacheType, $this->type, $this->typeId, '-1'];
|
||||
// mode, type, typeId, localeId,
|
||||
$key = [$this->mode, $this->type, '-1', User::$localeId];
|
||||
|
||||
if ($this->isLocalized)
|
||||
$key[] = User::$localeId;
|
||||
//category
|
||||
$key[] = $this->category ? implode('.', $this->category) : '-1';
|
||||
|
||||
// filter
|
||||
$key[] = $this->filter ? md5(serialize($this->filter)) : '-1';
|
||||
|
||||
return implode('_', $key);
|
||||
}
|
||||
@@ -42,24 +47,23 @@ class GenericPage
|
||||
{
|
||||
protected $tpl = '';
|
||||
protected $restrictedGroups = U_GROUP_NONE;
|
||||
protected $mode = CACHETYPE_NONE;
|
||||
|
||||
protected $jsGlobals = [];
|
||||
protected $jsgBuffer = [];
|
||||
protected $isCachable = true;
|
||||
protected $isLocalized = false;
|
||||
protected $hasCacheFile = false;
|
||||
protected $lvData = [];
|
||||
protected $title = [CFG_NAME]; // for title-Element
|
||||
protected $name = ''; // for h1-Element
|
||||
protected $tabId = 0;
|
||||
protected $community = ['co' => [], 'sc' => [], 'vi' => []];
|
||||
|
||||
protected $js = [];
|
||||
protected $css = [];
|
||||
|
||||
// private vars don't get cached
|
||||
private $cacheDir = 'cache/template/';
|
||||
private $jsgBuffer = [];
|
||||
private $gLocale = [];
|
||||
protected $gPageInfo = [];
|
||||
private $gPageInfo = [];
|
||||
private $gUser = [];
|
||||
private $community = ['co' => [], 'sc' => [], 'vi' => []];
|
||||
|
||||
protected function generatePath() {}
|
||||
protected function generateTitle() {}
|
||||
@@ -76,20 +80,25 @@ class GenericPage
|
||||
else if (CFG_MAINTENANCE && User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
Util::addNote(U_GROUP_EMPLOYEE, 'Maintenance mode enabled!');
|
||||
|
||||
if (isset($this->validCats) && !Util::isValidPage($this->validCats, $this->category))
|
||||
$this->error();
|
||||
// display modes
|
||||
if (isset($_GET['power']) && method_exists($this, 'generateTooltip'))
|
||||
$this->mode = CACHETYPE_TOOLTIP;
|
||||
else if (isset($_GET['xml']) && method_exists($this, 'generateXML'))
|
||||
$this->mode = CACHETYPE_XML;
|
||||
else
|
||||
{
|
||||
if (!$this->isValidPage() || !$this->tpl)
|
||||
$this->error();
|
||||
|
||||
$this->gUser = User::getUserGlobals();
|
||||
$this->gLocale = array(
|
||||
'id' => User::$localeId,
|
||||
'name' => User::$localeString
|
||||
);
|
||||
|
||||
if (!$this->tpl)
|
||||
return;
|
||||
$this->gUser = User::getUserGlobals();
|
||||
$this->gLocale = array(
|
||||
'id' => User::$localeId,
|
||||
'name' => User::$localeString
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function prepare()
|
||||
private function prepareContent()
|
||||
{
|
||||
if (!$this->loadCache())
|
||||
{
|
||||
@@ -113,15 +122,47 @@ class GenericPage
|
||||
|
||||
public function display($override = '')
|
||||
{
|
||||
if (!$override)
|
||||
$this->prepare();
|
||||
if ($override)
|
||||
{
|
||||
$this->addAnnouncements();
|
||||
|
||||
if (!$override && !$this->isSaneInclude('template/pages/', $this->tpl))
|
||||
die(User::isInGroup(U_GROUP_STAFF) ? 'Error: nonexistant template requestst: template/pages/'.$this->tpl.'.tpl.php' : null);
|
||||
include('template/pages/'.$override.'.tpl.php');
|
||||
die();
|
||||
}
|
||||
else if ($this->mode == CACHETYPE_TOOLTIP)
|
||||
{
|
||||
if (!$this->loadCache($tt))
|
||||
{
|
||||
$tt = $this->generateTooltip();
|
||||
$this->saveCache($tt);
|
||||
}
|
||||
|
||||
$this->addAnnouncements();
|
||||
header('Content-type: application/x-javascript; charsetUTF-8');
|
||||
die($tt);
|
||||
}
|
||||
else if ($this->mode == CACHETYPE_XML)
|
||||
{
|
||||
if (!$this->loadCache($xml))
|
||||
{
|
||||
$xml = $this->generateXML();
|
||||
$this->saveCache($xml);
|
||||
}
|
||||
|
||||
include('template/pages/'.($override ? $override : $this->tpl).'.tpl.php');
|
||||
header('Content-type: text/xml; charsetUTF-8');
|
||||
die($xml);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->prepareContent();
|
||||
|
||||
if (!$this->isSaneInclude('template/pages/', $this->tpl))
|
||||
die(User::isInGroup(U_GROUP_STAFF) ? 'Error: nonexistant template requested: template/pages/'.$this->tpl.'.tpl.php' : null);
|
||||
|
||||
$this->addAnnouncements();
|
||||
|
||||
include('template/pages/'.$this->tpl.'.tpl.php');
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
public function gBrick($file, array $localVars = [])
|
||||
@@ -130,7 +171,7 @@ class GenericPage
|
||||
$$n = $v;
|
||||
|
||||
if (!$this->isSaneInclude('template/globals/', $file))
|
||||
echo !User::isInGroup(U_GROUP_STAFF) ? "\n\nError: nonexistant template requestst: template/globals/".$file.".tpl.php\n\n" : null;
|
||||
echo !User::isInGroup(U_GROUP_STAFF) ? "\n\nError: nonexistant template requested: template/globals/".$file.".tpl.php\n\n" : null;
|
||||
else
|
||||
include('template/globals/'.$file.'.tpl.php');
|
||||
}
|
||||
@@ -141,7 +182,7 @@ class GenericPage
|
||||
$$n = $v;
|
||||
|
||||
if (!$this->isSaneInclude('template/bricks/', $file))
|
||||
echo User::isInGroup(U_GROUP_STAFF) ? "\n\nError: nonexistant template requestst: template/bricks/".$file.".tpl.php\n\n" : null;
|
||||
echo User::isInGroup(U_GROUP_STAFF) ? "\n\nError: nonexistant template requested: template/bricks/".$file.".tpl.php\n\n" : null;
|
||||
else
|
||||
include('template/bricks/'.$file.'.tpl.php');
|
||||
}
|
||||
@@ -152,7 +193,7 @@ class GenericPage
|
||||
$$n = $v;
|
||||
|
||||
if (!$this->isSaneInclude('template/listviews/', $file))
|
||||
echo User::isInGroup(U_GROUP_STAFF) ? "\n\nError: nonexistant template requestst: template/listviews/".$file.".tpl.php\n\n" : null;
|
||||
echo User::isInGroup(U_GROUP_STAFF) ? "\n\nError: nonexistant template requested: template/listviews/".$file.".tpl.php\n\n" : null;
|
||||
else
|
||||
include('template/listviews/'.$file.'.tpl.php');
|
||||
}
|
||||
@@ -168,6 +209,33 @@ class GenericPage
|
||||
return true;
|
||||
}
|
||||
|
||||
private function isValidPage()
|
||||
{
|
||||
if ($this->category === null || empty($this->validCats))
|
||||
return true;
|
||||
|
||||
switch (count($this->category))
|
||||
{
|
||||
case 0: // no params works always
|
||||
return true;
|
||||
case 1: // null is avalid || value in a 1-dim-array || key in a n-dim-array
|
||||
return $this->category[0] === null || in_array($this->category[0], $this->validCats) || (isset($this->validCats[$this->category[0]]) && is_array($this->validCats[$this->category[0]]));
|
||||
case 2: // first param has to be a key. otherwise invalid
|
||||
if (!isset($this->validCats[$this->category[0]]))
|
||||
return false;
|
||||
|
||||
// check if the sub-array is n-imensional
|
||||
if (count($this->validCats[$this->category[0]]) == count($this->validCats[$this->category[0]], COUNT_RECURSIVE))
|
||||
return in_array($this->category[1], $this->validCats[$this->category[0]]); // second param is value in second level array
|
||||
else
|
||||
return isset($this->validCats[$this->category[0]][$this->category[1]]); // check if params is key of another array
|
||||
case 3: // 3 params MUST point to a specific value
|
||||
return isset($this->validCats[$this->category[0]][$this->category[1]]) && in_array($this->category[2], $this->validCats[$this->category[0]][$this->category[1]]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addJS($name, $unshift = false)
|
||||
{
|
||||
if (is_array($name))
|
||||
@@ -395,10 +463,18 @@ class GenericPage
|
||||
|
||||
public function notFound($subject)
|
||||
{
|
||||
$this->subject = $subject;
|
||||
$this->mysql = DB::Aowow()->getStatistics();
|
||||
if ($this->mode == CACHETYPE_TOOLTIP)
|
||||
echo $this->generateTooltip(true);
|
||||
else if ($this->mode == CACHETYPE_XML)
|
||||
echo $this->generateXML(true);
|
||||
else
|
||||
{
|
||||
$this->subject = $subject;
|
||||
$this->mysql = DB::Aowow()->getStatistics();
|
||||
|
||||
$this->display('text-page-generic');
|
||||
}
|
||||
|
||||
$this->display('text-page-generic');
|
||||
exit();
|
||||
}
|
||||
|
||||
@@ -424,44 +500,76 @@ class GenericPage
|
||||
}
|
||||
|
||||
// creates the cache file
|
||||
public function saveCache(/*$key, $data, $filter = null*/)
|
||||
public function saveCache($saveString = null)
|
||||
{
|
||||
// if (CFG_DEBUG)
|
||||
if ($this->mode == CACHETYPE_NONE)
|
||||
return false;
|
||||
|
||||
if (CFG_DEBUG)
|
||||
return;
|
||||
|
||||
$file = $this->cache_dir.'data/'.$key;
|
||||
$file = CWD.$this->cacheDir.$this->generateCacheKey();
|
||||
$data = time()." ".AOWOW_REVISION." ".($saveString ? '1' : '0')."\n";
|
||||
if (!$saveString)
|
||||
{
|
||||
$cache = [];
|
||||
foreach ($this as $key => $val)
|
||||
{
|
||||
try
|
||||
{
|
||||
// public, protected and an undocumented flag added to properties created on the fly..?
|
||||
if ((new ReflectionProperty($this, $key))->getModifiers() & 0x1300)
|
||||
$cache[$key] = $val;
|
||||
}
|
||||
catch (ReflectionException $e) { } // shut up!
|
||||
}
|
||||
|
||||
$cacheData = time()." ".AOWOW_REVISION."\n";
|
||||
$cacheData .= serialize(str_replace(["\n", "\t"], ['\n', '\t'], $data));
|
||||
$data .= serialize($cache);
|
||||
}
|
||||
else
|
||||
$data .= (string)$saveString;
|
||||
|
||||
if ($filter)
|
||||
$cacheData .= "\n".serialize($filter);
|
||||
|
||||
file_put_contents($file, $cacheData);
|
||||
file_put_contents($file, $data);
|
||||
}
|
||||
|
||||
// loads and evaluates the cache file
|
||||
public function loadCache(/*$key, &$data, &$filter = null*/)
|
||||
public function loadCache(&$saveVar = null)
|
||||
{
|
||||
// if (CFG_DEBUG)
|
||||
if ($this->mode == CACHETYPE_NONE)
|
||||
return false;
|
||||
|
||||
$cache = @file_get_contents($this->cache_dir.'data/'.$key);
|
||||
if (CFG_DEBUG)
|
||||
return false;
|
||||
|
||||
$file = CWD.$this->cacheDir.$this->generateCacheKey();
|
||||
if (!file_exists($file))
|
||||
return false;
|
||||
|
||||
$cache = file_get_contents($file);
|
||||
if (!$cache)
|
||||
return false;
|
||||
|
||||
$cache = explode("\n", $cache);
|
||||
$cache = explode("\n", $cache, 2);
|
||||
|
||||
@list($time, $rev) = explode(' ', $cache[0]);
|
||||
$expireTime = $time + CFG_CACHE_DECAY;
|
||||
if ($expireTime <= time() || $rev < AOWOW_REVISION)
|
||||
@list($time, $rev, $type) = explode(' ', $cache[0]);
|
||||
if ($time + CFG_CACHE_DECAY <= time() || $rev < AOWOW_REVISION)
|
||||
return false;
|
||||
|
||||
$data = str_replace(['\n', '\t'], ["\n", "\t"], unserialize($cache[1]));
|
||||
if (isset($cache[2]))
|
||||
$filter = unserialize($cache[2]);
|
||||
if ($type == '0')
|
||||
{
|
||||
$data = unserialize($cache[1]);
|
||||
foreach ($data as $k => $v)
|
||||
$this->$k = $v;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
else if ($type == '1')
|
||||
{
|
||||
$saveVar = $cache[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
573
includes/loot.class.php
Normal file
573
includes/loot.class.php
Normal file
@@ -0,0 +1,573 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('invalid access');
|
||||
|
||||
|
||||
/* from TC wiki
|
||||
fishing_loot_template no relation entry is linked with ID of the fishing zone or area
|
||||
creature_loot_template entry many <- many creature_template lootid
|
||||
gameobject_loot_template entry many <- many gameobject_template data1 Only GO type 3 (CHEST) or 25 (FISHINGHOLE)
|
||||
item_loot_template entry many <- one item_template entry
|
||||
disenchant_loot_template entry many <- many item_template DisenchantID
|
||||
prospecting_loot_template entry many <- one item_template entry
|
||||
milling_loot_template entry many <- one item_template entry
|
||||
pickpocketing_loot_template entry many <- many creature_template pickpocketloot
|
||||
skinning_loot_template entry many <- many creature_template skinloot Can also store minable/herbable items gathered from creatures
|
||||
quest_mail_loot_template entry quest_template RewMailTemplateId
|
||||
reference_loot_template entry many <- many _loot_template -mincountOrRef In case of negative mincountOrRef
|
||||
*/
|
||||
|
||||
class Loot
|
||||
{
|
||||
public static $jsGlobals = [];
|
||||
public static $extraCols = [];
|
||||
|
||||
private static $results = [];
|
||||
private static $lootTemplates = array(
|
||||
LOOT_REFERENCE, // internal
|
||||
LOOT_ITEM, // item
|
||||
LOOT_DISENCHANT, // item
|
||||
LOOT_PROSPECTING, // item
|
||||
LOOT_MILLING, // item
|
||||
LOOT_CREATURE, // npc
|
||||
LOOT_PICKPOCKET, // npc
|
||||
LOOT_SKINNING, // npc (see its flags for mining, herbing or actual skinning)
|
||||
LOOT_FISHING, // zone
|
||||
LOOT_GAMEOBJECT, // object
|
||||
LOOT_MAIL, // quest || achievement
|
||||
LOOT_SPELL // spell
|
||||
);
|
||||
|
||||
public static function &iterate()
|
||||
{
|
||||
reset(self::$results);
|
||||
|
||||
while (list($k, $__) = each(self::$results))
|
||||
yield self::$results[$k];
|
||||
}
|
||||
|
||||
public static function getResult()
|
||||
{
|
||||
return self::$results;
|
||||
}
|
||||
|
||||
private static function createStack($l) // issue: TC always has an equal distribution between min/max
|
||||
{
|
||||
if (empty($l['min']) || empty($l['max']) || $l['min'] <= $l['max'])
|
||||
return null;
|
||||
|
||||
$stack = [];
|
||||
for ($i = $l['min']; $i <= $l['max']; $i++)
|
||||
$stack[$i] = round(100 / (1 + $l['max'] - $l['min']), 3);
|
||||
|
||||
// yes, it wants a string .. how weired is that..
|
||||
return json_encode($stack, JSON_NUMERIC_CHECK);
|
||||
}
|
||||
|
||||
private static function getByItemIdRecursive($tableName, $lootId, &$handledRefs, $groupId = 0, $baseChance = 1.0)
|
||||
{
|
||||
$loot = [];
|
||||
$rawItems = [];
|
||||
|
||||
if (!$tableName || !$lootId)
|
||||
return null;
|
||||
|
||||
$rows = DB::Aowow()->select('SELECT * FROM ?# WHERE entry = ?d{ AND groupid = ?d}', $tableName, abs($lootId), $groupId ? $groupId : DBSIMPLE_SKIP);
|
||||
if (!$rows)
|
||||
return null;
|
||||
|
||||
$groupChances = [];
|
||||
$nGroupEquals = [];
|
||||
foreach ($rows as $entry)
|
||||
{
|
||||
$set = array(
|
||||
'quest' => $entry['ChanceOrQuestChance'] < 0,
|
||||
'group' => $entry['groupid'],
|
||||
'reference' => $lootId < 0 ? abs($lootId) : 0,
|
||||
'realChanceMod' => $baseChance
|
||||
);
|
||||
|
||||
// if ($entry['lootmode'] > 1)
|
||||
// {
|
||||
$buff = [];
|
||||
for ($i = 0; $i < 8; $i++)
|
||||
if ($entry['lootmode'] & (1 << $i))
|
||||
$buff[] = $i + 1;
|
||||
|
||||
$set['mode'] = implode(', ', $buff);
|
||||
// }
|
||||
// else
|
||||
// $set['mode'] = 0;
|
||||
|
||||
/*
|
||||
modes:{"mode":8,"4":{"count":7173,"outof":17619},"8":{"count":7173,"outof":10684}}
|
||||
ignore lootmodes from sharedDefines.h use different creatures/GOs from each template
|
||||
modes.mode = b6543210
|
||||
||||||'dungeon heroic
|
||||
|||||'dungeon normal
|
||||
||||'<empty>
|
||||
|||'10man normal
|
||||
||'25man normal
|
||||
|'10man heroic
|
||||
'25man heroic
|
||||
*/
|
||||
|
||||
if ($entry['mincountOrRef'] < 0)
|
||||
{
|
||||
// bandaid.. remove when propperly handling lootmodes
|
||||
if (!in_array($entry['mincountOrRef'], $handledRefs))
|
||||
{ // todo (high): find out, why i used this in the first place. (don't do drugs, kids)
|
||||
list($data, $raw) = self::getByItemIdRecursive(LOOT_REFERENCE, $entry['mincountOrRef'], $handledRefs, /*$entry['groupid'],*/ 0, abs($entry['ChanceOrQuestChance'] / 100));
|
||||
|
||||
$handledRefs[] = $entry['mincountOrRef'];
|
||||
|
||||
$loot = array_merge($loot, $data);
|
||||
$rawItems = array_merge($rawItems, $raw);
|
||||
}
|
||||
|
||||
$set['content'] = $entry['mincountOrRef'];
|
||||
$set['multiplier'] = $entry['maxcount'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$rawItems[] = $entry['item'];
|
||||
$set['content'] = $entry['item'];
|
||||
$set['min'] = $entry['mincountOrRef'];
|
||||
$set['max'] = $entry['maxcount'];
|
||||
}
|
||||
|
||||
if (!isset($groupChances[$entry['groupid']]))
|
||||
{
|
||||
$groupChances[$entry['groupid']] = 0;
|
||||
$nGroupEquals[$entry['groupid']] = 0;
|
||||
}
|
||||
|
||||
if ($set['quest'] || !$set['group'])
|
||||
$set['groupChance'] = abs($entry['ChanceOrQuestChance']);
|
||||
else if ($entry['groupid'] && !$entry['ChanceOrQuestChance'])
|
||||
{
|
||||
$nGroupEquals[$entry['groupid']]++;
|
||||
$set['groupChance'] = &$groupChances[$entry['groupid']];
|
||||
}
|
||||
else if ($entry['groupid'] && $entry['ChanceOrQuestChance'])
|
||||
{
|
||||
@$groupChances[$entry['groupid']] += $entry['ChanceOrQuestChance'];
|
||||
$set['groupChance'] = abs($entry['ChanceOrQuestChance']);
|
||||
}
|
||||
else // shouldn't have happened
|
||||
{
|
||||
self::addNote(U_GROUP_EMPLOYEE, 'Loot::getByItemIdRecursive: unhandled case in calculating chance for item '.$entry['item'].'!');
|
||||
continue;
|
||||
}
|
||||
|
||||
$loot[] = $set;
|
||||
}
|
||||
|
||||
foreach (array_keys($nGroupEquals) as $k)
|
||||
{
|
||||
$sum = $groupChances[$k];
|
||||
if (!$sum)
|
||||
$sum = 0;
|
||||
else if ($sum > 100)
|
||||
{
|
||||
self::addNote(U_GROUP_EMPLOYEE, 'Loot::getByItemIdRecursive: entry '.$lootId.' / group '.$k.' has a total chance of '.number_format($sum, 2).'%. Some items cannot drop!');
|
||||
$sum = 100;
|
||||
}
|
||||
|
||||
$cnt = empty($nGroupEquals[$k]) ? 1 : $nGroupEquals[$k];
|
||||
|
||||
$groupChances[$k] = (100 - $sum) / $cnt; // is applied as backReference to items with 0-chance
|
||||
}
|
||||
|
||||
return [$loot, array_unique($rawItems)];
|
||||
}
|
||||
|
||||
public static function getByContainer($table, $entry)
|
||||
{
|
||||
$loot = null;
|
||||
|
||||
if (!$table || !$entry)
|
||||
return null;
|
||||
|
||||
/*
|
||||
todo (high): implement conditions on loot (and conditions in general)
|
||||
|
||||
also
|
||||
|
||||
// if (is_array($entry) && in_array($table, [LOOT_CREATURE, LOOT_GAMEOBJECT])
|
||||
// iterate over the 4 available difficulties and assign modes
|
||||
|
||||
|
||||
modes:{"mode":1,"1":{"count":4408,"outof":16013},"4":{"count":4408,"outof":22531}}
|
||||
*/
|
||||
$handledRefs = [];
|
||||
$struct = self::getByItemIdRecursive($table, $entry, $handledRefs);
|
||||
if (!$struct)
|
||||
return false;
|
||||
|
||||
$items = new ItemList(array(['i.id', $struct[1]], CFG_SQL_LIMIT_NONE));
|
||||
self::$jsGlobals = $items->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED);
|
||||
$foo = $items->getListviewData();
|
||||
|
||||
// assign listview LV rows to loot rows, not the other way round! The same item may be contained multiple times
|
||||
foreach ($struct[0] as $loot)
|
||||
{
|
||||
$base = array(
|
||||
'percent' => round($loot['groupChance'] * $loot['realChanceMod'], 3),
|
||||
'group' => $loot['group'],
|
||||
'quest' => $loot['quest'],
|
||||
'count' => 1 // satisfies the sort-script
|
||||
);
|
||||
|
||||
if ($_ = $loot['mode'])
|
||||
$base['mode'] = $_;
|
||||
|
||||
if ($_ = $loot['reference'])
|
||||
$base['reference'] = $_;
|
||||
|
||||
if ($_ = self::createStack($loot))
|
||||
$base['pctstack'] = $_;
|
||||
|
||||
if ($loot['content'] > 0) // regular drop
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_STAFF))
|
||||
{
|
||||
if (!isset(self::$results[$loot['content']]))
|
||||
self::$results[$loot['content']] = array_merge($foo[$loot['content']], $base, ['stack' => [$loot['min'], $loot['max']]]);
|
||||
else
|
||||
self::$results[$loot['content']]['percent'] += $base['percent'];
|
||||
}
|
||||
else // in case of limited trash loot, check if $foo[<itemId>] exists
|
||||
self::$results[] = array_merge($foo[$loot['content']], $base, ['stack' => [$loot['min'], $loot['max']]]);
|
||||
}
|
||||
else if (User::isInGroup(U_GROUP_STAFF)) // create dummy for ref-drop
|
||||
{
|
||||
$data = array(
|
||||
'id' => $loot['content'],
|
||||
'name' => '@REFERENCE: '.abs($loot['content']),
|
||||
'icon' => 'trade_engineering',
|
||||
'stack' => [$loot['multiplier'], $loot['multiplier']]
|
||||
);
|
||||
self::$results[] = array_merge($base, $data);
|
||||
|
||||
self::$jsGlobals[TYPE_ITEM][$loot['content']] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
// move excessive % to extra loot
|
||||
if (!User::isInGroup(U_GROUP_STAFF))
|
||||
{
|
||||
foreach (self::$results as &$_)
|
||||
{
|
||||
if ($_['percent'] <= 100)
|
||||
continue;
|
||||
|
||||
while ($_['percent'] > 200)
|
||||
{
|
||||
$_['stack'][0]++;
|
||||
$_['stack'][1]++;
|
||||
$_['percent'] -= 100;
|
||||
}
|
||||
|
||||
$_['stack'][1]++;
|
||||
$_['percent'] = 100;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$fields = ['mode', 'reference'];
|
||||
$base = [];
|
||||
$set = 0;
|
||||
foreach (self::$results as $foo)
|
||||
{
|
||||
foreach ($fields as $idx => $field)
|
||||
{
|
||||
if (!isset($base[$idx]))
|
||||
$base[$idx] = @$foo[$field];
|
||||
else if ($base[$idx] != @$foo[$field])
|
||||
$set |= 1 << $idx;
|
||||
}
|
||||
|
||||
if ($set == (pow(2, count($fields)) - 1))
|
||||
break;
|
||||
}
|
||||
|
||||
self::$extraCols[] = "Listview.funcBox.createSimpleCol('group', 'Group', '7%', 'group')";
|
||||
foreach ($fields as $idx => $field)
|
||||
if ($set & (1 << $idx))
|
||||
self::$extraCols[] = "Listview.funcBox.createSimpleCol('".$field."', '".Util::ucFirst($field)."', '7%', '".$field."')";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getByItem($itemId, $maxResults = CFG_SQL_LIMIT_DEFAULT)
|
||||
{
|
||||
if (!$itemId)
|
||||
return [];
|
||||
|
||||
// [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-achievemnt', [], [], []]
|
||||
);
|
||||
$refResults = [];
|
||||
$chanceMods = [];
|
||||
$query = 'SELECT
|
||||
-lt1.entry AS ARRAY_KEY,
|
||||
IF(lt1.mincountOrRef > 0, lt1.item, lt1.mincountOrRef) AS item,
|
||||
lt1.ChanceOrQuestChance AS chance,
|
||||
SUM(IF(lt2.ChanceOrQuestChance = 0, 1, 0)) AS nZeroItems,
|
||||
SUM(IF(lt2.ChanceOrQuestChance > 0, lt2.ChanceOrQuestChance, 0)) AS sumChance,
|
||||
IF(lt1.groupid > 0, 1, 0) AS isGrouped,
|
||||
IF(lt1.mincountOrRef > 0, lt1.mincountOrRef, 1) AS min,
|
||||
IF(lt1.mincountOrRef > 0, lt1.maxcount, 1) AS max,
|
||||
IF(lt1.mincountOrRef < 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';
|
||||
|
||||
$calcChance = function ($refs, $parents = []) use (&$chanceMods)
|
||||
{
|
||||
$retData = [];
|
||||
$retKeys = [];
|
||||
|
||||
foreach ($refs as $rId => $ref)
|
||||
{
|
||||
// check for possible database inconsistencies
|
||||
if (!$ref['chance'] && !$ref['isGrouped'])
|
||||
self::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: ungrouped Item/Ref '.$ref['item'].' has 0% chance assigned!');
|
||||
|
||||
if ($ref['isGrouped'] && $ref['sumChance'] > 100)
|
||||
self::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: group with Item/Ref '.$ref['item'].' has '.number_format($ref['sumChance'], 2).'% total chance! Some items cannot drop!');
|
||||
|
||||
if ($ref['isGrouped'] && $ref['sumChance'] == 100 && !$ref['chance'])
|
||||
self::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: Item/Ref '.$ref['item'].' with adaptive chance cannot drop. Group already at 100%!');
|
||||
|
||||
$chance = abs($ref['chance'] ? $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 // ..and one for the sort script
|
||||
);
|
||||
|
||||
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::Aowow()->select(
|
||||
sprintf($query, 'lt1.item = ?d AND lt1.mincountOrRef > 0'),
|
||||
LOOT_REFERENCE, LOOT_REFERENCE,
|
||||
$itemId
|
||||
);
|
||||
|
||||
while ($newRefs)
|
||||
{
|
||||
$curRefs = $newRefs;
|
||||
$newRefs = DB::Aowow()->select(
|
||||
sprintf($query, 'lt1.mincountOrRef 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(self::$lootTemplates); $i++)
|
||||
{
|
||||
$result = $calcChance(DB::Aowow()->select(
|
||||
sprintf($query, '{lt1.mincountOrRef IN (?a) OR }(lt1.mincountOrRef > 0 AND lt1.item = ?d)'),
|
||||
self::$lootTemplates[$i], self::$lootTemplates[$i],
|
||||
$refResults ? array_keys($refResults) : DBSIMPLE_SKIP,
|
||||
$itemId
|
||||
));
|
||||
|
||||
// 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 (self::$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
|
||||
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
|
||||
case LOOT_GAMEOBJECT:
|
||||
if (!$ids)
|
||||
break;
|
||||
|
||||
$srcObj = new GameObjectList(array(['lootId', $ids]));
|
||||
if ($srcObj->error)
|
||||
break;
|
||||
|
||||
$srcData = $srcObj->getListviewData();
|
||||
|
||||
foreach ($srcObj->iterate() as $curTpl)
|
||||
{
|
||||
switch ($curTpl['type'])
|
||||
{
|
||||
case 25: $tabId = 15; break; // fishing node
|
||||
case -3: $tabId = 14; break; // herb
|
||||
case -4: $tabId = 13; break; // 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';
|
||||
}
|
||||
break;
|
||||
case LOOT_MAIL:
|
||||
$conditions = array(['rewardChoiceItemId1', $itemId], ['rewardChoiceItemId2', $itemId], ['rewardChoiceItemId3', $itemId], ['rewardChoiceItemId4', $itemId], ['rewardChoiceItemId5', $itemId],
|
||||
['rewardChoiceItemId6', $itemId], ['rewardItemId1', $itemId], ['rewardItemId2', $itemId], ['rewardItemId3', $itemId], ['rewardItemId4', $itemId],
|
||||
'OR');
|
||||
if ($ids)
|
||||
$conditions[] = ['rewardMailTemplateId', $ids];
|
||||
|
||||
$srcObj = new QuestList($conditions);
|
||||
if (!$srcObj->error)
|
||||
{
|
||||
$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]);
|
||||
}
|
||||
|
||||
/*
|
||||
todo: search for achievements here
|
||||
$tabsFinal[17]
|
||||
*/
|
||||
|
||||
break;
|
||||
case LOOT_SPELL:
|
||||
$conditions = ['OR', ['effect1CreateItemId', $itemId], ['effect2CreateItemId', $itemId], ['effect3CreateItemId', $itemId]];
|
||||
if ($ids)
|
||||
$conditions[] = ['id', $ids];
|
||||
|
||||
$srcObj = new SpellList($conditions);
|
||||
if (!$srcObj->error)
|
||||
{
|
||||
$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]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$ids)
|
||||
continue;
|
||||
|
||||
switch ($tabsFinal[abs($tabId)][0])
|
||||
{
|
||||
case 'creature': // new CreatureList
|
||||
case 'item': // new ItemList
|
||||
case 'zone': // new ZoneList
|
||||
$oName = ucFirst($tabsFinal[abs($tabId)][0]).'List';
|
||||
$srcObj = new $oName(array([$field, $ids]));
|
||||
if (!$srcObj->error)
|
||||
{
|
||||
$srcObj->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED);
|
||||
$srcData = $srcObj->getListviewData();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return $tabsFinal;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -149,8 +149,6 @@ class User
|
||||
{
|
||||
self::$localeId = isset(Util::$localeStrings[$use]) ? $use : 0;
|
||||
self::$localeString = self::localeString(self::$localeId);
|
||||
|
||||
Lang::load(self::$localeString);
|
||||
}
|
||||
|
||||
public static function isInGroup($group)
|
||||
@@ -269,16 +267,16 @@ class User
|
||||
return $set;
|
||||
|
||||
if ($_ = self::getCharacters())
|
||||
$subSet['characters'] = json_encode($_, JSON_NUMERIC_CHECK);
|
||||
$subSet['characters'] = $_;
|
||||
|
||||
if ($_ = self::getProfiles())
|
||||
$subSet['profiles'] = json_encode($_, JSON_NUMERIC_CHECK);
|
||||
$subSet['profiles'] = $_;
|
||||
|
||||
if ($_ = self::getWeightScales())
|
||||
$subSet['weightscales'] = json_encode($_, JSON_NUMERIC_CHECK);
|
||||
$subSet['weightscales'] = $_;
|
||||
|
||||
if ($_ = self::getCookies())
|
||||
$subSet['cookies'] = json_encode($_, JSON_NUMERIC_CHECK);
|
||||
$subSet['cookies'] = $_;
|
||||
|
||||
return array_merge($set, $subSet);
|
||||
}
|
||||
@@ -335,7 +333,7 @@ class User
|
||||
);
|
||||
}
|
||||
|
||||
return $asJSON ? json_encode(self::$characters, JSON_NUMERIC_CHECK) : self::$characters;
|
||||
return self::$characters;
|
||||
}
|
||||
|
||||
public static function getProfiles($asJSON = true)
|
||||
@@ -350,7 +348,7 @@ class User
|
||||
);
|
||||
}
|
||||
|
||||
return $asJSON ? json_encode(self::$profiles, JSON_NUMERIC_CHECK) : self::$profiles;
|
||||
return self::$profiles;
|
||||
}
|
||||
|
||||
public static function getCookies()
|
||||
@@ -360,7 +358,7 @@ class User
|
||||
if (self::$id)
|
||||
$data = DB::Aowow()->selectCol('SELECT name AS ARRAY_KEY, data FROM ?_account_cookies WHERE userId = ?d', self::$id);
|
||||
|
||||
return json_encode($data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function writeCookie()
|
||||
|
||||
@@ -198,21 +198,6 @@ class Util
|
||||
null, 1.0, 0.6, 1.0, 0.8, 1.0, 1.0, 1.2, 1.25, 1.44, 2.5, 1.728, 3.0, 0.0, 0.0, 1.2, 1.25
|
||||
);
|
||||
|
||||
public static $lootTemplates = array(
|
||||
LOOT_REFERENCE, // internal
|
||||
LOOT_ITEM, // item
|
||||
LOOT_DISENCHANT, // item
|
||||
LOOT_PROSPECTING, // item
|
||||
LOOT_MILLING, // item
|
||||
LOOT_CREATURE, // npc
|
||||
LOOT_PICKPOCKET, // npc
|
||||
LOOT_SKINNING, // npc (see its flags for mining, herbing or actual skinning)
|
||||
LOOT_FISHING, // zone
|
||||
LOOT_GAMEOBJECT, // object
|
||||
LOOT_MAIL, // quest || achievement
|
||||
LOOT_SPELL // spell
|
||||
);
|
||||
|
||||
// todo: translate and move to Lang
|
||||
public static $spellEffectStrings = array(
|
||||
0 => 'None',
|
||||
@@ -979,6 +964,19 @@ class Util
|
||||
return 'b'.strToUpper($_);
|
||||
}
|
||||
|
||||
public static function htmlEscape($data)
|
||||
{
|
||||
if (is_array($data))
|
||||
{
|
||||
foreach ($data as &$v)
|
||||
$v = self::htmlEscape($v);
|
||||
|
||||
return $data;
|
||||
}
|
||||
else
|
||||
return htmlspecialchars(trim($data), ENT_QUOTES, 'utf-8');
|
||||
}
|
||||
|
||||
public static function jsEscape($data)
|
||||
{
|
||||
if (is_array($data))
|
||||
@@ -1203,30 +1201,6 @@ class Util
|
||||
return $return;
|
||||
}
|
||||
|
||||
public static function isValidPage($struct, $keys)
|
||||
{
|
||||
switch (count($keys))
|
||||
{
|
||||
case 0: // no params works always
|
||||
return true;
|
||||
case 1: // null is avalid || value in a 1-dim-array || key in a n-dim-array
|
||||
return $keys[0] === null || in_array($keys[0], $struct) || (isset($struct[$keys[0]]));
|
||||
case 2: // first param has to be a key. otherwise invalid
|
||||
if (!isset($struct[$keys[0]]))
|
||||
return false;
|
||||
|
||||
// check if the sub-array is n-imensional
|
||||
if (count($struct[$keys[0]]) == count($struct[$keys[0]], COUNT_RECURSIVE))
|
||||
return in_array($keys[1], $struct[$keys[0]]); // second param is value in second level array
|
||||
else
|
||||
return isset($struct[$keys[0]][$keys[1]]); // check if params is key of another array
|
||||
case 3: // 3 params MUST point to a specific value
|
||||
return isset($struct[$keys[0]][$keys[1]]) && in_array($keys[2], $struct[$keys[0]][$keys[1]]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// default ucFirst doesn't convert UTF-8 chars
|
||||
public static function ucFirst($str)
|
||||
{
|
||||
@@ -1336,538 +1310,6 @@ class Util
|
||||
return $data;
|
||||
}
|
||||
|
||||
/* todo (xxx): loot is extremly uncreative, messy, incomplete and uncreative
|
||||
the type-lookups in particular should be separated in a way the template can access the required jsGloblas
|
||||
*/
|
||||
|
||||
/* from TC wiki
|
||||
fishing_loot_template no relation entry is linked with ID of the fishing zone or area
|
||||
creature_loot_template entry many <- many creature_template lootid
|
||||
gameobject_loot_template entry many <- many gameobject_template data1 Only GO type 3 (CHEST) or 25 (FISHINGHOLE)
|
||||
item_loot_template entry many <- one item_template entry
|
||||
disenchant_loot_template entry many <- many item_template DisenchantID
|
||||
prospecting_loot_template entry many <- one item_template entry
|
||||
milling_loot_template entry many <- one item_template entry
|
||||
pickpocketing_loot_template entry many <- many creature_template pickpocketloot
|
||||
skinning_loot_template entry many <- many creature_template skinloot Can also store minable/herbable items gathered from creatures
|
||||
quest_mail_loot_template entry quest_template RewMailTemplateId
|
||||
reference_loot_template entry many <- many _loot_template -mincountOrRef In case of negative mincountOrRef
|
||||
*/
|
||||
private static function getLootByEntry($tableName, $lootId, &$handledRefs, $groupId = 0, $baseChance = 1.0)
|
||||
{
|
||||
$loot = [];
|
||||
$rawItems = [];
|
||||
|
||||
if (!$tableName || !$lootId)
|
||||
return null;
|
||||
|
||||
$rows = DB::Aowow()->select('SELECT * FROM ?# WHERE entry = ?d{ AND groupid = ?d}', $tableName, abs($lootId), $groupId ? $groupId : DBSIMPLE_SKIP);
|
||||
if (!$rows)
|
||||
return null;
|
||||
|
||||
$groupChances = [];
|
||||
$nGroupEquals = [];
|
||||
foreach ($rows as $entry)
|
||||
{
|
||||
$set = array(
|
||||
'quest' => $entry['ChanceOrQuestChance'] < 0,
|
||||
'group' => $entry['groupid'],
|
||||
'reference' => $lootId < 0 ? abs($lootId) : 0,
|
||||
'realChanceMod' => $baseChance
|
||||
);
|
||||
|
||||
// if ($entry['lootmode'] > 1)
|
||||
// {
|
||||
$buff = [];
|
||||
for ($i = 0; $i < 8; $i++)
|
||||
if ($entry['lootmode'] & (1 << $i))
|
||||
$buff[] = $i + 1;
|
||||
|
||||
$set['mode'] = implode(', ', $buff);
|
||||
// }
|
||||
// else
|
||||
// $set['mode'] = 0;
|
||||
|
||||
/*
|
||||
modes:{"mode":8,"4":{"count":7173,"outof":17619},"8":{"count":7173,"outof":10684}}
|
||||
ignore lootmodes from sharedDefines.h use different creatures/GOs from each template
|
||||
modes.mode = b6543210
|
||||
||||||'dungeon heroic
|
||||
|||||'dungeon normal
|
||||
||||'<empty>
|
||||
|||'10man normal
|
||||
||'25man normal
|
||||
|'10man heroic
|
||||
'25man heroic
|
||||
*/
|
||||
|
||||
if ($entry['mincountOrRef'] < 0)
|
||||
{
|
||||
// bandaid.. remove when propperly handling lootmodes
|
||||
if (!in_array($entry['mincountOrRef'], $handledRefs))
|
||||
{ // todo (high): find out, why i used this in the first place. (don't do drugs, kids)
|
||||
list($data, $raw) = self::getLootByEntry(LOOT_REFERENCE, $entry['mincountOrRef'], $handledRefs, /*$entry['groupid'],*/ 0, abs($entry['ChanceOrQuestChance'] / 100));
|
||||
|
||||
$handledRefs[] = $entry['mincountOrRef'];
|
||||
|
||||
$loot = array_merge($loot, $data);
|
||||
$rawItems = array_merge($rawItems, $raw);
|
||||
}
|
||||
|
||||
$set['content'] = $entry['mincountOrRef'];
|
||||
$set['multiplier'] = $entry['maxcount'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$rawItems[] = $entry['item'];
|
||||
$set['content'] = $entry['item'];
|
||||
$set['min'] = $entry['mincountOrRef'];
|
||||
$set['max'] = $entry['maxcount'];
|
||||
}
|
||||
|
||||
if (!isset($groupChances[$entry['groupid']]))
|
||||
{
|
||||
$groupChances[$entry['groupid']] = 0;
|
||||
$nGroupEquals[$entry['groupid']] = 0;
|
||||
}
|
||||
|
||||
if ($set['quest'] || !$set['group'])
|
||||
$set['groupChance'] = abs($entry['ChanceOrQuestChance']);
|
||||
else if ($entry['groupid'] && !$entry['ChanceOrQuestChance'])
|
||||
{
|
||||
$nGroupEquals[$entry['groupid']]++;
|
||||
$set['groupChance'] = &$groupChances[$entry['groupid']];
|
||||
}
|
||||
else if ($entry['groupid'] && $entry['ChanceOrQuestChance'])
|
||||
{
|
||||
@$groupChances[$entry['groupid']] += $entry['ChanceOrQuestChance'];
|
||||
$set['groupChance'] = abs($entry['ChanceOrQuestChance']);
|
||||
}
|
||||
else // shouldn't have happened
|
||||
{
|
||||
self::addNote(U_GROUP_EMPLOYEE, 'Loot by LootId: unhandled case in calculating chance for item '.$entry['item'].'!');
|
||||
continue;
|
||||
}
|
||||
|
||||
$loot[] = $set;
|
||||
}
|
||||
|
||||
foreach (array_keys($nGroupEquals) as $k)
|
||||
{
|
||||
$sum = $groupChances[$k];
|
||||
if (!$sum)
|
||||
$sum = 0;
|
||||
else if ($sum > 100)
|
||||
{
|
||||
self::addNote(U_GROUP_EMPLOYEE, 'Loot by LootId: entry '.$lootId.' / group '.$k.' has a total chance of '.number_format($sum, 2).'%. Some items cannot drop!');
|
||||
$sum = 100;
|
||||
}
|
||||
|
||||
$cnt = empty($nGroupEquals[$k]) ? 1 : $nGroupEquals[$k];
|
||||
|
||||
$groupChances[$k] = (100 - $sum) / $cnt; // is applied as backReference to items with 0-chance
|
||||
}
|
||||
|
||||
return [$loot, array_unique($rawItems)];
|
||||
}
|
||||
|
||||
public static function handleLoot($table, $entry, $debug = false, &$debugCols = [])
|
||||
{
|
||||
$lv = [];
|
||||
$loot = null;
|
||||
|
||||
if (!$table || !$entry)
|
||||
return null;
|
||||
|
||||
/*
|
||||
todo (high): implement conditions on loot (and conditions in general)
|
||||
|
||||
also
|
||||
|
||||
// if (is_array($entry) && in_array($table, [LOOT_CREATURE, LOOT_GAMEOBJECT])
|
||||
// iterate over the 4 available difficulties and assign modes
|
||||
|
||||
|
||||
modes:{"mode":1,"1":{"count":4408,"outof":16013},"4":{"count":4408,"outof":22531}}
|
||||
*/
|
||||
$handledRefs = [];
|
||||
$struct = self::getLootByEntry($table, $entry, $handledRefs);
|
||||
if (!$struct)
|
||||
return $lv;
|
||||
|
||||
$items = new ItemList(array(['i.id', $struct[1]], CFG_SQL_LIMIT_NONE));
|
||||
$items->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED);
|
||||
$foo = $items->getListviewData();
|
||||
|
||||
// assign listview LV rows to loot rows, not the other way round! The same item may be contained multiple times
|
||||
foreach ($struct[0] as $loot)
|
||||
{
|
||||
$base = array(
|
||||
'percent' => round($loot['groupChance'] * $loot['realChanceMod'], 3),
|
||||
'group' => $loot['group'],
|
||||
'quest' => $loot['quest'],
|
||||
'count' => 1 // satisfies the sort-script
|
||||
);
|
||||
|
||||
if ($_ = $loot['mode'])
|
||||
$base['mode'] = $_;
|
||||
|
||||
if ($_ = $loot['reference'])
|
||||
$base['reference'] = $_;
|
||||
|
||||
$stack = []; // equal distribution between min/max .. not blizzlike, but hey, TC-issue
|
||||
if (isset($loot['max']) && isset($loot['min']) && ($loot['max'] > $loot['min']))
|
||||
for ($i = $loot['min']; $i <= $loot['max']; $i++)
|
||||
$stack[$i] = round(100 / (1 + $loot['max'] - $loot['min']), 3);
|
||||
|
||||
if ($stack) // yes, it wants a string .. how weired is that..
|
||||
$base['pctstack'] = json_encode($stack, JSON_NUMERIC_CHECK);
|
||||
|
||||
if ($loot['content'] > 0) // regular drop
|
||||
{
|
||||
if (!$debug)
|
||||
{
|
||||
if (!isset($lv[$loot['content']]))
|
||||
$lv[$loot['content']] = array_merge($foo[$loot['content']], $base, ['stack' => [$loot['min'], $loot['max']]]);
|
||||
else
|
||||
$lv[$loot['content']]['percent'] += $base['percent'];
|
||||
}
|
||||
else // in case of limited trash loot, check if $foo[<itemId>] exists
|
||||
$lv[] = array_merge($foo[$loot['content']], $base, ['stack' => [$loot['min'], $loot['max']]]);
|
||||
}
|
||||
else if ($debug) // create dummy for ref-drop
|
||||
{
|
||||
$data = array(
|
||||
'id' => $loot['content'],
|
||||
'name' => '@REFERENCE: '.abs($loot['content']),
|
||||
'icon' => 'trade_engineering',
|
||||
'stack' => [$loot['multiplier'], $loot['multiplier']]
|
||||
);
|
||||
$lv[] = array_merge($base, $data);
|
||||
|
||||
Util::$pageTemplate->extendGlobalData(TYPE_ITEM, [$loot['content'] => $data]);
|
||||
}
|
||||
}
|
||||
|
||||
// move excessive % to extra loot
|
||||
if (!$debug)
|
||||
{
|
||||
foreach ($lv as &$_)
|
||||
{
|
||||
if ($_['percent'] <= 100)
|
||||
continue;
|
||||
|
||||
while ($_['percent'] > 200)
|
||||
{
|
||||
$_['stack'][0]++;
|
||||
$_['stack'][1]++;
|
||||
$_['percent'] -= 100;
|
||||
}
|
||||
|
||||
$_['stack'][1]++;
|
||||
$_['percent'] = 100;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$fields = ['mode', 'reference'];
|
||||
$base = [];
|
||||
$set = 0;
|
||||
foreach ($lv as $foo)
|
||||
{
|
||||
foreach ($fields as $idx => $field)
|
||||
{
|
||||
if (!isset($base[$idx]))
|
||||
$base[$idx] = @$foo[$field];
|
||||
else if ($base[$idx] != @$foo[$field])
|
||||
$set |= 1 << $idx;
|
||||
}
|
||||
|
||||
if ($set == (pow(2, count($fields)) - 1))
|
||||
break;
|
||||
}
|
||||
|
||||
$debugCols[] = "Listview.funcBox.createSimpleCol('group', 'Group', '7%', 'group')";
|
||||
foreach ($fields as $idx => $field)
|
||||
if ($set & (1 << $idx))
|
||||
$debugCols[] = "Listview.funcBox.createSimpleCol('".$field."', '".Util::ucFirst($field)."', '7%', '".$field."')";
|
||||
}
|
||||
|
||||
return $lv;
|
||||
}
|
||||
|
||||
public static function getLootSource($itemId, $maxResults = CFG_SQL_LIMIT_DEFAULT)
|
||||
{
|
||||
if (!$itemId)
|
||||
return [];
|
||||
|
||||
// [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-achievemnt', [], [], []]
|
||||
);
|
||||
$refResults = [];
|
||||
$chanceMods = [];
|
||||
$query = 'SELECT
|
||||
-lt1.entry AS ARRAY_KEY,
|
||||
IF(lt1.mincountOrRef > 0, lt1.item, lt1.mincountOrRef) AS item,
|
||||
lt1.ChanceOrQuestChance AS chance,
|
||||
SUM(IF(lt2.ChanceOrQuestChance = 0, 1, 0)) AS nZeroItems,
|
||||
SUM(IF(lt2.ChanceOrQuestChance > 0, lt2.ChanceOrQuestChance, 0)) AS sumChance,
|
||||
IF(lt1.groupid > 0, 1, 0) AS isGrouped,
|
||||
IF(lt1.mincountOrRef > 0, lt1.mincountOrRef, 1) AS min,
|
||||
IF(lt1.mincountOrRef > 0, lt1.maxcount, 1) AS max,
|
||||
IF(lt1.mincountOrRef < 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';
|
||||
|
||||
$calcChance = function ($refs, $parents = []) use (&$chanceMods)
|
||||
{
|
||||
$retData = [];
|
||||
$retKeys = [];
|
||||
|
||||
foreach ($refs as $rId => $ref)
|
||||
{
|
||||
// check for possible database inconsistencies
|
||||
if (!$ref['chance'] && !$ref['isGrouped'])
|
||||
self::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: ungrouped Item/Ref '.$ref['item'].' has 0% chance assigned!');
|
||||
|
||||
if ($ref['isGrouped'] && $ref['sumChance'] > 100)
|
||||
self::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: group with Item/Ref '.$ref['item'].' has '.number_format($ref['sumChance'], 2).'% total chance! Some items cannot drop!');
|
||||
|
||||
if ($ref['isGrouped'] && $ref['sumChance'] == 100 && !$ref['chance'])
|
||||
self::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: Item/Ref '.$ref['item'].' with adaptive chance cannot drop. Group already at 100%!');
|
||||
|
||||
$chance = abs($ref['chance'] ? $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 // ..and one for the sort script
|
||||
);
|
||||
|
||||
$stack = []; // equal distribution between min/max .. not blizzlike, but hey, TC-issue
|
||||
if ($ref['max'] > 1)
|
||||
for ($i = $ref['min']; $i <= $ref['max']; $i++)
|
||||
$stack[$i] = round(100 / (1 + $ref['max'] - $ref['min']), 3);
|
||||
|
||||
if ($stack) // yes, it wants a string .. how weired is that..
|
||||
$data['pctstack'] = json_encode($stack, JSON_NUMERIC_CHECK);
|
||||
|
||||
// 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::Aowow()->select(
|
||||
sprintf($query, 'lt1.item = ?d AND lt1.mincountOrRef > 0'),
|
||||
LOOT_REFERENCE, LOOT_REFERENCE,
|
||||
$itemId
|
||||
);
|
||||
|
||||
while ($newRefs)
|
||||
{
|
||||
$curRefs = $newRefs;
|
||||
$newRefs = DB::Aowow()->select(
|
||||
sprintf($query, 'lt1.mincountOrRef 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(self::$lootTemplates); $i++)
|
||||
{
|
||||
$result = $calcChance(DB::Aowow()->select(
|
||||
sprintf($query, '{lt1.mincountOrRef IN (?a) OR }(lt1.mincountOrRef > 0 AND lt1.item = ?d)'),
|
||||
self::$lootTemplates[$i], self::$lootTemplates[$i],
|
||||
$refResults ? array_keys($refResults) : DBSIMPLE_SKIP,
|
||||
$itemId
|
||||
));
|
||||
|
||||
// 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 (self::$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
|
||||
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
|
||||
case LOOT_GAMEOBJECT:
|
||||
if (!$ids)
|
||||
break;
|
||||
|
||||
$srcObj = new GameObjectList(array(['lootId', $ids]));
|
||||
if ($srcObj->error)
|
||||
break;
|
||||
|
||||
$srcData = $srcObj->getListviewData();
|
||||
|
||||
foreach ($srcObj->iterate() as $curTpl)
|
||||
{
|
||||
switch ($curTpl['type'])
|
||||
{
|
||||
case 25: $tabId = 15; break; // fishing node
|
||||
case -3: $tabId = 14; break; // herb
|
||||
case -4: $tabId = 13; break; // 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';
|
||||
}
|
||||
break;
|
||||
case LOOT_MAIL:
|
||||
$conditions = array(['rewardChoiceItemId1', $itemId], ['rewardChoiceItemId2', $itemId], ['rewardChoiceItemId3', $itemId], ['rewardChoiceItemId4', $itemId], ['rewardChoiceItemId5', $itemId],
|
||||
['rewardChoiceItemId6', $itemId], ['rewardItemId1', $itemId], ['rewardItemId2', $itemId], ['rewardItemId3', $itemId], ['rewardItemId4', $itemId],
|
||||
'OR');
|
||||
if ($ids)
|
||||
$conditions[] = ['rewardMailTemplateId', $ids];
|
||||
|
||||
$srcObj = new QuestList($conditions);
|
||||
if (!$srcObj->error)
|
||||
{
|
||||
$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]);
|
||||
}
|
||||
|
||||
/*
|
||||
todo: search for achievements here
|
||||
$tabsFinal[17]
|
||||
*/
|
||||
|
||||
break;
|
||||
case LOOT_SPELL:
|
||||
$conditions = ['OR', ['effect1CreateItemId', $itemId], ['effect2CreateItemId', $itemId], ['effect3CreateItemId', $itemId]];
|
||||
if ($ids)
|
||||
$conditions[] = ['id', $ids];
|
||||
|
||||
$srcObj = new SpellList($conditions);
|
||||
if (!$srcObj->error)
|
||||
{
|
||||
$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]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$ids)
|
||||
continue;
|
||||
|
||||
switch ($tabsFinal[abs($tabId)][0])
|
||||
{
|
||||
case 'creature': // new CreatureList
|
||||
case 'item': // new ItemList
|
||||
case 'zone': // new ZoneList
|
||||
$oName = ucFirst($tabsFinal[abs($tabId)][0]).'List';
|
||||
$srcObj = new $oName(array([$field, $ids]));
|
||||
if (!$srcObj->error)
|
||||
{
|
||||
$srcObj->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED);
|
||||
$srcData = $srcObj->getListviewData();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return $tabsFinal;
|
||||
}
|
||||
|
||||
public static function urlize($str)
|
||||
{
|
||||
$search = ['<', '>', ' / ', "'", '(', ')'];
|
||||
|
||||
889
pages/object.php
889
pages/object.php
@@ -4,50 +4,26 @@ if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
require 'includes/community.class.php';
|
||||
|
||||
$_id = intVal($pageParam);
|
||||
$_path = [0, 5];
|
||||
|
||||
$cacheKeyPage = implode('_', [CACHETYPE_PAGE, TYPE_OBJECT, $_id, -1, User::$localeId]);
|
||||
$cacheKeyTooltip = implode('_', [CACHETYPE_TOOLTIP, TYPE_OBJECT, $_id, -1, User::$localeId]);
|
||||
|
||||
// AowowPower-request
|
||||
if (isset($_GET['power']))
|
||||
// menuId 5: Object g_initPath()
|
||||
// tabId 0: Database g_initHeader()
|
||||
class ObjectPage extends GenericPage
|
||||
{
|
||||
header('Content-type: application/x-javascript; charsetUTF-8');
|
||||
|
||||
Util::powerUseLocale(@$_GET['domain']);
|
||||
|
||||
if (!$smarty->loadCache($cacheKeyTooltip, $x))
|
||||
{
|
||||
$object = new GameObjectList(array(['id', $_id]));
|
||||
if ($object->error)
|
||||
die('$WowheadPower.registerObject('.$_id.', '.User::$localeId.', {});');
|
||||
|
||||
$s = $object->getSpawns(true);
|
||||
|
||||
$x = '$WowheadPower.registerObject('.$_id.', '.User::$localeId.", {\n";
|
||||
$x .= "\tname_".User::$localeString.": '".Util::jsEscape($object->getField('name', true))."',\n";
|
||||
$x .= "\ttooltip_".User::$localeString.": '".Util::jsEscape($object->renderTooltip())."'\n";
|
||||
// $x .= "\tmap: ".($s ? '{zone: '.$s[0].', coords: {0:'.json_encode($s[1], JSON_NUMERIC_CHECK).'}' : '{}')."\n";
|
||||
$x .= "});";
|
||||
|
||||
$smarty->saveCache($cacheKeyTooltip, $x);
|
||||
}
|
||||
|
||||
die($x);
|
||||
}
|
||||
|
||||
// regular page
|
||||
if (!$smarty->loadCache($cacheKeyPage, $pageData))
|
||||
{
|
||||
$object = new GameObjectList(array(['id', $_id]));
|
||||
if ($object->error)
|
||||
$smarty->notFound(Lang::$game['gameObject'], $_id);
|
||||
|
||||
$_path[] = $object->getField('typeCat');
|
||||
use DetailPage;
|
||||
|
||||
protected $type = TYPE_OBJECT;
|
||||
protected $typeId = 0;
|
||||
protected $tpl = 'object';
|
||||
protected $path = [0, 5];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHETYPE_PAGE;
|
||||
protected $js = array(
|
||||
'swfobject.js',
|
||||
// 'Mapper.js'
|
||||
);
|
||||
protected $css = array(
|
||||
// ['path' => 'Mapper.css'],
|
||||
// ['path' => 'Mapper_ie6.css', 'ieCond' => 'lte IE 6']
|
||||
);
|
||||
|
||||
/* NOTE
|
||||
|
||||
@@ -56,443 +32,474 @@ if (!$smarty->loadCache($cacheKeyPage, $pageData))
|
||||
|
||||
all of this has to be done manually
|
||||
*/
|
||||
|
||||
/***********/
|
||||
/* Infobox */
|
||||
/***********/
|
||||
|
||||
$infobox = [];
|
||||
|
||||
// Event
|
||||
if ($_ = DB::Aowow()->selectRow('SELECT e.id, holidayId FROM ?_events e, game_event_gameobject geg, gameobject g WHERE e.id = ABS(geg.eventEntry) AND g.guid = geg.guid AND g.id = ?d', $_id))
|
||||
public function __construct($__, $id)
|
||||
{
|
||||
if ($h = $_['holidayId'])
|
||||
{
|
||||
Util::$pageTemplate->extendGlobalIds(TYPE_WORLDEVENT, $_['id']);
|
||||
$infobox[] = Util::ucFirst(Lang::$game['eventShort']).Lang::$colon.'[event='.$h.']';
|
||||
}
|
||||
}
|
||||
parent::__construct();
|
||||
|
||||
// Reaction
|
||||
$_ = function ($r)
|
||||
{
|
||||
if ($r == 1) return 2;
|
||||
if ($r == -1) return 10;
|
||||
return;
|
||||
};
|
||||
$infobox[] = Lang::$npc['react'].Lang::$colon.'[color=q'.$_($object->getField('A')).']A[/color] [color=q'.$_($object->getField('H')).']H[/color]';
|
||||
// temp locale
|
||||
if ($this->mode == CACHETYPE_TOOLTIP && isset($_GET['domain']))
|
||||
Util::powerUseLocale($_GET['domain']);
|
||||
|
||||
// reqSkill
|
||||
switch ($object->getField('typeCat'))
|
||||
{
|
||||
case -3: // Herbalism
|
||||
$infobox[] = sprintf(Lang::$game['requires'], Lang::$spell['lockType'][2].' ('.$object->getField('reqSkill').')');
|
||||
break;
|
||||
case -4: // Mining
|
||||
$infobox[] = sprintf(Lang::$game['requires'], Lang::$spell['lockType'][3].' ('.$object->getField('reqSkill').')');
|
||||
break;
|
||||
case -5: // Lockpicking
|
||||
$infobox[] = sprintf(Lang::$game['requires'], Lang::$spell['lockType'][1].' ('.$object->getField('reqSkill').')');
|
||||
break;
|
||||
default: // requires key .. maybe
|
||||
{
|
||||
$locks = Lang::getLocks($object->getField('lockId'));
|
||||
$l = '';
|
||||
foreach ($locks as $idx => $_)
|
||||
{
|
||||
if ($idx < 0)
|
||||
continue;
|
||||
$this->typeId = intVal($id);
|
||||
|
||||
Util::$pageTemplate->extendGlobalIds(TYPE_ITEM, $idx);
|
||||
$l = Lang::$gameObject['key'].Lang::$colon.'[item='.$idx.']';
|
||||
}
|
||||
$this->subject = new GameObjectList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->notFound(Lang::$game['gameObject']);
|
||||
|
||||
// if no propper item is found use a skill
|
||||
if ($locks)
|
||||
$infobox[] = $l ? $l : array_pop($locks);
|
||||
}
|
||||
}
|
||||
|
||||
// linked trap
|
||||
if ($_ = $object->getField('linkedTrap'))
|
||||
{
|
||||
Util::$pageTemplate->extendGlobalIds(TYPE_OBJECT, $_);
|
||||
$infobox[] = Lang::$gameObject['trap'].Lang::$colon.'[object='.$_.']';
|
||||
}
|
||||
|
||||
// trap for
|
||||
$trigger = new GameObjectList(array(['linkedTrap', $_id]));
|
||||
if (!$trigger->error)
|
||||
{
|
||||
$trigger->addGlobalsToJScript();
|
||||
$infobox[] = Lang::$gameObject['triggeredBy'].Lang::$colon.'[object='.$trigger->id.']';
|
||||
}
|
||||
|
||||
// SpellFocus
|
||||
if ($_ = $object->getField('spellFocusId'))
|
||||
$infobox[] = '[tooltip name=focus]'.Lang::$gameObject['focusDesc'].'[/tooltip][span class=tip tooltip=focus]'.Lang::$gameObject['focus'].Lang::$colon.Util::localizedString(DB::Aowow()->selectRow('SELECT * FROM ?_spellFocusObject WHERE id = ?d', $_), 'name').'[/span]';
|
||||
|
||||
// lootinfo: [min, max, restock]
|
||||
if (($_ = $object->getField('lootStack')) && $_[0])
|
||||
{
|
||||
$buff = Lang::$item['charges'].Lang::$colon.$_[0];
|
||||
if ($_[0] < $_[1])
|
||||
$buff .= Lang::$game['valueDelim'].$_[1];
|
||||
|
||||
// since Veins don't have charges anymore, the timer is questionable
|
||||
$infobox[] = $_[2] > 1 ? '[tooltip name=restock][Recharges every '.Util::formatTime($_[2] * 1000).'][/tooltip][span class=tip tooltip=restock]'.$buff.'[/span]' : $buff;
|
||||
}
|
||||
|
||||
// meeting stone [minLevel, maxLevel, zone]
|
||||
if ($object->getField('type') == OBJECT_MEETINGSTONE)
|
||||
{
|
||||
if ($_ = $object->getField('mStone'))
|
||||
{
|
||||
Util::$pageTemplate->extendGlobalIds(TYPE_ZONE, $_[2]);
|
||||
$m = Lang::$game['meetingStone'].Lang::$colon.'[zone='.$_[2].']';
|
||||
|
||||
$l = $_[0];
|
||||
if ($_[0] > 1 && $_[1] > $_[0])
|
||||
$l .= Lang::$game['valueDelim'].min($_[1], MAX_LEVEL);
|
||||
|
||||
$infobox[] = $l ? '[tooltip name=meetingstone]'.sprintf(Lang::$game['reqLevel'], $l).'[/tooltip][span class=tip tooltip=meetingstone]'.$m.'[/span]' : $m;
|
||||
}
|
||||
}
|
||||
|
||||
// capture area [minPlayer, maxPlayer, minTime, maxTime, radius]
|
||||
if ($object->getField('type') == OBJECT_CAPTURE_POINT)
|
||||
{
|
||||
if ($_ = $object->getField('capture'))
|
||||
{
|
||||
$buff = Lang::$gameObject['capturePoint'];
|
||||
|
||||
if ($_[2] > 1 || $_[0])
|
||||
$buff .= Lang::$colon.'[ul]';
|
||||
|
||||
if ($_[2] > 1)
|
||||
$buff .= '[li]'.Lang::$game['duration'].Lang::$colon.($_[3] > $_[2] ? Util::FormatTime($_[3] * 1000, true).' - ' : null).Util::FormatTime($_[2] * 1000, true).'[/li]';
|
||||
|
||||
if ($_[1])
|
||||
$buff .= '[li]'.Lang::$main['players'].Lang::$colon.$_[0].($_[1] > $_[0] ? ' - '.$_[1] : null).'[/li]';
|
||||
|
||||
if ($_[4])
|
||||
$buff .= '[li]'.sprintf(Lang::$spell['range'], $_[4]).'[/li]';
|
||||
|
||||
if ($_[2] > 1 || $_[0])
|
||||
$buff .= '[/ul]';
|
||||
}
|
||||
|
||||
$infobox[] = $buff;
|
||||
}
|
||||
|
||||
// AI
|
||||
if (User::isInGroup(U_GROUP_STAFF))
|
||||
{
|
||||
if ($_ = $object->getField('ScriptName'))
|
||||
$infobox[] = 'Script'.Lang::$colon.$_;
|
||||
else if ($_ = $object->getField('AIName'))
|
||||
$infobox[] = 'AI'.Lang::$colon.$_;
|
||||
}
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
// pageText
|
||||
$pageText = [];
|
||||
if ($next = $object->getField('pageTextId'))
|
||||
{
|
||||
while ($next)
|
||||
{
|
||||
$row = DB::Aowow()->selectRow('SELECT *, text as Text_loc0 FROM page_text pt LEFT JOIN locales_page_text lpt ON pt.entry = lpt.entry WHERE pt.entry = ?d', $next);
|
||||
$next = $row['next_page'];
|
||||
$pageText[] = Util::parseHtmlText(Util::localizedString($row, 'Text'));
|
||||
}
|
||||
}
|
||||
|
||||
// positions
|
||||
$positions = [];
|
||||
/*
|
||||
$positions = position($object['entry'], 'gameobject');
|
||||
// Исправить type, чтобы подсвечивались event-овые объекты
|
||||
if ($object['position'])
|
||||
foreach ($object['position'] as $z => $zone)
|
||||
foreach ($zone['points'] as $p => $pos)
|
||||
if ($pos['type'] == 0 && ($events = event_find(array('object_guid' => $pos['guid']))))
|
||||
{
|
||||
$names = arraySelectKey(event_name($events), 'name');
|
||||
$object['position'][$z]['points'][$p]['type'] = 4;
|
||||
$object['position'][$z]['points'][$p]['events'] = implode(", ", $names);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// consider phaseMasks
|
||||
|
||||
// consider pooled spawns
|
||||
|
||||
|
||||
// menuId 5: Object g_initPath()
|
||||
// tabId 0: Database g_initHeader()
|
||||
$pageData = array(
|
||||
'page' => array(
|
||||
'title' => $object->getField('name', true).' - '.Util::ucFirst(Lang::$game['gameObject']),
|
||||
'path' => json_encode($_path, JSON_NUMERIC_CHECK),
|
||||
'name' => $object->getField('name', true),
|
||||
'tab' => 0,
|
||||
'type' => TYPE_OBJECT,
|
||||
'typeId' => $_id,
|
||||
'infobox' => $infobox ? '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]' : null,
|
||||
'pageText' => $pageText,
|
||||
'positions' => $positions,
|
||||
'redButtons' => array(
|
||||
BUTTON_WOWHEAD => true,
|
||||
BUTTON_LINKS => true,
|
||||
BUTTON_VIEW3D => ['displayId' => $object->getField('displayId'), 'type' => TYPE_OBJECT, 'typeId' => $_id]
|
||||
),
|
||||
'reqCSS' => array(
|
||||
$pageText ? ['path' => STATIC_URL.'/css/Book.css'] : null,
|
||||
// ['path' => STATIC_URL.'/css/Mapper.css'],
|
||||
// ['path' => STATIC_URL.'/css/Mapper_ie6.css', 'ieCond' => 'lte IE 6']
|
||||
),
|
||||
'reqJS' => array(
|
||||
$pageText ? STATIC_URL.'/js/Book.js' : null,
|
||||
// STATIC_URL.'/js/Mapper.js',
|
||||
STATIC_URL.'/js/swfobject.js'
|
||||
)
|
||||
),
|
||||
'relTabs' => []
|
||||
);
|
||||
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
// tab: summoned by
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['AND', ['effect1Id', [50, 76, 104, 105, 106, 107]], ['effect1MiscValue', $_id]],
|
||||
['AND', ['effect2Id', [50, 76, 104, 105, 106, 107]], ['effect2MiscValue', $_id]],
|
||||
['AND', ['effect3Id', [50, 76, 104, 105, 106, 107]], ['effect3MiscValue', $_id]]
|
||||
);
|
||||
|
||||
$summons = new SpellList($conditions);
|
||||
if (!$summons->error)
|
||||
{
|
||||
$summons->addGlobalsToJScript(GLOBALINFO_SELF | GLOBALINFO_RELATED);
|
||||
|
||||
$pageData['relTabs'][] = array(
|
||||
'file' => 'spell',
|
||||
'data' => $summons->getListviewData(),
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'id' => 'summoned-by',
|
||||
'name' => '$LANG.tab_summonedby'
|
||||
]
|
||||
$this->name = $this->subject->getField('name', true);
|
||||
$this->gPageInfo = array(
|
||||
'type' => $this->type,
|
||||
'typeId' => $this->typeId,
|
||||
'name' => $this->name
|
||||
);
|
||||
}
|
||||
|
||||
// tab: related spells
|
||||
if ($_ = $object->getField('spells'))
|
||||
protected function generatePath()
|
||||
{
|
||||
$relSpells = new SpellList(array(['id', $_]));
|
||||
if (!$relSpells->error)
|
||||
{
|
||||
$relSpells->addGlobalsToJScript(GLOBALINFO_SELF | GLOBALINFO_RELATED);
|
||||
$data = $relSpells->getListviewData();
|
||||
|
||||
foreach ($data as $relId => $d)
|
||||
$data[$relId]['trigger'] = array_search($relId, $_);
|
||||
|
||||
$pageData['relTabs'][] = array(
|
||||
'file' => 'spell',
|
||||
'data' => $data,
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'id' => 'spells',
|
||||
'name' => '$LANG.tab_spells',
|
||||
'hiddenCols' => "$['skill']",
|
||||
'extraCols' => "$[Listview.funcBox.createSimpleCol('trigger', 'Condition', '10%', 'trigger')]"
|
||||
]
|
||||
);
|
||||
}
|
||||
$this->path[] = $this->subject->getField('typeCat');
|
||||
}
|
||||
|
||||
// tab: criteria of
|
||||
$acvs = new AchievementList(array(['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT]], ['ac.value1', $_id]));
|
||||
if (!$acvs->error)
|
||||
protected function generateTitle()
|
||||
{
|
||||
$acvs->addGlobalsToJScript(GLOBALINFO_SELF | GLOBALINFO_RELATED);
|
||||
|
||||
$pageData['relTabs'][] = array(
|
||||
'file' => 'achievement',
|
||||
'data' => $acvs->getListviewData(),
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'id' => 'criteria-of',
|
||||
'name' => '$LANG.tab_criteriaof'
|
||||
]
|
||||
);
|
||||
array_unshift($this->title, $this->subject->getField('name', true), Util::ucFirst(Lang::$game['gameObject']));
|
||||
}
|
||||
|
||||
// tab: starts quest
|
||||
// tab: ends quest
|
||||
$startEnd = new QuestList(array(['qse.type', TYPE_OBJECT], ['qse.typeId', $_id]));
|
||||
if (!$startEnd->error)
|
||||
protected function generateContent()
|
||||
{
|
||||
$startEnd->addGlobalsToJScript();
|
||||
$lvData = $startEnd->getListviewData();
|
||||
$_ = [[], []];
|
||||
/***********/
|
||||
/* Infobox */
|
||||
/***********/
|
||||
|
||||
foreach ($startEnd->iterate() as $id => $__)
|
||||
$infobox = [];
|
||||
|
||||
// Event
|
||||
if ($_ = DB::Aowow()->selectRow('SELECT e.id, holidayId FROM ?_events e, game_event_gameobject geg, gameobject g WHERE e.id = ABS(geg.eventEntry) AND g.guid = geg.guid AND g.id = ?d', $this->typeId))
|
||||
{
|
||||
$m = $startEnd->getField('method');
|
||||
if ($m & 0x1)
|
||||
$_[0][] = $lvData[$id];
|
||||
if ($m & 0x2)
|
||||
$_[1][] = $lvData[$id];
|
||||
}
|
||||
|
||||
if ($_[0])
|
||||
{
|
||||
$pageData['relTabs'][] = array(
|
||||
'file' => 'quest',
|
||||
'data' => $_[0],
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'name' => '$LANG.tab_starts',
|
||||
'id' => 'starts'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ($_[1])
|
||||
{
|
||||
$pageData['relTabs'][] = array(
|
||||
'file' => 'quest',
|
||||
'data' => $_[1],
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'name' => '$LANG.tab_ends',
|
||||
'id' => 'ends'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tab: related quests
|
||||
if ($_ = $object->getField('reqQuest'))
|
||||
{
|
||||
$relQuest = new QuestList(array(['id', $_]));
|
||||
if (!$relQuest->error)
|
||||
{
|
||||
$relQuest->addGlobalsToJScript();
|
||||
|
||||
$pageData['relTabs'][] = array(
|
||||
'file' => 'quest',
|
||||
'data' => $relQuest->getListviewData(),
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'name' => '$LANG.tab_quests',
|
||||
'id' => 'quests'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tab: contains
|
||||
$reqQuest = [];
|
||||
if ($_ = $object->getField('lootId'))
|
||||
{
|
||||
if ($itemLoot = Util::handleLoot(LOOT_GAMEOBJECT, $_, User::isInGroup(U_GROUP_STAFF), $extraCols))
|
||||
{
|
||||
$hiddenCols = ['source', 'side', 'slot', 'reqlevel'];
|
||||
foreach ($itemLoot as $l => $lv)
|
||||
if ($h = $_['holidayId'])
|
||||
{
|
||||
if (!empty($hiddenCols))
|
||||
foreach ($hiddenCols as $k => $str)
|
||||
if (!empty($lv[$str]))
|
||||
unset($hiddenCols[$k]);
|
||||
Util::$pageTemplate->extendGlobalIds(TYPE_WORLDEVENT, $_['id']);
|
||||
$infobox[] = Util::ucFirst(Lang::$game['eventShort']).Lang::$main['colon'].'[event='.$h.']';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$lv['quest'])
|
||||
continue;
|
||||
// Reaction
|
||||
$_ = function ($r)
|
||||
{
|
||||
if ($r == 1) return 2;
|
||||
if ($r == -1) return 10;
|
||||
return;
|
||||
};
|
||||
$infobox[] = Lang::$npc['react'].Lang::$main['colon'].'[color=q'.$_($this->subject->getField('A')).']A[/color] [color=q'.$_($this->subject->getField('H')).']H[/color]';
|
||||
|
||||
$extraCols[] = 'Listview.extraCols.condition';
|
||||
// reqSkill
|
||||
switch ($this->subject->getField('typeCat'))
|
||||
{
|
||||
case -3: // Herbalism
|
||||
$infobox[] = sprintf(Lang::$game['requires'], Lang::$spell['lockType'][2].' ('.$this->subject->getField('reqSkill').')');
|
||||
break;
|
||||
case -4: // Mining
|
||||
$infobox[] = sprintf(Lang::$game['requires'], Lang::$spell['lockType'][3].' ('.$this->subject->getField('reqSkill').')');
|
||||
break;
|
||||
case -5: // Lockpicking
|
||||
$infobox[] = sprintf(Lang::$game['requires'], Lang::$spell['lockType'][1].' ('.$this->subject->getField('reqSkill').')');
|
||||
break;
|
||||
default: // requires key .. maybe
|
||||
{
|
||||
$locks = Lang::getLocks($this->subject->getField('lockId'));
|
||||
$l = '';
|
||||
foreach ($locks as $idx => $_)
|
||||
{
|
||||
if ($idx < 0)
|
||||
continue;
|
||||
|
||||
$reqQuest[$lv['id']] = 0;
|
||||
Util::$pageTemplate->extendGlobalIds(TYPE_ITEM, $idx);
|
||||
$l = Lang::$gameObject['key'].Lang::$main['colon'].'[item='.$idx.']';
|
||||
}
|
||||
|
||||
$itemLoot[$l]['condition'][] = ['type' => TYPE_QUEST, 'typeId' => &$reqQuest[$lv['id']], 'status' => 1];
|
||||
// if no propper item is found use a skill
|
||||
if ($locks)
|
||||
$infobox[] = $l ? $l : array_pop($locks);
|
||||
}
|
||||
}
|
||||
|
||||
// linked trap
|
||||
if ($_ = $this->subject->getField('linkedTrap'))
|
||||
{
|
||||
Util::$pageTemplate->extendGlobalIds(TYPE_OBJECT, $_);
|
||||
$infobox[] = Lang::$gameObject['trap'].Lang::$main['colon'].'[object='.$_.']';
|
||||
}
|
||||
|
||||
// trap for
|
||||
$trigger = new GameObjectList(array(['linkedTrap', $this->typeId]));
|
||||
if (!$trigger->error)
|
||||
{
|
||||
$this->extendGlobalData($trigger->getJSGlobals());
|
||||
$infobox[] = Lang::$gameObject['triggeredBy'].Lang::$main['colon'].'[object='.$trigger->id.']';
|
||||
}
|
||||
|
||||
// SpellFocus
|
||||
if ($_ = $this->subject->getField('spellFocusId'))
|
||||
$infobox[] = '[tooltip name=focus]'.Lang::$gameObject['focusDesc'].'[/tooltip][span class=tip tooltip=focus]'.Lang::$gameObject['focus'].Lang::$main['colon'].Util::localizedString(DB::Aowow()->selectRow('SELECT * FROM ?_spellFocusObject WHERE id = ?d', $_), 'name').'[/span]';
|
||||
|
||||
// lootinfo: [min, max, restock]
|
||||
if (($_ = $this->subject->getField('lootStack')) && $_[0])
|
||||
{
|
||||
$buff = Lang::$item['charges'].Lang::$main['colon'].$_[0];
|
||||
if ($_[0] < $_[1])
|
||||
$buff .= Lang::$game['valueDelim'].$_[1];
|
||||
|
||||
// since Veins don't have charges anymore, the timer is questionable
|
||||
$infobox[] = $_[2] > 1 ? '[tooltip name=restock][Recharges every '.Util::formatTime($_[2] * 1000).'][/tooltip][span class=tip tooltip=restock]'.$buff.'[/span]' : $buff;
|
||||
}
|
||||
|
||||
// meeting stone [minLevel, maxLevel, zone]
|
||||
if ($this->subject->getField('type') == OBJECT_MEETINGSTONE)
|
||||
{
|
||||
if ($_ = $this->subject->getField('mStone'))
|
||||
{
|
||||
Util::$pageTemplate->extendGlobalIds(TYPE_ZONE, $_[2]);
|
||||
$m = Lang::$game['meetingStone'].Lang::$main['colon'].'[zone='.$_[2].']';
|
||||
|
||||
$l = $_[0];
|
||||
if ($_[0] > 1 && $_[1] > $_[0])
|
||||
$l .= Lang::$game['valueDelim'].min($_[1], MAX_LEVEL);
|
||||
|
||||
$infobox[] = $l ? '[tooltip name=meetingstone]'.sprintf(Lang::$game['reqLevel'], $l).'[/tooltip][span class=tip tooltip=meetingstone]'.$m.'[/span]' : $m;
|
||||
}
|
||||
}
|
||||
|
||||
// capture area [minPlayer, maxPlayer, minTime, maxTime, radius]
|
||||
if ($this->subject->getField('type') == OBJECT_CAPTURE_POINT)
|
||||
{
|
||||
if ($_ = $this->subject->getField('capture'))
|
||||
{
|
||||
$buff = Lang::$gameObject['capturePoint'];
|
||||
|
||||
if ($_[2] > 1 || $_[0])
|
||||
$buff .= Lang::$main['colon'].'[ul]';
|
||||
|
||||
if ($_[2] > 1)
|
||||
$buff .= '[li]'.Lang::$game['duration'].Lang::$main['colon'].($_[3] > $_[2] ? Util::FormatTime($_[3] * 1000, true).' - ' : null).Util::FormatTime($_[2] * 1000, true).'[/li]';
|
||||
|
||||
if ($_[1])
|
||||
$buff .= '[li]'.Lang::$main['players'].Lang::$main['colon'].$_[0].($_[1] > $_[0] ? ' - '.$_[1] : null).'[/li]';
|
||||
|
||||
if ($_[4])
|
||||
$buff .= '[li]'.sprintf(Lang::$spell['range'], $_[4]).'[/li]';
|
||||
|
||||
if ($_[2] > 1 || $_[0])
|
||||
$buff .= '[/ul]';
|
||||
}
|
||||
|
||||
$extraCols[] = 'Listview.extraCols.percent';
|
||||
|
||||
$pageData['relTabs'][] = array(
|
||||
'file' => 'item',
|
||||
'data' => $itemLoot,
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'name' => '$LANG.tab_contains',
|
||||
'id' => 'contains',
|
||||
'extraCols' => "$[".implode(', ', array_unique($extraCols))."]",
|
||||
'hiddenCols' => $hiddenCols ? '$'.json_encode(array_values($hiddenCols)) : null
|
||||
]
|
||||
);
|
||||
$infobox[] = $buff;
|
||||
}
|
||||
}
|
||||
|
||||
if ($reqIds = array_keys($reqQuest)) // apply quest-conditions as back-reference
|
||||
{
|
||||
// AI
|
||||
if (User::isInGroup(U_GROUP_STAFF))
|
||||
{
|
||||
if ($_ = $this->subject->getField('ScriptName'))
|
||||
$infobox[] = 'Script'.Lang::$main['colon'].$_;
|
||||
else if ($_ = $this->subject->getField('AIName'))
|
||||
$infobox[] = 'AI'.Lang::$main['colon'].$_;
|
||||
}
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
// pageText
|
||||
$pageText = [];
|
||||
if ($next = $this->subject->getField('pageTextId'))
|
||||
{
|
||||
while ($next)
|
||||
{
|
||||
$row = DB::Aowow()->selectRow('SELECT *, text as Text_loc0 FROM page_text pt LEFT JOIN locales_page_text lpt ON pt.entry = lpt.entry WHERE pt.entry = ?d', $next);
|
||||
$next = $row['next_page'];
|
||||
$pageText[] = Util::parseHtmlText(Util::localizedString($row, 'Text'));
|
||||
}
|
||||
}
|
||||
|
||||
// add conditional js & css
|
||||
if ($pageText)
|
||||
{
|
||||
$this->addCSS(['path' => 'Book.css']);
|
||||
$this->addJS('Book.js');
|
||||
}
|
||||
|
||||
// positions
|
||||
$positions = [];
|
||||
/*
|
||||
$positions = position($object['entry'], 'gameobject');
|
||||
// Исправить type, чтобы подсвечивались event-овые объекты
|
||||
if ($object['position'])
|
||||
foreach ($object['position'] as $z => $zone)
|
||||
foreach ($zone['points'] as $p => $pos)
|
||||
if ($pos['type'] == 0 && ($events = event_find(array('object_guid' => $pos['guid']))))
|
||||
{
|
||||
$names = arraySelectKey(event_name($events), 'name');
|
||||
$object['position'][$z]['points'][$p]['type'] = 4;
|
||||
$object['position'][$z]['points'][$p]['events'] = implode(", ", $names);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// consider phaseMasks
|
||||
|
||||
// consider pooled spawns
|
||||
|
||||
$this->infobox = $infobox ? '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]' : null;
|
||||
$this->pageText = $pageText;
|
||||
$this->positions = $positions;
|
||||
$this->redButtons = array(
|
||||
BUTTON_WOWHEAD => true,
|
||||
BUTTON_LINKS => true,
|
||||
BUTTON_VIEW3D => ['displayId' => $this->subject->getField('displayId'), 'type' => TYPE_OBJECT, 'typeId' => $this->typeId]
|
||||
);
|
||||
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
// tab: summoned by
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['reqSourceItemId1', $reqIds], ['reqSourceItemId2', $reqIds],
|
||||
['reqSourceItemId3', $reqIds], ['reqSourceItemId4', $reqIds],
|
||||
['reqItemId1', $reqIds], ['reqItemId2', $reqIds], ['reqItemId3', $reqIds],
|
||||
['reqItemId4', $reqIds], ['reqItemId5', $reqIds], ['reqItemId6', $reqIds]
|
||||
['AND', ['effect1Id', [50, 76, 104, 105, 106, 107]], ['effect1MiscValue', $this->typeId]],
|
||||
['AND', ['effect2Id', [50, 76, 104, 105, 106, 107]], ['effect2MiscValue', $this->typeId]],
|
||||
['AND', ['effect3Id', [50, 76, 104, 105, 106, 107]], ['effect3MiscValue', $this->typeId]]
|
||||
);
|
||||
|
||||
$reqQuests = new QuestList($conditions);
|
||||
$reqQuests->addGlobalsToJscript();
|
||||
|
||||
foreach ($reqQuests->iterate() as $qId => $__)
|
||||
$summons = new SpellList($conditions);
|
||||
if (!$summons->error)
|
||||
{
|
||||
if (empty($reqQuests->requires[$qId][TYPE_ITEM]))
|
||||
continue;
|
||||
$this->extendGlobalData($summons->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
|
||||
|
||||
foreach ($reqIds as $rId)
|
||||
if (in_array($rId, $reqQuests->requires[$qId][TYPE_ITEM]))
|
||||
$reqQuest[$rId] = $reqQuests->id;
|
||||
$this->lvData[] = array(
|
||||
'file' => 'spell',
|
||||
'data' => $summons->getListviewData(),
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'id' => 'summoned-by',
|
||||
'name' => '$LANG.tab_summonedby'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// tab: related spells
|
||||
if ($_ = $this->subject->getField('spells'))
|
||||
{
|
||||
$relSpells = new SpellList(array(['id', $_]));
|
||||
if (!$relSpells->error)
|
||||
{
|
||||
$this->extendGlobalData($relSpells->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
|
||||
$data = $relSpells->getListviewData();
|
||||
|
||||
foreach ($data as $relId => $d)
|
||||
$data[$relId]['trigger'] = array_search($relId, $_);
|
||||
|
||||
$this->lvData[] = array(
|
||||
'file' => 'spell',
|
||||
'data' => $data,
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'id' => 'spells',
|
||||
'name' => '$LANG.tab_spells',
|
||||
'hiddenCols' => "$['skill']",
|
||||
'extraCols' => "$[Listview.funcBox.createSimpleCol('trigger', 'Condition', '10%', 'trigger')]"
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tab: criteria of
|
||||
$acvs = new AchievementList(array(['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT]], ['ac.value1', $this->typeId]));
|
||||
if (!$acvs->error)
|
||||
{
|
||||
$this->extendGlobalData($acvs->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
|
||||
|
||||
$this->lvData[] = array(
|
||||
'file' => 'achievement',
|
||||
'data' => $acvs->getListviewData(),
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'id' => 'criteria-of',
|
||||
'name' => '$LANG.tab_criteriaof'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// tab: starts quest
|
||||
// tab: ends quest
|
||||
$startEnd = new QuestList(array(['qse.type', TYPE_OBJECT], ['qse.typeId', $this->typeId]));
|
||||
if (!$startEnd->error)
|
||||
{
|
||||
$this->extendGlobalData($startEnd->getJSGlobals());
|
||||
$lvData = $startEnd->getListviewData();
|
||||
$_ = [[], []];
|
||||
|
||||
foreach ($startEnd->iterate() as $id => $__)
|
||||
{
|
||||
$m = $startEnd->getField('method');
|
||||
if ($m & 0x1)
|
||||
$_[0][] = $lvData[$id];
|
||||
if ($m & 0x2)
|
||||
$_[1][] = $lvData[$id];
|
||||
}
|
||||
|
||||
if ($_[0])
|
||||
{
|
||||
$this->lvData[] = array(
|
||||
'file' => 'quest',
|
||||
'data' => $_[0],
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'name' => '$LANG.tab_starts',
|
||||
'id' => 'starts'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ($_[1])
|
||||
{
|
||||
$this->lvData[] = array(
|
||||
'file' => 'quest',
|
||||
'data' => $_[1],
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'name' => '$LANG.tab_ends',
|
||||
'id' => 'ends'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tab: related quests
|
||||
if ($_ = $this->subject->getField('reqQuest'))
|
||||
{
|
||||
$relQuest = new QuestList(array(['id', $_]));
|
||||
if (!$relQuest->error)
|
||||
{
|
||||
$this->extendGlobalData($relQuest->getJSGlobals());
|
||||
|
||||
$this->lvData[] = array(
|
||||
'file' => 'quest',
|
||||
'data' => $relQuest->getListviewData(),
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'name' => '$LANG.tab_quests',
|
||||
'id' => 'quests'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tab: contains
|
||||
$reqQuest = [];
|
||||
if ($_ = $this->subject->getField('lootId'))
|
||||
{
|
||||
include 'includes/loot.class.php';
|
||||
|
||||
if (Loot::getByContainer(LOOT_GAMEOBJECT, $_))
|
||||
{
|
||||
$extraCols = Loot::$extraCols;
|
||||
$hiddenCols = ['source', 'side', 'slot', 'reqlevel'];
|
||||
$itemLoot = Loot::getResult();
|
||||
|
||||
$this->extendGlobalData(Loot::$jsGlobals);
|
||||
|
||||
foreach ($itemLoot as $l => $lv)
|
||||
{
|
||||
if (!empty($hiddenCols))
|
||||
foreach ($hiddenCols as $k => $str)
|
||||
if (!empty($lv[$str]))
|
||||
unset($hiddenCols[$k]);
|
||||
|
||||
if (!$lv['quest'])
|
||||
continue;
|
||||
|
||||
$extraCols[] = 'Listview.extraCols.condition';
|
||||
|
||||
$reqQuest[$lv['id']] = 0;
|
||||
|
||||
$itemLoot[$l]['condition'][] = ['type' => TYPE_QUEST, 'typeId' => &$reqQuest[$lv['id']], 'status' => 1];
|
||||
}
|
||||
|
||||
$extraCols[] = 'Listview.extraCols.percent';
|
||||
|
||||
$this->lvData[] = array(
|
||||
'file' => 'item',
|
||||
'data' => $itemLoot,
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'name' => '$LANG.tab_contains',
|
||||
'id' => 'contains',
|
||||
'extraCols' => "$[".implode(', ', array_unique($extraCols))."]",
|
||||
'hiddenCols' => $hiddenCols ? '$'.json_encode(array_values($hiddenCols)) : null
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($reqIds = array_keys($reqQuest)) // apply quest-conditions as back-reference
|
||||
{
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['reqSourceItemId1', $reqIds], ['reqSourceItemId2', $reqIds],
|
||||
['reqSourceItemId3', $reqIds], ['reqSourceItemId4', $reqIds],
|
||||
['reqItemId1', $reqIds], ['reqItemId2', $reqIds], ['reqItemId3', $reqIds],
|
||||
['reqItemId4', $reqIds], ['reqItemId5', $reqIds], ['reqItemId6', $reqIds]
|
||||
);
|
||||
|
||||
$reqQuests = new QuestList($conditions);
|
||||
$this->extendGlobalData($reqQuests->getJSGlobals());
|
||||
|
||||
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: Same model as .. whats the fucking point..?
|
||||
$sameModel = new GameObjectList(array(['displayId', $this->subject->getField('displayId')], ['id', $this->typeId, '!']));
|
||||
if (!$sameModel->error)
|
||||
{
|
||||
$this->extendGlobalData($sameModel->getJSGlobals());
|
||||
|
||||
$this->lvData[] = array(
|
||||
'file' => 'object',
|
||||
'data' => $sameModel->getListviewData(),
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'name' => '$LANG.tab_samemodelas',
|
||||
'id' => 'same-model-as'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tab: Same model as .. whats the fucking point..?
|
||||
$sameModel = new GameObjectList(array(['displayId', $object->getField('displayId')], ['id', $_id, '!']));
|
||||
if (!$sameModel->error)
|
||||
{
|
||||
$sameModel->addGlobalsToJScript();
|
||||
|
||||
$pageData['relTabs'][] = array(
|
||||
'file' => 'object',
|
||||
'data' => $sameModel->getListviewData(),
|
||||
'params' => [
|
||||
'tabs' => '$tabsRelated',
|
||||
'name' => '$LANG.tab_samemodelas',
|
||||
'id' => 'same-model-as'
|
||||
]
|
||||
);
|
||||
protected function generateTooltip($asError = false)
|
||||
{
|
||||
if ($asError)
|
||||
die('$WowheadPower.registerObject('.$this->typeId.', '.User::$localeId.', {});');
|
||||
|
||||
$s = $this->subject->getSpawns(true);
|
||||
|
||||
$x = '$WowheadPower.registerObject('.$this->typeId.', '.User::$localeId.", {\n";
|
||||
$x .= "\tname_".User::$localeString.": '".Util::jsEscape($this->subject->getField('name', true))."',\n";
|
||||
$x .= "\ttooltip_".User::$localeString.": '".Util::jsEscape($this->subject->renderTooltip())."'\n";
|
||||
// $x .= "\tmap: ".($s ? '{zone: '.$s[0].', coords: {0:'.json_encode($s[1], JSON_NUMERIC_CHECK).'}' : '{}')."\n";
|
||||
$x .= "});";
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
$smarty->saveCache($cacheKeyPage, $pageData);
|
||||
}
|
||||
|
||||
|
||||
$smarty->updatePageVars($pageData['page']);
|
||||
$smarty->assign('community', CommunityContent::getAll(TYPE_OBJECT, $_id)); // comments, screenshots, videos
|
||||
$smarty->assign('lang', array_merge(Lang::$main, Lang::$game, Lang::$item, Lang::$gameObject, ['colon' => Lang::$colon]));
|
||||
$smarty->assign('lvData', $pageData['relTabs']);
|
||||
|
||||
// load the page
|
||||
$smarty->display('object.tpl');
|
||||
|
||||
?>
|
||||
|
||||
@@ -4,82 +4,87 @@ if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
$filter = [];
|
||||
$conditions = [];
|
||||
$cat = Util::extractURLParams($pageParam);
|
||||
$path = [0, 5];
|
||||
$validCats = [-2, -3, -4, -5, -6, 0, 3, 9, 25];
|
||||
$title = [Util::ucFirst(Lang::$game['gameObjects'])];
|
||||
$cacheKey = implode('_', [CACHETYPE_PAGE, TYPE_OBJECT, -1, $cat ? $cat[0] : -1, User::$localeId]);
|
||||
|
||||
if (!Util::isValidPage($validCats, $cat))
|
||||
$smarty->error();
|
||||
|
||||
if ($cat)
|
||||
// menuId 5: Object g_initPath()
|
||||
// tabId 0: Database g_initHeader()
|
||||
class ObjectsPage extends GenericPage
|
||||
{
|
||||
$path[] = $cat[0];
|
||||
array_unshift($title, Lang::$gameObject['cat'][$cat[0]]);
|
||||
$conditions[] = ['typeCat', (int)$cat[0]];
|
||||
}
|
||||
use ListPage;
|
||||
|
||||
if (!$smarty->loadCache($cacheKey, $pageData, $filter))
|
||||
{
|
||||
protected $type = TYPE_OBJECT;
|
||||
protected $tpl = 'objects';
|
||||
protected $path = [0, 5];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHETYPE_PAGE;
|
||||
protected $validCats = [-2, -3, -4, -5, -6, 0, 3, 9, 25];
|
||||
protected $js = ['filters.js'];
|
||||
|
||||
$objectFilter = new GameObjectListFilter();
|
||||
if ($_ = $objectFilter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$objects = new GameObjectList($conditions, ['extraOpts' => $objectFilter->extraOpts]);
|
||||
|
||||
// menuId 5: Object g_initPath()
|
||||
// tabId 0: Database g_initHeader()
|
||||
$pageData = array(
|
||||
'page' => array(
|
||||
'tab' => 0,
|
||||
'title' => implode(" - ", $title),
|
||||
'path' => json_encode($path, JSON_NUMERIC_CHECK),
|
||||
'subCat' => $pageParam ? '='.$pageParam : '',
|
||||
'reqJS' => [STATIC_URL.'/js/filters.js']
|
||||
),
|
||||
'lv' => []
|
||||
);
|
||||
|
||||
// recreate form selection
|
||||
$filter = array_merge($objectFilter->getForm('form'), $filter);
|
||||
$filter['query'] = isset($_GET['filter']) ? $_GET['filter'] : NULL;
|
||||
$filter['fi'] = $objectFilter->getForm();
|
||||
|
||||
$params = [];
|
||||
if ($objects->hasSetFields(['reqSkill']))
|
||||
$params['visibleCols'] = "$['skill']";
|
||||
|
||||
$lv = array(
|
||||
'file' => 'object',
|
||||
'data' => $objects->getListviewData(),
|
||||
'params' => $params
|
||||
);
|
||||
|
||||
// create note if search limit was exceeded
|
||||
if ($objects->getMatches() > CFG_SQL_LIMIT_DEFAULT)
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
$lv['params']['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_objectsfound', $objects->getMatches(), CFG_SQL_LIMIT_DEFAULT);
|
||||
$lv['params']['_truncated'] = 1;
|
||||
$this->category = Util::extractURLParams($pageParam);
|
||||
|
||||
parent::__construct();
|
||||
|
||||
$this->name = Util::ucFirst(Lang::$game['gameObjects']);
|
||||
$this->subCat = $pageParam ? '='.$pageParam : '';
|
||||
}
|
||||
|
||||
if ($objectFilter->error)
|
||||
$lv['params']['_errors'] = '$1';
|
||||
protected function generateContent()
|
||||
{
|
||||
$conditions = [];
|
||||
|
||||
$pageData['lv'] = $lv;
|
||||
if ($this->category)
|
||||
$conditions[] = ['typeCat', (int)$this->category[0]];
|
||||
|
||||
$smarty->saveCache($cacheKey, $pageData, $filter);
|
||||
$objectFilter = new GameObjectListFilter();
|
||||
|
||||
// recreate form selection
|
||||
$this->filter = $objectFilter->getForm('form');
|
||||
$this->filter['query'] = isset($_GET['filter']) ? $_GET['filter'] : null;
|
||||
$this->filter['fi'] = $objectFilter->getForm();
|
||||
|
||||
if ($_ = $objectFilter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$params = $data = [];
|
||||
$objects = new GameObjectList($conditions, ['extraOpts' => $objectFilter->extraOpts]);
|
||||
if (!$objects->error)
|
||||
{
|
||||
$data = $objects->getListviewData();
|
||||
if ($objects->hasSetFields(['reqSkill']))
|
||||
$params['visibleCols'] = "$['skill']";
|
||||
|
||||
|
||||
// create note if search limit was exceeded
|
||||
if ($objects->getMatches() > CFG_SQL_LIMIT_DEFAULT)
|
||||
{
|
||||
$params['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_objectsfound', $objects->getMatches(), CFG_SQL_LIMIT_DEFAULT);
|
||||
$params['_truncated'] = 1;
|
||||
}
|
||||
|
||||
if ($objectFilter->error)
|
||||
$params['_errors'] = '$1';
|
||||
|
||||
}
|
||||
|
||||
$this->lvData = array(
|
||||
'file' => 'object',
|
||||
'data' => $data,
|
||||
'params' => $params
|
||||
);
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
array_unshift($this->title, $this->name);
|
||||
if ($this->category)
|
||||
array_unshift($this->title, Lang::$gameObject['cat'][$this->category[0]]);
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
{
|
||||
if ($this->category)
|
||||
$this->path[] = $this->category[0];
|
||||
}
|
||||
}
|
||||
|
||||
$smarty->updatePageVars($pageData['page']);
|
||||
$smarty->assign('filter', $filter);
|
||||
$smarty->assign('lang', array_merge(Lang::$main, ['colon' => Lang::$colon]));
|
||||
$smarty->assign('lvData', $pageData['lv']);
|
||||
|
||||
// load the page
|
||||
$smarty->display('objects.tpl');
|
||||
|
||||
?>
|
||||
|
||||
@@ -18386,16 +18386,16 @@ var Links = new function() {
|
||||
fields:
|
||||
[
|
||||
{
|
||||
id: 'wowheadurl',
|
||||
type: 'text',
|
||||
id: 'wowheadurl',
|
||||
type: 'text',
|
||||
label: 'Aowow URL',
|
||||
size: 40
|
||||
size: 40
|
||||
},
|
||||
{
|
||||
id: 'markuptag',
|
||||
type: 'text',
|
||||
id: 'markuptag',
|
||||
type: 'text',
|
||||
label: 'Markup Tag',
|
||||
size: 40
|
||||
size: 40
|
||||
}
|
||||
],
|
||||
|
||||
@@ -18405,7 +18405,7 @@ var Links = new function() {
|
||||
|
||||
onShow: function(form) {
|
||||
setTimeout(function() {
|
||||
document.getElementsByName('ingamelink')[0].select();
|
||||
$(form.ingamelink).select();
|
||||
}, 50);
|
||||
setTimeout(Lightbox.reveal, 100);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
if (!empty($this->pageText)):
|
||||
?>
|
||||
<div class="clear"></div>
|
||||
<h3><?php echo Lang:$main['content']; ?></h3>
|
||||
<h3><?php echo Lang::$main['content']; ?></h3>
|
||||
|
||||
<div id="book-generic"></div>
|
||||
<script>//<![CDATA[
|
||||
|
||||
@@ -15,7 +15,7 @@ foreach ($this->css as $css):
|
||||
echo ' <style type="text/css">'.$css['string']."</style>\n";
|
||||
elseif (!empty($css['path'])):
|
||||
echo ' '.(!empty($css['ieCond']) ? '<!--[if '.$css['ieCond'].']>' : null) .
|
||||
'<link rel="stylesheet" type="text/css" href="'.$css['path'].'?'.AOWOW_REVISION.'" />' .
|
||||
'<link rel="stylesheet" type="text/css" href="'.STATIC_URL.'/css/'.$css['path'].'?'.AOWOW_REVISION.'" />' .
|
||||
(!empty($css['ieCond']) ? '<![endif]-->' : null)."\n";
|
||||
endif;
|
||||
endforeach;
|
||||
@@ -39,7 +39,7 @@ endif;
|
||||
<?php
|
||||
foreach ($this->js as $js):
|
||||
if (!empty($js)):
|
||||
echo ' <script src="'.$js.($js[0] == '?' ? '&' : '?').AOWOW_REVISION."\" type=\"text/javascript\"></script>\n";
|
||||
echo ' <script src="'.($js[0] == '?' ? $js.'&' : STATIC_URL.'/js/'.$js.'?').AOWOW_REVISION."\" type=\"text/javascript\"></script>\n";
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
|
||||
@@ -22,7 +22,14 @@ endif;
|
||||
// view in 3D
|
||||
if (isset($this->redButtons[BUTTON_VIEW3D])):
|
||||
if ($b = $this->redButtons[BUTTON_VIEW3D]):
|
||||
echo '<a href="javascript:;" id="view3D-button" class="button-red" onclick="this.blur(); ModelViewer.show('.json_encode($b, JSON_NUMERIC_CHECK).')"><em><b><i>'.Lang::$main['view3D'].'</i></b><span>'.Lang::$main['view3D'].'</span></em></a>';
|
||||
{
|
||||
// json_encode puts property names in brackets wich is not cool with inline javascript
|
||||
$data = [];
|
||||
foreach ($b as $k => $v)
|
||||
$data[] = $k.': '.json_encode($v, JSON_NUMERIC_CHECK);
|
||||
|
||||
echo '<a href="javascript:;" id="view3D-button" class="button-red" onclick="this.blur(); ModelViewer.show({'.implode(', ', $data).'})"><em><b><i>'.Lang::$main['view3D'].'</i></b><span>'.Lang::$main['view3D'].'</span></em></a>';
|
||||
}
|
||||
else:
|
||||
echo '<a href="javascript:;" id="view3D-button" class="button-red button-red-disabled"><em><b><i>'.Lang::$main['view3D'].'</i></b><span>'.Lang::$main['view3D'].'</span></em></a>';
|
||||
endif;
|
||||
|
||||
@@ -1,38 +1,37 @@
|
||||
{include file='header.tpl'}
|
||||
<?php $this->brick('header'); ?>
|
||||
|
||||
<div class="main" id="main">
|
||||
<div class="main-precontents" id="main-precontents"></div>
|
||||
<div class="main-contents" id="main-contents">
|
||||
|
||||
{if !empty($announcements)}
|
||||
{foreach from=$announcements item=item}
|
||||
{include file='bricks/announcement.tpl' an=$item}
|
||||
{/foreach}
|
||||
{/if}
|
||||
<?php $this->brick('announcement'); ?>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
{include file='bricks/community.tpl'}
|
||||
var g_pageInfo = {ldelim}type: {$type}, typeId: {$typeId}, name: '{$name|escape:"quotes"}'{rdelim};
|
||||
g_initPath({$path});
|
||||
<?php
|
||||
$this->brick('community');
|
||||
echo "var g_pageInfo = ".json_encode($this->gPageInfo, JSON_NUMERIC_CHECK).";\n" .
|
||||
"g_initPath(".json_encode($this->path, JSON_NUMERIC_CHECK).");\n";
|
||||
?>
|
||||
//]]></script>
|
||||
|
||||
{include file='bricks/infobox.tpl'}
|
||||
<?php $this->brick('infobox'); ?>
|
||||
|
||||
<div class="text">
|
||||
{include file='bricks/redButtons.tpl'}
|
||||
<?php $this->brick('redButtons'); ?>
|
||||
|
||||
<h1>{$name}</h1>
|
||||
<h1><?php echo $this->name; ?></h1>
|
||||
|
||||
{include file='bricks/article.tpl'}
|
||||
<?php
|
||||
$this->brick('article');
|
||||
|
||||
{if $positions}
|
||||
if ($this->positions):
|
||||
?>
|
||||
<div>{#This_Object_can_be_found_in#}
|
||||
{strip}
|
||||
<span id="locations">
|
||||
{foreach from=$object.position item=zone name=zone}
|
||||
<a href="javascript:;" onclick="
|
||||
myMapper.update(
|
||||
{ldelim}
|
||||
{
|
||||
{if $zone.atid}
|
||||
zone:{$zone.atid}
|
||||
{if $zone.points}
|
||||
@@ -45,7 +44,7 @@
|
||||
coords:[
|
||||
{foreach from=$zone.points item=point name=point}
|
||||
[{$point.x},{$point.y},
|
||||
{ldelim}
|
||||
{
|
||||
label:'$<br>
|
||||
<div class=q0>
|
||||
<small>{#Respawn#}:
|
||||
@@ -55,37 +54,40 @@
|
||||
{if isset($point.events)}<br>{$point.events|escape:"quotes"}{/if}
|
||||
</small>
|
||||
</div>',type:'{$point.type}'
|
||||
{rdelim}]
|
||||
}]
|
||||
{if !$smarty.foreach.point.last},{/if}
|
||||
{/foreach}
|
||||
]
|
||||
{/if}
|
||||
{rdelim});
|
||||
});
|
||||
g_setSelectedLink(this, 'mapper'); return false" onmousedown="return false">
|
||||
{$zone.name}</a>{if $zone.population > 1} ({$zone.population}){/if}{if $smarty.foreach.zone.last}.{else}, {/if}
|
||||
{/foreach}
|
||||
</span></div>
|
||||
{/strip}
|
||||
|
||||
<div id="mapper-generic"></div>
|
||||
<div class="clear"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var myMapper = new Mapper({ldelim}parent: 'mapper-generic', zone: '{$position[0].atid}'{rdelim});
|
||||
var myMapper = new Mapper({parent: 'mapper-generic', zone: '{$position[0].atid}'});
|
||||
$WH.gE($WH.ge('locations'), 'a')[0].onclick();
|
||||
</script>
|
||||
{else}
|
||||
{$lang.unkPosition}
|
||||
{/if}
|
||||
{include file='bricks/book.tpl'}
|
||||
<?php
|
||||
else:
|
||||
echo Lang::$gameObject['unkPosition'];
|
||||
endif;
|
||||
|
||||
<h2 class="clear">{$lang.related}</h2>
|
||||
$this->brick('book');
|
||||
?>
|
||||
|
||||
<h2 class="clear"><?php echo Lang::$main['related']; ?></h2>
|
||||
</div>
|
||||
|
||||
{include file='bricks/tabsRelated.tpl' tabs=$lvData}
|
||||
<?php $this->brick('tabsRelated'); ?>
|
||||
|
||||
{include file='bricks/contribute.tpl'}
|
||||
<?php $this->brick('contribute'); ?>
|
||||
|
||||
</div><!-- main-contents -->
|
||||
</div><!-- main -->
|
||||
|
||||
{include file='footer.tpl'}
|
||||
<?php $this->brick('footer'); ?>
|
||||
@@ -1,61 +0,0 @@
|
||||
{include file='header.tpl'}
|
||||
|
||||
<div class="main" id="main">
|
||||
<div class="main-precontents" id="main-precontents"></div>
|
||||
<div class="main-contents" id="main-contents">
|
||||
|
||||
{if !empty($announcements)}
|
||||
{foreach from=$announcements item=item}
|
||||
{include file='bricks/announcement.tpl' an=$item}
|
||||
{/foreach}
|
||||
{/if}
|
||||
|
||||
<script type="text/javascript">
|
||||
g_initPath({$path}, {if empty($filter.query)} 0 {else} 1 {/if});
|
||||
{if !empty($filter.query)}
|
||||
Menu.modifyUrl(Menu.findItem(mn_database, [5]), {ldelim} filter: '+={$filter.query|escape:'quotes'}' {rdelim}, {ldelim} onAppendCollision: fi_mergeFilterParams, onAppendEmpty: fi_setFilterParams, menuUrl: Menu.getItemUrl(Menu.findItem(mn_database, [5])) {rdelim});
|
||||
{/if}
|
||||
</script>
|
||||
|
||||
<div id="fi" style="display: {if empty($filter.query)}none{else}block{/if};">
|
||||
<form action="?objects{$subCat}&filter" method="post" name="fi" onsubmit="return fi_submit(this)" onreset="return fi_reset(this)">
|
||||
<table>
|
||||
<tr><td>{$lang.name|ucFirst}: </td><td> <input type="text" name="na" size="30" {if isset($filter.na)}value="{$filter.na|escape:'html'}" {/if}/></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">{$lang.addFilter}</a></div>
|
||||
|
||||
<div class="padded2 clear">
|
||||
<div style="float: right">{$lang.refineSearch}</div>
|
||||
{$lang.match}{$lang.colon}<input type="radio" name="ma" value="" id="ma-0" {if !isset($filter.ma)}checked="checked"{/if} /><label for="ma-0">{$lang.allFilter}</label><input type="radio" name="ma" value="1" id="ma-1" {if isset($filter.ma)}checked="checked"{/if} /><label for="ma-1">{$lang.oneFilter}</label>
|
||||
</div>
|
||||
|
||||
<div class="clear"></div>
|
||||
|
||||
<div class="padded">
|
||||
<input type="submit" value="{$lang.applyFilter}" />
|
||||
<input type="reset" value="{$lang.resetForm}" />
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<div class="pad"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
fi_init('objects');
|
||||
{foreach from=$filter.fi item=str}
|
||||
{$str}
|
||||
{/foreach}
|
||||
//]]></script>
|
||||
|
||||
<div id="lv-generic" class="listview"></div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
{include file='listviews/object.tpl' data=$lvData.data params=$lvData.params}
|
||||
//]]></script>
|
||||
|
||||
<div class="clear"></div>
|
||||
</div><!-- main-contents -->
|
||||
</div><!-- main -->
|
||||
|
||||
{include file='footer.tpl'}
|
||||
61
template/pages/objects.tpl.php
Normal file
61
template/pages/objects.tpl.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php $this->brick('header'); ?>
|
||||
|
||||
<div class="main" id="main">
|
||||
<div class="main-precontents" id="main-precontents"></div>
|
||||
<div class="main-contents" id="main-contents">
|
||||
|
||||
<?php $this->brick('announcement'); ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
g_initPath(<?php echo json_encode($this->path, JSON_NUMERIC_CHECK).', '.(empty($this->filter['query']) ? 0 : 1) ?>);
|
||||
<?php
|
||||
if (!empty($this->filter['query'])):
|
||||
// todo: update menu-class Menu.modifyUrl(Menu.findItem(mn_database, [5]), { filter: '+={$filter.query|escape:'quotes'}' }, { onAppendCollision: fi_mergeFilterParams, onAppendEmpty: fi_setFilterParams, menuUrl: Menu.getItemUrl(Menu.findItem(mn_database, [5])) });
|
||||
endif;
|
||||
?>
|
||||
</script>
|
||||
|
||||
<div id="fi" style="display: <?php echo empty($this->filter['query']) ? 'none' : 'block' ?>;">
|
||||
<form action="?objects<?php echo $this->subCat; ?>&filter" method="post" name="fi" onsubmit="return fi_submit(this)" onreset="return fi_reset(this)">
|
||||
<table>
|
||||
<tr><td><?php echo Util::ucFirst(Lang::$main['name']).Lang::$main['colon']; ?></td><td> <input type="text" name="na" size="30" <?php echo isset($this->filter['na']) ? 'value="'.Util::htmlEscape($this->filter['na']).'" ' : null; ?>/></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']; ?></a></div>
|
||||
|
||||
<div class="padded2 clear">
|
||||
<div style="float: right"><?php echo Lang::$main['refineSearch']; ?></div>
|
||||
<?php echo Lang::$main['match'].Lang::$main['colon']; ?><input type="radio" name="ma" value="" id="ma-0" <?php echo !isset($this->filter['ma']) ? 'checked="checked" ' : null ?>/><label for="ma-0"><?php echo Lang::$main['allFilter']; ?></label><input type="radio" name="ma" value="1" id="ma-1" <?php echo isset($this->filter['ma']) ? 'checked="checked" ' : null ?> /><label for="ma-1"><?php echo Lang::$main['oneFilter']; ?></label>
|
||||
</div>
|
||||
|
||||
<div class="clear"></div>
|
||||
|
||||
<div class="padded">
|
||||
<input type="submit" value="<?php echo Lang::$main['applyFilter']; ?>" />
|
||||
<input type="reset" value="<?php echo Lang::$main['resetForm']; ?>" />
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<div class="pad"></div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
fi_init('objects');
|
||||
<?php
|
||||
foreach ($this->filter['fi'] as $str):
|
||||
echo ' '.$str."\n";
|
||||
endforeach;
|
||||
?>
|
||||
//]]></script>
|
||||
|
||||
<div id="lv-generic" class="listview"></div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
<?php $this->lvBrick($this->lvData['file'], ['data' => $this->lvData['data'], 'params' => $this->lvData['params']]); ?>
|
||||
//]]></script>
|
||||
|
||||
<div class="clear"></div>
|
||||
</div><!-- main-contents -->
|
||||
</div><!-- main -->
|
||||
|
||||
<?php $this->brick('footer'); ?>
|
||||
Reference in New Issue
Block a user