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
/cache/*.tmp /cache/template/*
/cache/*.php /cache/alphaMaps/*.png
# generated files # generated files
/static/js/profile_all.js /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_SKILL', 15);
define('TYPE_CURRENCY', 17); define('TYPE_CURRENCY', 17);
define('CACHETYPE_PAGE', 0); define('CACHETYPE_NONE', 0); // page will not be cached
define('CACHETYPE_TOOLTIP', 1); define('CACHETYPE_PAGE', 1);
define('CACHETYPE_BUFF', 2); // only used by spells obviously define('CACHETYPE_TOOLTIP', 2);
define('CACHETYPE_SEARCH', 3); define('CACHETYPE_SEARCH', 3);
define('CACHETYPE_XML', 4); // only used by items 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_REGULAR', 0x10000000);
define('SEARCH_TYPE_OPEN', 0x20000000); define('SEARCH_TYPE_OPEN', 0x20000000);

View File

@@ -7,13 +7,14 @@ if (!defined('AOWOW_REVISION'))
trait DetailPage trait DetailPage
{ {
protected $hasComContent = true; 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]; // mode, type, typeId, localeId, category, filter
$key = [$this->mode, $this->type, $this->typeId, User::$localeId, '-1', '-1'];
if ($this->isLocalized)
$key[] = User::$localeId;
return implode('_', $key); return implode('_', $key);
} }
@@ -23,15 +24,19 @@ trait DetailPage
trait ListPage trait ListPage
{ {
protected $category = null; protected $category = null;
protected $validCats = [];
protected $typeId = 0; 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) //category
$key[] = User::$localeId; $key[] = $this->category ? implode('.', $this->category) : '-1';
// filter
$key[] = $this->filter ? md5(serialize($this->filter)) : '-1';
return implode('_', $key); return implode('_', $key);
} }
@@ -42,24 +47,23 @@ class GenericPage
{ {
protected $tpl = ''; protected $tpl = '';
protected $restrictedGroups = U_GROUP_NONE; protected $restrictedGroups = U_GROUP_NONE;
protected $mode = CACHETYPE_NONE;
protected $jsGlobals = []; protected $jsGlobals = [];
protected $jsgBuffer = [];
protected $isCachable = true;
protected $isLocalized = false;
protected $hasCacheFile = false;
protected $lvData = []; protected $lvData = [];
protected $title = [CFG_NAME]; // for title-Element protected $title = [CFG_NAME]; // for title-Element
protected $name = ''; // for h1-Element protected $name = ''; // for h1-Element
protected $tabId = 0; protected $tabId = 0;
protected $community = ['co' => [], 'sc' => [], 'vi' => []];
protected $js = []; protected $js = [];
protected $css = []; protected $css = [];
// private vars don't get cached
private $cacheDir = 'cache/template/';
private $jsgBuffer = [];
private $gLocale = []; private $gLocale = [];
protected $gPageInfo = []; private $gPageInfo = [];
private $gUser = []; private $gUser = [];
private $community = ['co' => [], 'sc' => [], 'vi' => []];
protected function generatePath() {} protected function generatePath() {}
protected function generateTitle() {} protected function generateTitle() {}
@@ -76,20 +80,25 @@ class GenericPage
else if (CFG_MAINTENANCE && User::isInGroup(U_GROUP_EMPLOYEE)) else if (CFG_MAINTENANCE && User::isInGroup(U_GROUP_EMPLOYEE))
Util::addNote(U_GROUP_EMPLOYEE, 'Maintenance mode enabled!'); Util::addNote(U_GROUP_EMPLOYEE, 'Maintenance mode enabled!');
if (isset($this->validCats) && !Util::isValidPage($this->validCats, $this->category)) // display modes
$this->error(); 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->gUser = User::getUserGlobals();
$this->gLocale = array( $this->gLocale = array(
'id' => User::$localeId, 'id' => User::$localeId,
'name' => User::$localeString 'name' => User::$localeString
); );
}
if (!$this->tpl)
return;
} }
private function prepare() private function prepareContent()
{ {
if (!$this->loadCache()) if (!$this->loadCache())
{ {
@@ -113,15 +122,47 @@ class GenericPage
public function display($override = '') public function display($override = '')
{ {
if (!$override) if ($override)
$this->prepare(); {
$this->addAnnouncements();
if (!$override && !$this->isSaneInclude('template/pages/', $this->tpl)) include('template/pages/'.$override.'.tpl.php');
die(User::isInGroup(U_GROUP_STAFF) ? 'Error: nonexistant template requestst: template/pages/'.$this->tpl.'.tpl.php' : null); 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 = []) public function gBrick($file, array $localVars = [])
@@ -130,7 +171,7 @@ class GenericPage
$$n = $v; $$n = $v;
if (!$this->isSaneInclude('template/globals/', $file)) 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 else
include('template/globals/'.$file.'.tpl.php'); include('template/globals/'.$file.'.tpl.php');
} }
@@ -141,7 +182,7 @@ class GenericPage
$$n = $v; $$n = $v;
if (!$this->isSaneInclude('template/bricks/', $file)) 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 else
include('template/bricks/'.$file.'.tpl.php'); include('template/bricks/'.$file.'.tpl.php');
} }
@@ -152,7 +193,7 @@ class GenericPage
$$n = $v; $$n = $v;
if (!$this->isSaneInclude('template/listviews/', $file)) 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 else
include('template/listviews/'.$file.'.tpl.php'); include('template/listviews/'.$file.'.tpl.php');
} }
@@ -168,6 +209,33 @@ class GenericPage
return true; 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) public function addJS($name, $unshift = false)
{ {
if (is_array($name)) if (is_array($name))
@@ -395,10 +463,18 @@ class GenericPage
public function notFound($subject) public function notFound($subject)
{ {
$this->subject = $subject; if ($this->mode == CACHETYPE_TOOLTIP)
$this->mysql = DB::Aowow()->getStatistics(); 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(); exit();
} }
@@ -424,44 +500,76 @@ class GenericPage
} }
// creates the cache file // 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; 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"; $data .= serialize($cache);
$cacheData .= serialize(str_replace(["\n", "\t"], ['\n', '\t'], $data)); }
else
$data .= (string)$saveString;
if ($filter) file_put_contents($file, $data);
$cacheData .= "\n".serialize($filter);
file_put_contents($file, $cacheData);
} }
// loads and evaluates the cache file // 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; 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) if (!$cache)
return false; return false;
$cache = explode("\n", $cache); $cache = explode("\n", $cache, 2);
@list($time, $rev) = explode(' ', $cache[0]); @list($time, $rev, $type) = explode(' ', $cache[0]);
$expireTime = $time + CFG_CACHE_DECAY; if ($time + CFG_CACHE_DECAY <= time() || $rev < AOWOW_REVISION)
if ($expireTime <= time() || $rev < AOWOW_REVISION)
return false; return false;
$data = str_replace(['\n', '\t'], ["\n", "\t"], unserialize($cache[1])); if ($type == '0')
if (isset($cache[2])) {
$filter = unserialize($cache[2]); $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::$localeId = isset(Util::$localeStrings[$use]) ? $use : 0;
self::$localeString = self::localeString(self::$localeId); self::$localeString = self::localeString(self::$localeId);
Lang::load(self::$localeString);
} }
public static function isInGroup($group) public static function isInGroup($group)
@@ -269,16 +267,16 @@ class User
return $set; return $set;
if ($_ = self::getCharacters()) if ($_ = self::getCharacters())
$subSet['characters'] = json_encode($_, JSON_NUMERIC_CHECK); $subSet['characters'] = $_;
if ($_ = self::getProfiles()) if ($_ = self::getProfiles())
$subSet['profiles'] = json_encode($_, JSON_NUMERIC_CHECK); $subSet['profiles'] = $_;
if ($_ = self::getWeightScales()) if ($_ = self::getWeightScales())
$subSet['weightscales'] = json_encode($_, JSON_NUMERIC_CHECK); $subSet['weightscales'] = $_;
if ($_ = self::getCookies()) if ($_ = self::getCookies())
$subSet['cookies'] = json_encode($_, JSON_NUMERIC_CHECK); $subSet['cookies'] = $_;
return array_merge($set, $subSet); 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) 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() public static function getCookies()
@@ -360,7 +358,7 @@ class User
if (self::$id) if (self::$id)
$data = DB::Aowow()->selectCol('SELECT name AS ARRAY_KEY, data FROM ?_account_cookies WHERE userId = ?d', 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() 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 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 // todo: translate and move to Lang
public static $spellEffectStrings = array( public static $spellEffectStrings = array(
0 => 'None', 0 => 'None',
@@ -979,6 +964,19 @@ class Util
return 'b'.strToUpper($_); 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) public static function jsEscape($data)
{ {
if (is_array($data)) if (is_array($data))
@@ -1203,30 +1201,6 @@ class Util
return $return; 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 // default ucFirst doesn't convert UTF-8 chars
public static function ucFirst($str) public static function ucFirst($str)
{ {
@@ -1336,538 +1310,6 @@ class Util
return $data; 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) public static function urlize($str)
{ {
$search = ['<', '>', ' / ', "'", '(', ')']; $search = ['<', '>', ' / ', "'", '(', ')'];

View File

@@ -4,50 +4,26 @@ if (!defined('AOWOW_REVISION'))
die('illegal access'); die('illegal access');
require 'includes/community.class.php'; // menuId 5: Object g_initPath()
// tabId 0: Database g_initHeader()
$_id = intVal($pageParam); class ObjectPage extends GenericPage
$_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']))
{ {
header('Content-type: application/x-javascript; charsetUTF-8'); use DetailPage;
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');
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 /* NOTE
@@ -56,443 +32,474 @@ if (!$smarty->loadCache($cacheKeyPage, $pageData))
all of this has to be done manually all of this has to be done manually
*/ */
public function __construct($__, $id)
/***********/
/* 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))
{ {
if ($h = $_['holidayId']) parent::__construct();
{
Util::$pageTemplate->extendGlobalIds(TYPE_WORLDEVENT, $_['id']);
$infobox[] = Util::ucFirst(Lang::$game['eventShort']).Lang::$colon.'[event='.$h.']';
}
}
// Reaction // temp locale
$_ = function ($r) if ($this->mode == CACHETYPE_TOOLTIP && isset($_GET['domain']))
{ Util::powerUseLocale($_GET['domain']);
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]';
// reqSkill $this->typeId = intVal($id);
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;
Util::$pageTemplate->extendGlobalIds(TYPE_ITEM, $idx); $this->subject = new GameObjectList(array(['id', $this->typeId]));
$l = Lang::$gameObject['key'].Lang::$colon.'[item='.$idx.']'; if ($this->subject->error)
} $this->notFound(Lang::$game['gameObject']);
// if no propper item is found use a skill $this->name = $this->subject->getField('name', true);
if ($locks) $this->gPageInfo = array(
$infobox[] = $l ? $l : array_pop($locks); 'type' => $this->type,
} 'typeId' => $this->typeId,
} 'name' => $this->name
// 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'
]
); );
} }
// tab: related spells protected function generatePath()
if ($_ = $object->getField('spells'))
{ {
$relSpells = new SpellList(array(['id', $_])); $this->path[] = $this->subject->getField('typeCat');
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')]"
]
);
}
} }
// tab: criteria of protected function generateTitle()
$acvs = new AchievementList(array(['ac.type', [ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT]], ['ac.value1', $_id]));
if (!$acvs->error)
{ {
$acvs->addGlobalsToJScript(GLOBALINFO_SELF | GLOBALINFO_RELATED); array_unshift($this->title, $this->subject->getField('name', true), Util::ucFirst(Lang::$game['gameObject']));
$pageData['relTabs'][] = array(
'file' => 'achievement',
'data' => $acvs->getListviewData(),
'params' => [
'tabs' => '$tabsRelated',
'id' => 'criteria-of',
'name' => '$LANG.tab_criteriaof'
]
);
} }
// tab: starts quest protected function generateContent()
// tab: ends quest
$startEnd = new QuestList(array(['qse.type', TYPE_OBJECT], ['qse.typeId', $_id]));
if (!$startEnd->error)
{ {
$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 ($h = $_['holidayId'])
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 (!empty($hiddenCols)) Util::$pageTemplate->extendGlobalIds(TYPE_WORLDEVENT, $_['id']);
foreach ($hiddenCols as $k => $str) $infobox[] = Util::ucFirst(Lang::$game['eventShort']).Lang::$main['colon'].'[event='.$h.']';
if (!empty($lv[$str])) }
unset($hiddenCols[$k]); }
if (!$lv['quest']) // Reaction
continue; $_ = 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'; $infobox[] = $buff;
$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
]
);
} }
}
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( $conditions = array(
'OR', 'OR',
['reqSourceItemId1', $reqIds], ['reqSourceItemId2', $reqIds], ['AND', ['effect1Id', [50, 76, 104, 105, 106, 107]], ['effect1MiscValue', $this->typeId]],
['reqSourceItemId3', $reqIds], ['reqSourceItemId4', $reqIds], ['AND', ['effect2Id', [50, 76, 104, 105, 106, 107]], ['effect2MiscValue', $this->typeId]],
['reqItemId1', $reqIds], ['reqItemId2', $reqIds], ['reqItemId3', $reqIds], ['AND', ['effect3Id', [50, 76, 104, 105, 106, 107]], ['effect3MiscValue', $this->typeId]]
['reqItemId4', $reqIds], ['reqItemId5', $reqIds], ['reqItemId6', $reqIds]
); );
$reqQuests = new QuestList($conditions); $summons = new SpellList($conditions);
$reqQuests->addGlobalsToJscript(); if (!$summons->error)
foreach ($reqQuests->iterate() as $qId => $__)
{ {
if (empty($reqQuests->requires[$qId][TYPE_ITEM])) $this->extendGlobalData($summons->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
continue;
foreach ($reqIds as $rId) $this->lvData[] = array(
if (in_array($rId, $reqQuests->requires[$qId][TYPE_ITEM])) 'file' => 'spell',
$reqQuest[$rId] = $reqQuests->id; '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( protected function generateTooltip($asError = false)
'file' => 'object', {
'data' => $sameModel->getListviewData(), if ($asError)
'params' => [ die('$WowheadPower.registerObject('.$this->typeId.', '.User::$localeId.', {});');
'tabs' => '$tabsRelated',
'name' => '$LANG.tab_samemodelas', $s = $this->subject->getSpawns(true);
'id' => 'same-model-as'
] $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'); die('illegal access');
$filter = []; // menuId 5: Object g_initPath()
$conditions = []; // tabId 0: Database g_initHeader()
$cat = Util::extractURLParams($pageParam); class ObjectsPage extends GenericPage
$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)
{ {
$path[] = $cat[0]; use ListPage;
array_unshift($title, Lang::$gameObject['cat'][$cat[0]]);
$conditions[] = ['typeCat', (int)$cat[0]];
}
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(); public function __construct($pageCall, $pageParam)
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)
{ {
$lv['params']['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_objectsfound', $objects->getMatches(), CFG_SQL_LIMIT_DEFAULT); $this->category = Util::extractURLParams($pageParam);
$lv['params']['_truncated'] = 1;
parent::__construct();
$this->name = Util::ucFirst(Lang::$game['gameObjects']);
$this->subCat = $pageParam ? '='.$pageParam : '';
} }
if ($objectFilter->error) protected function generateContent()
$lv['params']['_errors'] = '$1'; {
$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: fields:
[ [
{ {
id: 'wowheadurl', id: 'wowheadurl',
type: 'text', type: 'text',
label: 'Aowow URL', label: 'Aowow URL',
size: 40 size: 40
}, },
{ {
id: 'markuptag', id: 'markuptag',
type: 'text', type: 'text',
label: 'Markup Tag', label: 'Markup Tag',
size: 40 size: 40
} }
], ],
@@ -18405,7 +18405,7 @@ var Links = new function() {
onShow: function(form) { onShow: function(form) {
setTimeout(function() { setTimeout(function() {
document.getElementsByName('ingamelink')[0].select(); $(form.ingamelink).select();
}, 50); }, 50);
setTimeout(Lightbox.reveal, 100); setTimeout(Lightbox.reveal, 100);
} }

View File

@@ -2,7 +2,7 @@
if (!empty($this->pageText)): if (!empty($this->pageText)):
?> ?>
<div class="clear"></div> <div class="clear"></div>
<h3><?php echo Lang:$main['content']; ?></h3> <h3><?php echo Lang::$main['content']; ?></h3>
<div id="book-generic"></div> <div id="book-generic"></div>
<script>//<![CDATA[ <script>//<![CDATA[

View File

@@ -15,7 +15,7 @@ foreach ($this->css as $css):
echo ' <style type="text/css">'.$css['string']."</style>\n"; echo ' <style type="text/css">'.$css['string']."</style>\n";
elseif (!empty($css['path'])): elseif (!empty($css['path'])):
echo ' '.(!empty($css['ieCond']) ? '<!--[if '.$css['ieCond'].']>' : null) . 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"; (!empty($css['ieCond']) ? '<![endif]-->' : null)."\n";
endif; endif;
endforeach; endforeach;
@@ -39,7 +39,7 @@ endif;
<?php <?php
foreach ($this->js as $js): foreach ($this->js as $js):
if (!empty($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; endif;
endforeach; endforeach;
?> ?>

View File

@@ -22,7 +22,14 @@ endif;
// view in 3D // view in 3D
if (isset($this->redButtons[BUTTON_VIEW3D])): if (isset($this->redButtons[BUTTON_VIEW3D])):
if ($b = $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: 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>'; 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; endif;

View File

@@ -1,38 +1,37 @@
{include file='header.tpl'} <?php $this->brick('header'); ?>
<div class="main" id="main"> <div class="main" id="main">
<div class="main-precontents" id="main-precontents"></div> <div class="main-precontents" id="main-precontents"></div>
<div class="main-contents" id="main-contents"> <div class="main-contents" id="main-contents">
{if !empty($announcements)} <?php $this->brick('announcement'); ?>
{foreach from=$announcements item=item}
{include file='bricks/announcement.tpl' an=$item}
{/foreach}
{/if}
<script type="text/javascript">//<![CDATA[ <script type="text/javascript">//<![CDATA[
{include file='bricks/community.tpl'} <?php
var g_pageInfo = {ldelim}type: {$type}, typeId: {$typeId}, name: '{$name|escape:"quotes"}'{rdelim}; $this->brick('community');
g_initPath({$path}); echo "var g_pageInfo = ".json_encode($this->gPageInfo, JSON_NUMERIC_CHECK).";\n" .
"g_initPath(".json_encode($this->path, JSON_NUMERIC_CHECK).");\n";
?>
//]]></script> //]]></script>
{include file='bricks/infobox.tpl'} <?php $this->brick('infobox'); ?>
<div class="text"> <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#} <div>{#This_Object_can_be_found_in#}
{strip}
<span id="locations"> <span id="locations">
{foreach from=$object.position item=zone name=zone} {foreach from=$object.position item=zone name=zone}
<a href="javascript:;" onclick=" <a href="javascript:;" onclick="
myMapper.update( myMapper.update(
{ldelim} {
{if $zone.atid} {if $zone.atid}
zone:{$zone.atid} zone:{$zone.atid}
{if $zone.points} {if $zone.points}
@@ -45,7 +44,7 @@
coords:[ coords:[
{foreach from=$zone.points item=point name=point} {foreach from=$zone.points item=point name=point}
[{$point.x},{$point.y}, [{$point.x},{$point.y},
{ldelim} {
label:'$<br> label:'$<br>
<div class=q0> <div class=q0>
<small>{#Respawn#}: <small>{#Respawn#}:
@@ -55,37 +54,40 @@
{if isset($point.events)}<br>{$point.events|escape:"quotes"}{/if} {if isset($point.events)}<br>{$point.events|escape:"quotes"}{/if}
</small> </small>
</div>',type:'{$point.type}' </div>',type:'{$point.type}'
{rdelim}] }]
{if !$smarty.foreach.point.last},{/if} {if !$smarty.foreach.point.last},{/if}
{/foreach} {/foreach}
] ]
{/if} {/if}
{rdelim}); });
g_setSelectedLink(this, 'mapper'); return false" onmousedown="return false"> 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} {$zone.name}</a>{if $zone.population > 1}&nbsp;({$zone.population}){/if}{if $smarty.foreach.zone.last}.{else}, {/if}
{/foreach} {/foreach}
</span></div> </span></div>
{/strip}
<div id="mapper-generic"></div> <div id="mapper-generic"></div>
<div class="clear"></div> <div class="clear"></div>
<script type="text/javascript"> <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(); $WH.gE($WH.ge('locations'), 'a')[0].onclick();
</script> </script>
{else} <?php
{$lang.unkPosition} else:
{/if} echo Lang::$gameObject['unkPosition'];
{include file='bricks/book.tpl'} endif;
<h2 class="clear">{$lang.related}</h2> $this->brick('book');
?>
<h2 class="clear"><?php echo Lang::$main['related']; ?></h2>
</div> </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-contents -->
</div><!-- main --> </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'); ?>