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:
Sarjuuk
2014-06-21 13:54:41 +02:00
parent 56934dbe51
commit 9c7c2e29b5
17 changed files with 1398 additions and 1259 deletions

6
.gitignore vendored
View File

@@ -1,6 +1,6 @@
# smarty cache
/cache/*.tmp
/cache/*.php
# cache
/cache/template/*
/cache/alphaMaps/*.png
# generated files
/static/js/profile_all.js

View File

@@ -1 +0,0 @@
<html><body bgcolor="#FFFFFF"></body></html>

View File

@@ -1 +0,0 @@
<html><body bgcolor="#FFFFFF"></body></html>

View File

@@ -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);

View File

@@ -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
View 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;
}
}
?>

View File

@@ -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()

View File

@@ -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 = ['<', '>', ' / ', "'", '(', ')'];

View File

@@ -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');
?>

View File

@@ -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');
?>

View File

@@ -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);
}

View File

@@ -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[

View File

@@ -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;
?>

View File

@@ -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;

View File

@@ -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}&nbsp;({$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'); ?>

View File

@@ -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>&nbsp;<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'}

View 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>&nbsp;<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'); ?>