mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Compare commits
105 Commits
v2.0
...
a135dfce90
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a135dfce90 | ||
|
|
0d42d2a2c4 | ||
|
|
fa89a5ad1e | ||
|
|
6eb5a67add | ||
|
|
8a169eb400 | ||
|
|
cf4e8a527c | ||
|
|
48564ab8b5 | ||
|
|
edc297f97a | ||
|
|
5d02a20719 | ||
|
|
f44de66de7 | ||
|
|
16c5b73cd3 | ||
|
|
9020e36db6 | ||
|
|
597898450d | ||
|
|
6a94888686 | ||
|
|
e3d6f7b3a7 | ||
|
|
37380ff515 | ||
|
|
8212811970 | ||
|
|
1e9e406ff0 | ||
|
|
3984bd0ae2 | ||
|
|
441ad38543 | ||
|
|
88cc76feae | ||
|
|
96c777191d | ||
|
|
40b2830cad | ||
|
|
9741774683 | ||
|
|
e8bc37f82f | ||
|
|
7cbe1f6007 | ||
|
|
3a25c2390f | ||
|
|
cf2ace805b | ||
|
|
2f8e035783 | ||
|
|
1a55b30766 | ||
|
|
6d7f9c0f00 | ||
|
|
862b3dff73 | ||
|
|
b1f22f7e68 | ||
|
|
1d922c1147 | ||
|
|
f9ace6a671 | ||
|
|
6ea1457c4f | ||
|
|
f522c960d9 | ||
|
|
1365cdb261 | ||
|
|
9b591e7a3a | ||
|
|
6da71afc68 | ||
|
|
033a9181ae | ||
|
|
1dcc9363da | ||
|
|
51b6e29316 | ||
|
|
14c159c164 | ||
|
|
33cd290dc3 | ||
|
|
2e029f3d96 | ||
|
|
6a32c770cd | ||
|
|
4d421d2bbb | ||
|
|
176cf137fb | ||
|
|
830edb8265 | ||
|
|
7d8b524478 | ||
|
|
95918c0410 | ||
|
|
a275955ee3 | ||
|
|
37beaa2db5 | ||
|
|
c0097f3987 | ||
|
|
92c58cc5d1 | ||
|
|
04f3aa7a82 | ||
|
|
65d490a8ae | ||
|
|
816eacaf73 | ||
|
|
034eca1f58 | ||
|
|
a33abb84fe | ||
|
|
fb7b22db36 | ||
|
|
dd838fa994 | ||
|
|
d32074fdcd | ||
|
|
494061de82 | ||
|
|
9b0aa5c885 | ||
|
|
40e98081c9 | ||
|
|
77f2a0c21d | ||
|
|
465e019eaa | ||
|
|
63053757c9 | ||
|
|
a96f6c4cdf | ||
|
|
b832fc172c | ||
|
|
196f60f176 | ||
|
|
204d4b8ae2 | ||
|
|
5d2fd00358 | ||
|
|
1dcdf9623b | ||
|
|
215ad39cc6 | ||
|
|
a9ed897ea6 | ||
|
|
3edac3c77a | ||
|
|
95ee9d2c25 | ||
|
|
d79742d599 | ||
|
|
e300086cc8 | ||
|
|
a7e9ac2cf2 | ||
|
|
05f5b0ed34 | ||
|
|
e37620c01b | ||
|
|
c40bd3851b | ||
|
|
452615a92d | ||
|
|
704894c1e3 | ||
|
|
045c16c241 | ||
|
|
7b429811a9 | ||
|
|
aa7c0186fc | ||
|
|
7b752143a0 | ||
|
|
baf4ba5b98 | ||
|
|
eb95b03e31 | ||
|
|
4fe35d9e3c | ||
|
|
5355989015 | ||
|
|
9fc84cdf9e | ||
|
|
a6108be400 | ||
|
|
ff690770b5 | ||
|
|
6263ccd92a | ||
|
|
60eb816002 | ||
|
|
bc112b2b16 | ||
|
|
6d86f880f4 | ||
|
|
bd1f139c2e | ||
|
|
36aa33ac26 |
@@ -4,7 +4,7 @@ if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
function extAuth(string &$usernameOrEmail, string $password, int &$userId = 0, int &$userGroup = -1) : int
|
||||
function extAuth(string &$usernameOrEmail, #[\SensitiveParameter] string $password, int &$userId = 0, int &$userGroup = -1) : int
|
||||
{
|
||||
/*
|
||||
insert some auth mechanism here
|
||||
|
||||
@@ -21,7 +21,7 @@ class AchievementBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'achievement';
|
||||
protected string $pageName = 'achievement';
|
||||
@@ -107,15 +107,32 @@ class AchievementBaseResponse extends TemplateResponse implements ICache
|
||||
default => Lang::game('si', SIDE_BOTH) // 0, 3
|
||||
};
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::achievement('id') . $this->typeId;
|
||||
|
||||
// icon
|
||||
if ($_ = $this->subject->getField('iconId'))
|
||||
{
|
||||
$infobox[] = Util::ucFirst(lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$infobox[] = Util::ucFirst(Lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$this->extendGlobalIds(Type::ICON, $_);
|
||||
}
|
||||
|
||||
// profiler relateed (note that this is part of the cache. I don't think this is important enough to calc for every view)
|
||||
if (Cfg::get('PROFILER_ENABLE') && !($this->subject->getField('flags') & ACHIEVEMENT_FLAG_COUNTER))
|
||||
{
|
||||
$x = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_completion_achievements WHERE `achievementId` = ?d', $this->typeId);
|
||||
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `custom` = 0 AND `stub` = 0');
|
||||
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
|
||||
|
||||
// completion row added by InfoboxMarkup
|
||||
}
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', !($this->subject->getField('flags') & ACHIEVEMENT_FLAG_COUNTER));
|
||||
|
||||
|
||||
/**********/
|
||||
|
||||
@@ -11,7 +11,7 @@ class AchievementsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::ACHIEVEMENT;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'achievements';
|
||||
protected string $pageName = 'achievements';
|
||||
@@ -54,6 +54,12 @@ class AchievementsBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new AchievementListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -69,13 +75,9 @@ class AchievementsBaseResponse extends TemplateResponse implements ICache
|
||||
if ($this->category)
|
||||
$conditions[] = ['category', end($this->category)];
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
if ($fiCnd = $this->filter->getConditions())
|
||||
$conditions[] = $fiCnd;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
@@ -119,7 +121,7 @@ class AchievementsBaseResponse extends TemplateResponse implements ICache
|
||||
$conditions = [];
|
||||
if ($fiCnd)
|
||||
$conditions[] = $fiCnd;
|
||||
if ($catList = DB::Aowow()->SelectCol('SELECT `id` FROM ?_achievementcategory WHERE `parentCat` IN (?a) OR `parentCat2` IN (?a) ', end($this->category), end($this->category)))
|
||||
if ($catList = DB::Aowow()->SelectCol('SELECT `id` FROM ?_achievementcategory WHERE `parentCat` IN (?a) OR `parentCat2` IN (?a) ', $this->category, $this->category))
|
||||
$conditions[] = ['category', $catList];
|
||||
|
||||
$acvList = new AchievementList($conditions, ['calcTotal' => true]);
|
||||
|
||||
@@ -10,7 +10,7 @@ class AreatriggerBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
protected int $requiredUserGroup = U_GROUP_STAFF;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
|
||||
@@ -11,7 +11,7 @@ class AreatriggersBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::AREATRIGGER;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
protected int $requiredUserGroup = U_GROUP_STAFF;
|
||||
|
||||
protected string $template = 'areatriggers';
|
||||
@@ -33,6 +33,12 @@ class AreatriggersBaseResponse extends TemplateResponse implements ICache
|
||||
parent::__construct($pageParam);
|
||||
|
||||
$this->filter = new AreaTriggerListFilter($this->_get['filter'] ?? '');
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -40,8 +46,6 @@ class AreatriggersBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('areatriggers'));
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
$fiForm = $this->filter->values;
|
||||
|
||||
|
||||
@@ -73,8 +77,6 @@ class AreatriggersBaseResponse extends TemplateResponse implements ICache
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
$tabData = [];
|
||||
$trigger = new AreaTriggerList($conditions, ['calcTotal' => true]);
|
||||
if (!$trigger->error)
|
||||
|
||||
@@ -46,21 +46,24 @@ class ArenateamBaseResponse extends TemplateResponse
|
||||
|
||||
// 3 possibilities
|
||||
// 1) already synced to aowow
|
||||
if ($subject = DB::Aowow()->selectRow('SELECT `id`, `realmGUID`, `cuFlags` FROM ?_profiler_arena_team WHERE `realm` = ?d AND `nameUrl` = ?', $this->realmId, Profiler::urlize($this->subjectName)))
|
||||
if ($subject = DB::Aowow()->selectRow('SELECT `id`, `realmGUID`, `stub` FROM ?_profiler_arena_team WHERE `realm` = ?d AND `nameUrl` = ?', $this->realmId, Profiler::urlize($this->subjectName)))
|
||||
{
|
||||
$this->typeId = $subject['id'];
|
||||
|
||||
if ($subject['cuFlags'] & PROFILER_CU_NEEDS_RESYNC)
|
||||
if ($subject['stub'])
|
||||
$this->handleIncompleteData(Type::ARENA_TEAM, $subject['realmGUID']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) not yet synced but exists on realm (wont work if we get passed an urlized name, but there is nothing we can do about it)
|
||||
else if ($subject = DB::Characters($this->realmId)->selectRow('SELECT at.`arenaTeamId` AS "realmGUID", at.`name`, at.`type` FROM arena_team at WHERE at.`name` = ?', Util::ucFirst($this->subjectName)))
|
||||
$subjects = DB::Characters($this->realmId)->select('SELECT at.`arenaTeamId` AS "realmGUID", at.`name`, at.`type` FROM arena_team at WHERE at.`name` = ?', $this->subjectName);
|
||||
if ($subject = array_filter($subjects, fn($x) => Util::lower($x['name']) == Util::lower($this->subjectName)))
|
||||
{
|
||||
$subject = $subject[0];
|
||||
$subject['realm'] = $this->realmId;
|
||||
$subject['cuFlags'] = PROFILER_CU_NEEDS_RESYNC;
|
||||
$subject['stub'] = 1;
|
||||
$subject['nameUrl'] = Profiler::urlize($subject['name']);
|
||||
|
||||
// create entry from realm with basic info
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team (?#) VALUES (?a)', array_keys($subject), array_values($subject));
|
||||
|
||||
@@ -53,6 +53,12 @@ class ArenateamsBaseResponse extends TemplateResponse implements IProfilerList
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new ArenaTeamListFilter($this->_get['filter'] ?? '', ['realms' => $realms]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class ClassBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
private const TC_CLASS_IDS = [null, 8, 3, 1, 5, 4, 9, 6, 2, 7, null, 0]; // see TalentCalc.js
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'class';
|
||||
@@ -103,6 +103,13 @@ class ClassBaseResponse extends TemplateResponse implements ICache
|
||||
if ($specList)
|
||||
$infobox[] = Lang::game('specs').'[ul][li]'.implode('[/li][li]', $specList).'[/li][/ul]';
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::chrClass('id') . $this->typeId;
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class ClassesBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::CHR_CLASS;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'classes';
|
||||
|
||||
@@ -47,7 +47,7 @@ class CommentDownvotereplyResponse extends TextResponse
|
||||
User::canSupervote() ? -2 : -1
|
||||
);
|
||||
|
||||
if (!$ok)
|
||||
if (!is_int($ok))
|
||||
{
|
||||
trigger_error('CommentDownvotereplyResponse - write to db failed', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'write to db failed' : '');
|
||||
|
||||
@@ -47,7 +47,7 @@ class CommentUpvotereplyResponse extends TextResponse
|
||||
User::canSupervote() ? 2 : 1
|
||||
);
|
||||
|
||||
if (!$ok)
|
||||
if (!is_int($ok))
|
||||
{
|
||||
trigger_error('CommentUpvotereplyResponse - write to db failed', E_USER_ERROR);
|
||||
$this->generate404(User::isInGroup(U_GROUP_STAFF) ? 'write to db failed' : '');
|
||||
|
||||
@@ -106,7 +106,7 @@ class CompareBaseResponse extends TemplateResponse
|
||||
protected static function checkCompareString(string $val) : string
|
||||
{
|
||||
$val = urldecode($val);
|
||||
if (preg_match('/[^\d\.:;]/', $val))
|
||||
if (preg_match('/[^-?\d\.:;]/', $val))
|
||||
return '';
|
||||
|
||||
return $val;
|
||||
|
||||
@@ -11,7 +11,7 @@ class CurrenciesBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::CURRENCY;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'currencies';
|
||||
|
||||
@@ -10,7 +10,7 @@ class CurrencyBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'currency';
|
||||
@@ -72,13 +72,20 @@ class CurrencyBaseResponse extends TemplateResponse implements ICache
|
||||
if ($_ = $this->subject->getField('cap'))
|
||||
$infobox[] = Lang::currency('cap').Lang::nf($_);
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::currency('id') . $this->typeId;
|
||||
|
||||
// icon
|
||||
if ($_ = $this->subject->getField('iconId'))
|
||||
{
|
||||
$infobox[] = Util::ucFirst(lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$infobox[] = Util::ucFirst(Lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$this->extendGlobalIds(Type::ICON, $_);
|
||||
}
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ if (!defined('AOWOW_REVISION'))
|
||||
class DataBaseResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedGET = array(
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFrom'] ],
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkLocale' ]],
|
||||
't' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine' ]],
|
||||
'catg' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'skill' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkSkill' ]],
|
||||
|
||||
@@ -10,7 +10,7 @@ class EmoteBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'emote';
|
||||
@@ -94,6 +94,9 @@ class EmoteBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::emote('id') . $this->typeId;
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ class EmotesBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
protected int $type = Type::EMOTE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
|
||||
@@ -10,7 +10,7 @@ class EnchantmentBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'enchantment';
|
||||
protected string $pageName = 'enchantment';
|
||||
@@ -85,6 +85,13 @@ class EnchantmentBaseResponse extends TemplateResponse implements ICache
|
||||
$infobox[] = $foo;
|
||||
}
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::enchantment('id') . $this->typeId;
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class EnchantmentsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::ENCHANTMENT;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'enchantments';
|
||||
protected string $pageName = 'enchantments';
|
||||
@@ -35,6 +35,12 @@ class EnchantmentsBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new EnchantmentListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -42,18 +48,13 @@ class EnchantmentsBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('enchantments'));
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
$conditions = [];
|
||||
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
|
||||
@@ -10,7 +10,7 @@ class EventBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'event';
|
||||
@@ -88,9 +88,16 @@ class EventBaseResponse extends TemplateResponse implements ICache
|
||||
$infobox[] = Lang::npc('rank', 3).Lang::main('colon').'[npc='.$_.']';
|
||||
}
|
||||
|
||||
// display internal id to staff
|
||||
if (User::isInGroup(U_GROUP_STAFF))
|
||||
$infobox[] = 'Event-Id'.Lang::main('colon').$this->typeId;
|
||||
// id
|
||||
$infobox[] = Lang::event('id') . $this->typeId;
|
||||
|
||||
// display holiday id to staff
|
||||
if ($_holidayId && User::isInGroup(U_GROUP_STAFF))
|
||||
$infobox[] = 'Holiday ID'.Lang::main('colon').$_holidayId;
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
@@ -11,7 +11,7 @@ class EventsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::WORLDEVENT;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'events';
|
||||
|
||||
@@ -10,7 +10,7 @@ class FactionBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'faction';
|
||||
@@ -96,8 +96,25 @@ class FactionBaseResponse extends TemplateResponse implements ICache
|
||||
if ($_ = $this->subject->getField('side'))
|
||||
$infobox[] = Lang::main('side').'[span class=icon-'.($_ == SIDE_ALLIANCE ? 'alliance' : 'horde').']'.Lang::game('si', $_).'[/span]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
// id
|
||||
$infobox[] = Lang::faction('id') . $this->typeId;
|
||||
|
||||
// profiler relateed (note that this is part of the cache. I don't think this is important enough to calc for every view)
|
||||
if (Cfg::get('PROFILER_ENABLE') && !($this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW))
|
||||
{
|
||||
$x = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_completion_reputation WHERE `exalted` = 1 AND `factionId` = ?d', $this->typeId);
|
||||
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `custom` = 0 AND `stub` = 0');
|
||||
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
|
||||
|
||||
// completion row added by InfoboxMarkup
|
||||
}
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox) // unsure if this should be tracked (needs data dump in User::getCompletion())
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', 0);
|
||||
|
||||
|
||||
/****************/
|
||||
@@ -208,7 +225,8 @@ class FactionBaseResponse extends TemplateResponse implements ICache
|
||||
);
|
||||
|
||||
if ($items->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?items&filter=cr=17;crs='.$this->typeId.';crv=0');
|
||||
if (!is_null(ItemListFilter::getCriteriaIndex(17, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?items&filter=cr=17;crs='.$this->typeId.';crv=0');
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, ItemList::$brickFile, 'itemStandingCol'));
|
||||
}
|
||||
@@ -242,7 +260,8 @@ class FactionBaseResponse extends TemplateResponse implements ICache
|
||||
);
|
||||
|
||||
if ($killCreatures->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?npcs&filter=cr=42;crs='.$this->typeId.';crv=0');
|
||||
if (!is_null(CreatureListFilter::getCriteriaIndex(42, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?npcs&filter=cr=42;crs='.$this->typeId.';crv=0');
|
||||
|
||||
$this->addDataLoader('zones');
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, CreatureList::$brickFile, 'npcRepCol'));
|
||||
@@ -263,7 +282,8 @@ class FactionBaseResponse extends TemplateResponse implements ICache
|
||||
);
|
||||
|
||||
if ($members->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?npcs&filter=cr=3;crs='.$this->typeId.';crv=0');
|
||||
if (!is_null(CreatureListFilter::getCriteriaIndex(3, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?npcs&filter=cr=3;crs='.$this->typeId.';crv=0');
|
||||
|
||||
$this->addDataLoader('zones');
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, CreatureList::$brickFile));
|
||||
@@ -301,7 +321,8 @@ class FactionBaseResponse extends TemplateResponse implements ICache
|
||||
);
|
||||
|
||||
if ($quests->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?quests&filter=cr=1;crs='.$this->typeId.';crv=0');
|
||||
if (!is_null(QuestListFilter::getCriteriaIndex(1, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?quests&filter=cr=1;crs='.$this->typeId.';crv=0');
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, QuestList::$brickFile, 'questRepCol'));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class FactionsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::FACTION;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'factions';
|
||||
|
||||
@@ -33,7 +33,7 @@ class GuideChangelogResponse extends TemplateResponse
|
||||
if (!$guide->canBeViewed() && !$guide->userCanView())
|
||||
$this->forward('?guides='.$guide->getField('category'));
|
||||
|
||||
$this->h1 = lang::guide('clTitle', [$this->_get['id'], $guide->getField('title')]);
|
||||
$this->h1 = Lang::guide('clTitle', [$this->_get['id'], $guide->getField('title')]);
|
||||
if (!$this->h1)
|
||||
$this->h1 = $guide->getField('name');
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class GuideEditResponse extends TemplateResponse
|
||||
'description' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkDescription'] ],
|
||||
'changelog' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ],
|
||||
'body' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ],
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFrom'] ],
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkLocale'] ],
|
||||
'category' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_value' => 1, 'max_value' => 9] ],
|
||||
'specId' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_value' => -1, 'max_value' => 2, 'default' => -1]],
|
||||
'classId' => ['filter' => FILTER_VALIDATE_INT, 'options' => ['min_value' => 1, 'max_value' => 11, 'default' => 0]]
|
||||
|
||||
@@ -10,7 +10,7 @@ class GuideBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'guide';
|
||||
@@ -68,12 +68,12 @@ class GuideBaseResponse extends TemplateResponse implements ICache
|
||||
$this->contribute = CONTRIBUTE_NONE;
|
||||
}
|
||||
|
||||
if ($this->articleUrl)
|
||||
// owner or staff and manual rev passed
|
||||
if ($this->subject->userCanView() && $this->_get['rev'])
|
||||
$this->guideRevision = $this->_get['rev'];
|
||||
// has publicly viewable version
|
||||
else if ($this->subject->canBeViewed())
|
||||
$this->guideRevision = $this->subject->getField('rev');
|
||||
else if ($this->subject->userCanView())
|
||||
$this->guideRevision = $this->_get['rev'] ?? $this->subject->getField('latest');
|
||||
else
|
||||
$this->subject->getField('rev');
|
||||
|
||||
$this->h1 = $this->subject->getField('name');
|
||||
|
||||
@@ -127,7 +127,7 @@ class GuideBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], __forceTabs: true);
|
||||
|
||||
// the article text itself is added by PageTemplate::addArticle()
|
||||
// the article text itself is added by TemplateResponse::addArticle()
|
||||
parent::generate();
|
||||
|
||||
$this->result->registerDisplayHook('infobox', [self::class, 'infoboxHook']);
|
||||
|
||||
@@ -10,7 +10,7 @@ class GuidesBaseResponse extends TemplateResponse // implements ICache
|
||||
{
|
||||
use TrListPage/* , TrCache */;
|
||||
|
||||
// protected int $cacheType = CACHE_TYPE_PAGE; // really do? cache would need to be destroyed externally with each guide status update
|
||||
// protected int $cacheType = CACHE_TYPE_LIST_PAGE; // really do? cache would need to be destroyed externally with each guide status update
|
||||
protected int $type = Type::GUIDE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
|
||||
@@ -46,21 +46,24 @@ class GuildBaseResponse extends TemplateResponse
|
||||
|
||||
// 3 possibilities
|
||||
// 1) already synced to aowow
|
||||
if ($subject = DB::Aowow()->selectRow('SELECT `id`, `realmGUID`, `cuFlags` FROM ?_profiler_guild WHERE `realm` = ?d AND `nameUrl` = ?', $this->realmId, Profiler::urlize($this->subjectName)))
|
||||
if ($subject = DB::Aowow()->selectRow('SELECT `id`, `realmGUID`, `stub` FROM ?_profiler_guild WHERE `realm` = ?d AND `nameUrl` = ?', $this->realmId, Profiler::urlize($this->subjectName)))
|
||||
{
|
||||
$this->typeId = $subject['id'];
|
||||
|
||||
if ($subject['cuFlags'] & PROFILER_CU_NEEDS_RESYNC)
|
||||
if ($subject['stub'])
|
||||
$this->handleIncompleteData(Type::GUILD, $subject['realmGUID']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) not yet synced but exists on realm (wont work if we get passed an urlized name, but there is nothing we can do about it)
|
||||
else if ($subject = DB::Characters($this->realmId)->selectRow('SELECT `guildid` AS "realmGUID", `name` FROM guild WHERE `name` = ?', Util::ucFirst($this->subjectName)))
|
||||
$subjects = DB::Characters($this->realmId)->select('SELECT `guildid` AS "realmGUID", `name` FROM guild WHERE `name` = ?', $this->subjectName);
|
||||
if ($subject = array_filter($subjects, fn($x) => Util::lower($x['name']) == Util::lower($this->subjectName)))
|
||||
{
|
||||
$subject = $subject[0];
|
||||
$subject['realm'] = $this->realmId;
|
||||
$subject['cuFlags'] = PROFILER_CU_NEEDS_RESYNC;
|
||||
$subject['stub'] = 1;
|
||||
$subject['nameUrl'] = Profiler::urlize($subject['name']);
|
||||
|
||||
// create entry from realm with basic info
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_guild (?#) VALUES (?a)', array_keys($subject), array_values($subject));
|
||||
|
||||
@@ -53,6 +53,12 @@ class GuildsBaseResponse extends TemplateResponse implements IProfilerList
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new GuildListFilter($this->_get['filter'] ?? '', ['realms' => $realms]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ class IconBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'icon';
|
||||
protected string $pageName = 'icon';
|
||||
|
||||
@@ -11,7 +11,7 @@ class IconsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::ICON;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'icons';
|
||||
protected string $pageName = 'icons';
|
||||
@@ -32,6 +32,12 @@ class IconsBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new IconListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -43,13 +49,9 @@ class IconsBaseResponse extends TemplateResponse implements ICache
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
|
||||
@@ -10,7 +10,7 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'item';
|
||||
protected string $pageName = 'item';
|
||||
@@ -103,10 +103,13 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
SIDE_BOTH => Lang::game('si', SIDE_BOTH)
|
||||
};
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::item('id') . $this->typeId;
|
||||
|
||||
// icon
|
||||
if ($_ = $this->subject->getField('iconId'))
|
||||
{
|
||||
$infobox[] = Util::ucFirst(lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$infobox[] = Util::ucFirst(Lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$this->extendGlobalIds(Type::ICON, $_);
|
||||
}
|
||||
|
||||
@@ -145,9 +148,9 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
$infobox[] = Lang::item('tool').'[url=?items&filter=cr=91;crs='.$tId.';crv=0]'.Util::localizedString($tName, 'name').'[/url]';
|
||||
|
||||
// extendedCost
|
||||
if (!empty($this->subject->getExtendedCost([], $_reqRating)[$this->subject->id]))
|
||||
if (!empty($this->subject->getExtendedCost([], $_reqRating)[$this->typeId]))
|
||||
{
|
||||
$vendors = $this->subject->getExtendedCost()[$this->subject->id];
|
||||
$vendors = $this->subject->getExtendedCost()[$this->typeId];
|
||||
$stack = $this->subject->getField('buyCount');
|
||||
$divisor = $stack;
|
||||
$each = '';
|
||||
@@ -316,8 +319,15 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
if ($_bagFamily & 0x0100)
|
||||
$infobox[] = Lang::item('atKeyring');
|
||||
|
||||
// completion row added by InfoboxMarkup
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
$hasCompletion = !($this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW) && ($_class == ITEM_CLASS_RECIPE || ($_class == ITEM_CLASS_MISC && in_array($_subClass, [2, 5, -7])));
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', $hasCompletion);
|
||||
|
||||
|
||||
/****************/
|
||||
@@ -473,9 +483,9 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
// tabs: this item contains..
|
||||
$sourceFor = array(
|
||||
[LOOT_ITEM, $this->subject->id, '$LANG.tab_contains', 'contains', ['$Listview.extraCols.percent'], [] ],
|
||||
[LOOT_PROSPECTING, $this->subject->id, '$LANG.tab_prospecting', 'prospecting', ['$Listview.extraCols.percent'], ['side', 'slot', 'reqlevel']],
|
||||
[LOOT_MILLING, $this->subject->id, '$LANG.tab_milling', 'milling', ['$Listview.extraCols.percent'], ['side', 'slot', 'reqlevel']],
|
||||
[LOOT_ITEM, $this->typeId, '$LANG.tab_contains', 'contains', ['$Listview.extraCols.percent'], [] ],
|
||||
[LOOT_PROSPECTING, $this->typeId, '$LANG.tab_prospecting', 'prospecting', ['$Listview.extraCols.percent'], ['side', 'slot', 'reqlevel']],
|
||||
[LOOT_MILLING, $this->typeId, '$LANG.tab_milling', 'milling', ['$Listview.extraCols.percent'], ['side', 'slot', 'reqlevel']],
|
||||
[LOOT_DISENCHANT, $this->subject->getField('disenchantId'), '$LANG.tab_disenchanting', 'disenchanting', ['$Listview.extraCols.percent'], ['side', 'slot', 'reqlevel']]
|
||||
);
|
||||
|
||||
@@ -585,12 +595,14 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
), SpellList::$brickFile));
|
||||
}
|
||||
|
||||
// tab: unlocks (object or item) - LOCK_TYPE_ITEM: 1
|
||||
// tab: unlocks (object or item)
|
||||
$lockIds = DB::Aowow()->selectCol(
|
||||
'SELECT `id` FROM ?_lock WHERE (`type1` = 1 AND `properties1` = ?d) OR
|
||||
(`type2` = 1 AND `properties2` = ?d) OR (`type3` = 1 AND `properties3` = ?d) OR
|
||||
(`type4` = 1 AND `properties4` = ?d) OR (`type5` = 1 AND `properties5` = ?d)',
|
||||
$this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId
|
||||
'SELECT `id` FROM ?_lock WHERE (`type1` = ?d AND `properties1` = ?d) OR
|
||||
(`type2` = ?d AND `properties2` = ?d) OR (`type3` = ?d AND `properties3` = ?d) OR
|
||||
(`type4` = ?d AND `properties4` = ?d) OR (`type5` = ?d AND `properties5` = ?d)',
|
||||
LOCK_TYPE_ITEM, $this->typeId, LOCK_TYPE_ITEM, $this->typeId,
|
||||
LOCK_TYPE_ITEM, $this->typeId, LOCK_TYPE_ITEM, $this->typeId,
|
||||
LOCK_TYPE_ITEM, $this->typeId
|
||||
);
|
||||
|
||||
if ($lockIds)
|
||||
@@ -726,9 +738,9 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
// tab: sold by
|
||||
if (!empty($this->subject->getExtendedCost()[$this->subject->id]))
|
||||
if (!empty($this->subject->getExtendedCost()[$this->typeId]))
|
||||
{
|
||||
$vendors = $this->subject->getExtendedCost()[$this->subject->id];
|
||||
$vendors = $this->subject->getExtendedCost()[$this->typeId];
|
||||
$soldBy = new CreatureList(array(['id', array_keys($vendors)]));
|
||||
if (!$soldBy->error)
|
||||
{
|
||||
|
||||
@@ -192,7 +192,7 @@ class ItemXmlResponse extends TextResponse implements ICache
|
||||
}
|
||||
|
||||
// link
|
||||
$xml->addChild('link', Cfg::get('HOST_URL').'?item='.$this->subject->id);
|
||||
$xml->addChild('link', Cfg::get('HOST_URL').'?item='.$this->typeId);
|
||||
|
||||
$this->result = $root->asXML();
|
||||
}
|
||||
@@ -220,8 +220,7 @@ class ItemXmlResponse extends TextResponse implements ICache
|
||||
{
|
||||
return array(
|
||||
$this->type, // DBType
|
||||
$this->typeId, // DBTypeId
|
||||
-1, // category
|
||||
$this->typeId, // DBTypeId/category
|
||||
-1, // staff mask (content does not diff)
|
||||
'' // misc (unused)
|
||||
);
|
||||
|
||||
@@ -11,7 +11,7 @@ class ItemsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::ITEM;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'items';
|
||||
protected string $pageName = 'items';
|
||||
@@ -99,6 +99,12 @@ class ItemsBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new ItemListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -110,14 +116,9 @@ class ItemsBaseResponse extends TemplateResponse implements ICache
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
$this->filter->evalWeights();
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
|
||||
/*******************/
|
||||
/* evaluate filter */
|
||||
|
||||
@@ -10,7 +10,7 @@ class ItemsetBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'itemset';
|
||||
protected string $pageName = 'itemset';
|
||||
@@ -95,15 +95,7 @@ class ItemsetBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
// itemLevel
|
||||
if ($min = $this->subject->getField('minLevel'))
|
||||
{
|
||||
$foo = Lang::game('level').Lang::main('colon').$min;
|
||||
$max = $this->subject->getField('maxLevel');
|
||||
|
||||
if ($min < $max)
|
||||
$foo .= ' - '.$max;
|
||||
|
||||
$infobox[] = $foo;
|
||||
}
|
||||
$infobox[] = Lang::game('level').Lang::main('colon').Util::createNumRange($min, $this->subject->getField('maxLevel'), ' - ');
|
||||
|
||||
// class
|
||||
if ($cl = Lang::getClassString($this->subject->getField('classMask'), $jsg, Lang::FMT_MARKUP))
|
||||
@@ -125,6 +117,13 @@ class ItemsetBaseResponse extends TemplateResponse implements ICache
|
||||
if ($_ta)
|
||||
$infobox[] = Lang::itemset('_tag').'[url=?itemsets&filter=ta='.$_ta.']'.Lang::itemset('notes', $_ta).'[/url]';
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::itemset('id') . $this->subject->getField('refSetId');
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class ItemsetsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::ITEMSET;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'itemsets';
|
||||
protected string $pageName = 'itemsets';
|
||||
@@ -32,6 +32,12 @@ class ItemsetsBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new ItemsetListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -43,13 +49,9 @@ class ItemsetsBaseResponse extends TemplateResponse implements ICache
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
|
||||
@@ -14,15 +14,20 @@ class LatestcommentsRssResponse extends TextResponse
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
foreach (CommunityContent::getCommentPreviews(dateFmt: false) as $comment)
|
||||
foreach (CommunityContent::getCommentPreviews(['comments' => 1, 'replies' => 1], dateFmt: false) as $comment)
|
||||
{
|
||||
if (empty($comment['commentid']))
|
||||
$url = Cfg::get('HOST_URL').'/?go-to-comment&id='.$comment['id'];
|
||||
else
|
||||
$url = Cfg::get('HOST_URL').'/?go-to-reply&id='.$comment['id'];
|
||||
|
||||
// todo (low): preview should be html-formated
|
||||
$this->feedData[] = array(
|
||||
'title' => [true, [], Lang::typeName($comment['type']).Lang::main('colon').htmlentities($comment['subject'])],
|
||||
'link' => [false, [], Cfg::get('HOST_URL').'/?go-to-comment&id='.$comment['id']],
|
||||
'link' => [false, [], $url],
|
||||
'description' => [true, [], htmlentities($comment['preview'])."<br /><br />".Lang::main('byUser', [$comment['user'], '']) . Util::formatTimeDiff($comment['date'])],
|
||||
'pubDate' => [false, [], date(DATE_RSS, $comment['date'])],
|
||||
'guid' => [false, [], Cfg::get('HOST_URL').'/?go-to-comment&id='.$comment['id']]
|
||||
'guid' => [false, [], $url]
|
||||
// 'domain' => [false, [], null]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ if (!defined('AOWOW_REVISION'))
|
||||
class LocaleBaseResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedGET = array(
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => [Locale::class, 'tryFrom']]
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkLocale']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
|
||||
@@ -10,7 +10,7 @@ class MailBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'mail';
|
||||
@@ -108,6 +108,9 @@ class MailBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::mail('id') . $this->typeId;
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class MailsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::MAIL;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'mails';
|
||||
|
||||
@@ -8,8 +8,6 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class MapsBaseResponse extends TemplateResponse
|
||||
{
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
|
||||
protected string $template = 'maps';
|
||||
protected string $pageName = 'maps';
|
||||
protected ?int $activeTab = parent::TAB_TOOLS;
|
||||
|
||||
@@ -10,7 +10,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'npc';
|
||||
protected string $pageName = 'npc';
|
||||
@@ -194,6 +194,13 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
if ($this->subject->getField('npcflag') & (NPC_FLAG_SPIRIT_HEALER | NPC_FLAG_SPIRIT_GUIDE))
|
||||
$infobox[] = Lang::npc('extraFlags', CREATURE_FLAG_EXTRA_GHOST_VISIBILITY);
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::npc('id') . $this->typeId;
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
{
|
||||
// AI
|
||||
@@ -526,7 +533,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
$soldItems = new ItemList(array(['id', $sells]));
|
||||
if (!$soldItems->error)
|
||||
{
|
||||
$colAddIn = null;
|
||||
$colAddIn = '';
|
||||
$extraCols = ["\$Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')", '$Listview.extraCols.cost'];
|
||||
|
||||
$lvData = $soldItems->getListviewData(ITEMINFO_VENDOR, [Type::NPC => [$this->typeId]]);
|
||||
@@ -825,7 +832,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
$spill[0][1] = $set[1][1] / 2;
|
||||
|
||||
$spillover[$factions->getField('cat')] = $spill;
|
||||
$set[6] = $factions->getField('cat'); // set spillover
|
||||
$set[5] = $factions->getField('cat'); // set spillover
|
||||
}
|
||||
|
||||
$result[] = $set;
|
||||
@@ -865,7 +872,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
foreach ($reputation as $i => [, $data])
|
||||
{
|
||||
foreach ($data as [$factionId, , , , , , $spillover])
|
||||
foreach ($data as [$factionId, , , , , $spillover])
|
||||
{
|
||||
if (!$spillover)
|
||||
continue;
|
||||
@@ -999,10 +1006,13 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
$modes['ranged'][] = sprintf($modeRow, $m, Lang::nf($ranged[0]).' - '.Lang::nf($ranged[1]));
|
||||
}
|
||||
|
||||
// todo: resistances can be present/missing in either $stats or $modes
|
||||
// should be handled separately..?
|
||||
|
||||
if ($modes)
|
||||
foreach ($stats as $k => $v)
|
||||
if ($v)
|
||||
$stats[$k] = sprintf($hint, implode('[/tr][tr]', $modes[$k]), $v, $k);
|
||||
$stats[$k] = isset($modes[$k]) ? sprintf($hint, implode('[/tr][tr]', $modes[$k]), $v, $k) : $v;
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class NpcsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::NPC;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'npcs';
|
||||
protected string $pageName = 'npcs';
|
||||
@@ -35,6 +35,12 @@ class NpcsBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new CreatureListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -46,13 +52,9 @@ class NpcsBaseResponse extends TemplateResponse implements ICache
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
if ($this->category)
|
||||
{
|
||||
$conditions[] = ['type', $this->category[0]];
|
||||
|
||||
@@ -10,7 +10,7 @@ class ObjectBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'object';
|
||||
protected string $pageName = 'object';
|
||||
@@ -148,9 +148,7 @@ class ObjectBaseResponse extends TemplateResponse implements ICache
|
||||
if ($this->subject->getField('lootStack'))
|
||||
{
|
||||
[$min, $max, $restock] = $this->subject->getField('lootStack');
|
||||
$buff = Lang::spell('spellModOp', 4).Lang::main('colon').$min;
|
||||
if ($min < $max)
|
||||
$buff .= Lang::game('valueDelim').$max;
|
||||
$buff = Lang::spell('spellModOp', 4).Lang::main('colon').Util::createNumRange($min, $max);
|
||||
|
||||
// since Veins don't have charges anymore, the timer is questionable
|
||||
$infobox[] = $restock > 1 ? '[tooltip name=restock]'.Lang::gameObject('restock', [Util::formatTime($restock * 1000)]).'[/tooltip][span class=tip tooltip=restock]'.$buff.'[/span]' : $buff;
|
||||
@@ -163,10 +161,7 @@ class ObjectBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->extendGlobalIds(Type::ZONE, $zone);
|
||||
$m = Lang::game('meetingStone').'[zone='.$zone.']';
|
||||
|
||||
$l = $minLevel;
|
||||
if ($minLevel > 1 && $maxLevel > $minLevel)
|
||||
$l .= Lang::game('valueDelim').min($maxLevel, MAX_LEVEL);
|
||||
$l = Util::createNumRange($minLevel, min($maxLevel, MAX_LEVEL));
|
||||
|
||||
$infobox[] = $l ? '[tooltip name=meetingstone]'.Lang::game('reqLevel', [$l]).'[/tooltip][span class=tip tooltip=meetingstone]'.$m.'[/span]' : $m;
|
||||
}
|
||||
@@ -181,11 +176,11 @@ class ObjectBaseResponse extends TemplateResponse implements ICache
|
||||
if ($minTime > 1 || $minPlayer || $radius)
|
||||
$buff .= Lang::main('colon').'[ul]';
|
||||
|
||||
if ($minTime > 1)
|
||||
$buff .= '[li]'.Lang::game('duration').Lang::main('colon').($maxTime > $minTime ? Util::FormatTime($maxTime * 1000, true).' - ' : '').Util::FormatTime($minTime * 1000, true).'[/li]';
|
||||
if ($minTime > 1) // sign shenannigans reverse the display order
|
||||
$buff .= '[li]'.Lang::game('duration').Lang::main('colon').Util::createNumRange(-$maxTime, -$minTime, fn: fn($x) => Util::FormatTime(-$x * 1000, true)).'[/li]';
|
||||
|
||||
if ($minPlayer)
|
||||
$buff .= '[li]'.Lang::main('players').Lang::main('colon').$minPlayer.($maxPlayer > $minPlayer ? ' - '.$maxPlayer : '').'[/li]';
|
||||
$buff .= '[li]'.Lang::main('players').Lang::main('colon').Util::createNumRange($minPlayer, $maxPlayer).'[/li]';
|
||||
|
||||
if ($radius)
|
||||
$buff .= '[li]'.Lang::spell('range', [$radius]).'[/li]';
|
||||
@@ -196,6 +191,13 @@ class ObjectBaseResponse extends TemplateResponse implements ICache
|
||||
$infobox[] = $buff;
|
||||
}
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::gameObject('id') . $this->typeId;
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
// AI
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
if ($_ = $this->subject->getField('ScriptOrAI'))
|
||||
|
||||
@@ -11,7 +11,7 @@ class ObjectsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::OBJECT;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'objects';
|
||||
protected string $pageName = 'objects';
|
||||
@@ -35,6 +35,12 @@ class ObjectsBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new GameObjectListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -46,16 +52,12 @@ class ObjectsBaseResponse extends TemplateResponse implements ICache
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
if ($this->category)
|
||||
$conditions[] = ['typeCat', (int)$this->category[0]];
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
|
||||
@@ -10,7 +10,7 @@ class PetBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'pet';
|
||||
@@ -73,13 +73,20 @@ class PetBaseResponse extends TemplateResponse implements ICache
|
||||
if ($this->subject->getField('exotic'))
|
||||
$infobox[] = '[url=?spell=53270]'.Lang::pet('exotic').'[/url]';
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::pet('id') . $this->typeId;
|
||||
|
||||
// icon
|
||||
if ($_ = $this->subject->getField('iconId'))
|
||||
{
|
||||
$infobox[] = Util::ucFirst(lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$infobox[] = Util::ucFirst(Lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$this->extendGlobalIds(Type::ICON, $_);
|
||||
}
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class PetsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::PET;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'pets';
|
||||
|
||||
@@ -37,10 +37,8 @@ class ProfileDeleteResponse extends TextResponse
|
||||
|
||||
// only flag as deleted; only custom profiles
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_profiler_profiles SET `cuFlags` = `cuFlags` | ?d WHERE `id` IN (?a) AND `cuFlags` & ?d {AND `user` = ?d}',
|
||||
PROFILER_CU_DELETED,
|
||||
'UPDATE ?_profiler_profiles SET `deleted` = 1 WHERE `id` IN (?a) AND `custom` = 1 {AND `user` = ?d}',
|
||||
$this->_get['id'],
|
||||
PROFILER_CU_PROFILE,
|
||||
User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU) ? DBSIMPLE_SKIP : User::$id
|
||||
);
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ class ProfileLinkResponse extends TextResponse
|
||||
// only link characters, not custom profiles
|
||||
$newId = DB::Aowow()->query(
|
||||
'REPLACE INTO ?_account_profiles (`accountId`, `profileId`, `extraFlags`)
|
||||
SELECT ?d, p.`id`, 0 FROM ?_profiler_profiles p WHERE p.`id` = ?d AND (`cuFlags` & ?d) = 0',
|
||||
User::$id, $this->_get['id'], PROFILER_CU_PROFILE
|
||||
SELECT ?d, p.`id`, 0 FROM ?_profiler_profiles p WHERE p.`id` = ?d AND `custom` = 0',
|
||||
User::$id, $this->_get['id']
|
||||
);
|
||||
|
||||
if (!is_int($newId))
|
||||
|
||||
@@ -47,7 +47,7 @@ class ProfileLoadResponse extends TextResponse
|
||||
return;
|
||||
}
|
||||
|
||||
if (($pBase['cuFlags'] & PROFILER_CU_DELETED) && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
if ($pBase['deleted'] && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
return;
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ class ProfileLoadResponse extends TextResponse
|
||||
if ($rId == $pBase['realm'])
|
||||
break;
|
||||
|
||||
if (!$rData) // realm doesn't exist or access is restricted
|
||||
if ($pBase['realm'] && !$rData) // realm doesn't exist or access is restricted
|
||||
return;
|
||||
|
||||
$profile = array(
|
||||
@@ -103,7 +103,7 @@ class ProfileLoadResponse extends TextResponse
|
||||
'activity' => [], // recent raid activity [achievementId => 1] (is a subset of statistics)
|
||||
);
|
||||
|
||||
if ($pBase['cuFlags'] & PROFILER_CU_PROFILE)
|
||||
if ($pBase['custom'])
|
||||
{
|
||||
// this parameter is _really_ strange .. probably still not doing this right
|
||||
$profile['source'] = $pBase['realm'] ? $pBase['sourceId'] : 0;
|
||||
@@ -135,7 +135,7 @@ class ProfileLoadResponse extends TextResponse
|
||||
$profile['pets'] = $pets;
|
||||
|
||||
// source for custom profiles; profileId => [name, ownerId, iconString(optional)]
|
||||
if ($customs = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `name`, `user`, `icon` FROM ?_profiler_profiles WHERE `sourceId` = ?d AND `sourceId` <> `id` {AND (`cuFlags` & ?d) = 0}', $pBase['id'], User::isInGroup(U_GROUP_STAFF) ? DBSIMPLE_SKIP : PROFILER_CU_DELETED))
|
||||
if ($customs = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `name`, `user`, `icon` FROM ?_profiler_profiles WHERE `sourceId` = ?d AND `sourceId` <> `id` {AND `deleted` = ?d}', $pBase['id'], User::isInGroup(U_GROUP_STAFF) ? DBSIMPLE_SKIP : 0))
|
||||
{
|
||||
foreach ($customs as $id => $cu)
|
||||
{
|
||||
|
||||
@@ -67,11 +67,11 @@ class ProfileBaseResponse extends TemplateResponse
|
||||
|
||||
// 3 possibilities
|
||||
// 1) already synced to aowow
|
||||
if ($subject = DB::Aowow()->selectRow('SELECT `id`, `realmGUID`, `cuFlags` FROM ?_profiler_profiles WHERE `realm` = ?d AND `realmGUID` IS NOT NULL AND `name` = ? AND `renameItr` = ?d', $this->realmId, Util::ucFirst($this->subjectName), $rnItr))
|
||||
if ($subject = DB::Aowow()->selectRow('SELECT `id`, `realmGUID`, `stub` FROM ?_profiler_profiles WHERE `realm` = ?d AND `custom` = 0 AND `name` = ? AND `renameItr` = ?d', $this->realmId, Util::ucFirst($this->subjectName), $rnItr))
|
||||
{
|
||||
$this->typeId = $subject['id'];
|
||||
|
||||
if ($subject['cuFlags'] & PROFILER_CU_NEEDS_RESYNC)
|
||||
if ($subject['stub'])
|
||||
$this->handleIncompleteData(Type::PROFILE, $subject['realmGUID']);
|
||||
|
||||
return;
|
||||
@@ -82,27 +82,29 @@ class ProfileBaseResponse extends TemplateResponse
|
||||
$this->notFound();
|
||||
|
||||
// 2) not yet synced but exists on realm (and not a gm character)
|
||||
if ($subject = DB::Characters($this->realmId)->selectRow(
|
||||
$subjects = DB::Characters($this->realmId)->select(
|
||||
'SELECT c.`guid` AS "realmGUID", c.`name`, c.`race`, c.`class`, c.`level`, c.`gender`, c.`at_login`, g.`guildid` AS "guildGUID", IFNULL(g.`name`, "") AS "guildName", IFNULL(gm.`rank`, 0) AS "guildRank"
|
||||
FROM characters c
|
||||
LEFT JOIN guild_member gm ON gm.`guid` = c.`guid`
|
||||
LEFT JOIN guild g ON g.`guildid` = gm.`guildid`
|
||||
WHERE c.`name` = ? AND `level` <= ?d AND (`extra_flags` & ?d) = 0',
|
||||
Util::ucFirst($this->subjectName), MAX_LEVEL, Profiler::CHAR_GMFLAGS
|
||||
))
|
||||
);
|
||||
if ($subject = array_filter($subjects, fn($x) => Util::lower($x['name']) == Util::lower($this->subjectName)))
|
||||
{
|
||||
$subject['realm'] = $this->realmId;
|
||||
$subject['cuFlags'] = PROFILER_CU_NEEDS_RESYNC;
|
||||
$subject = $subject[0];
|
||||
$subject['realm'] = $this->realmId;
|
||||
$subject['stub'] = 1;
|
||||
|
||||
if ($subject['at_login'] & 0x1)
|
||||
$subject['renameItr'] = DB::Aowow()->selectCell('SELECT MAX(`renameItr`) FROM ?_profiler_profiles WHERE `realm` = ?d AND `realmGUID` IS NOT NULL AND `name` = ?', $this->realmId, $subject['name']);
|
||||
$subject['renameItr'] = DB::Aowow()->selectCell('SELECT MAX(`renameItr`) FROM ?_profiler_profiles WHERE `realm` = ?d AND `custom` = 0 AND `name` = ?', $this->realmId, $subject['name']);
|
||||
|
||||
if ($subject['guildGUID'])
|
||||
{
|
||||
// create empty guild if nessecary to satisfy foreign keys
|
||||
// create empty guild if necessary to satisfy foreign keys
|
||||
$subject['guild'] = DB::Aowow()->selectCell('SELECT `id` FROM ?_profiler_guild WHERE `realm` = ?d AND `realmGUID` = ?d', $this->realmId, $subject['guildGUID']);
|
||||
if (!$subject['guild'])
|
||||
$subject['guild'] = DB::Aowow()->query('INSERT INTO ?_profiler_guild (`realm`, `realmGUID`, `cuFlags`, `name`) VALUES (?d, ?d, ?d, ?)', $this->realmId, $subject['guildGUID'], PROFILER_CU_NEEDS_RESYNC, $subject['guildName']);
|
||||
$subject['guild'] = DB::Aowow()->query('INSERT INTO ?_profiler_guild (`realm`, `realmGUID`, `stub`, `name`, `nameUrl`) VALUES (?d, ?d, 1, ?, ?)', $this->realmId, $subject['guildGUID'], $subject['guildName'], Profiler::urlize($subject['guildName']));
|
||||
}
|
||||
|
||||
unset($subject['guildGUID'], $subject['guildName'], $subject['at_login']);
|
||||
@@ -122,7 +124,10 @@ class ProfileBaseResponse extends TemplateResponse
|
||||
protected function generate() : void
|
||||
{
|
||||
if ($this->doResync)
|
||||
{
|
||||
parent::generate();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->typeId)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ class ProfilePowerResponse extends TextResponse implements ICache
|
||||
if (preg_match('/([^\-]+)-(\d+)/i', $this->subjectName, $m))
|
||||
[, $this->subjectName, $renameItr] = $m;
|
||||
|
||||
if ($x = DB::Aowow()->selectCell('SELECT `id` FROM ?_profiler_profiles WHERE `realm` = ?d AND `realmGUID` IS NOT NULL AND LOWER(`name`) = ? AND `renameItr` = ?d', $this->realmId, $this->subjectName, $renameItr ?? 0))
|
||||
if ($x = DB::Aowow()->selectCell('SELECT `id` FROM ?_profiler_profiles WHERE `realm` = ?d AND `custom` = 0 AND `name` = ? AND `renameItr` = ?d', $this->realmId, Util::ucWords($this->subjectName), $renameItr ?? 0))
|
||||
$this->typeId = $x;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class ProfileSaveResponse extends TextResponse
|
||||
'copy' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'public' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'gearscore' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'inv' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned'], 'flags' => FILTER_REQUIRE_ARRAY]
|
||||
'inv' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdList'], 'flags' => FILTER_REQUIRE_ARRAY]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
@@ -72,7 +72,8 @@ class ProfileSaveResponse extends TextResponse
|
||||
'glyphs2' => $this->_post['glyphs2'],
|
||||
'gearscore' => $this->_post['gearscore'],
|
||||
'icon' => $this->_post['icon'],
|
||||
'cuFlags' => PROFILER_CU_PROFILE | ($this->_post['public'] ? PROFILER_CU_PUBLISHED : 0)
|
||||
'custom' => 1,
|
||||
'cuFlags' => $this->_post['public'] ? PROFILER_CU_PUBLISHED : 0
|
||||
);
|
||||
|
||||
// remnant of a conflict between wotlk generic icons and cata+ auto-generated, char-based icons (see profile=avatar)
|
||||
@@ -88,7 +89,7 @@ class ProfileSaveResponse extends TextResponse
|
||||
if ($_ = $this->_post['copy']) // gets set to source profileId when "save as" is clicked. Whats the difference to 'source' though?
|
||||
{
|
||||
// get character origin info if possible
|
||||
if ($r = DB::Aowow()->selectCell('SELECT `realm` FROM ?_profiler_profiles WHERE `id` = ?d AND `realm` IS NOT NULL', $_))
|
||||
if ($r = DB::Aowow()->selectCell('SELECT `realm` FROM ?_profiler_profiles WHERE `id` = ?d AND `custom` = 0', $_))
|
||||
$cuProfile['realm'] = $r;
|
||||
|
||||
$cuProfile['sourceId'] = $_;
|
||||
@@ -105,7 +106,7 @@ class ProfileSaveResponse extends TextResponse
|
||||
}
|
||||
else // new
|
||||
{
|
||||
$nProfiles = DB::Aowow()->selectCell('SELECT COUNT(*) FROM ?_profiler_profiles WHERE `user` = ?d AND (`cuFlags` & ?d) = 0 AND `realmGUID` IS NULL', User::$id, PROFILER_CU_DELETED);
|
||||
$nProfiles = DB::Aowow()->selectCell('SELECT COUNT(*) FROM ?_profiler_profiles WHERE `user` = ?d AND `deleted` = 0 AND `custom` = 1', User::$id);
|
||||
if ($nProfiles < 10 || User::isPremium())
|
||||
if ($newId = DB::Aowow()->query('INSERT INTO ?_profiler_profiles (?#) VALUES (?a)', array_keys($cuProfile), array_values($cuProfile)))
|
||||
$charId = $newId;
|
||||
@@ -139,6 +140,12 @@ class ProfileSaveResponse extends TextResponse
|
||||
{
|
||||
foreach ($this->_post['inv'] as $slot => $itemData)
|
||||
{
|
||||
if (!$itemData)
|
||||
{
|
||||
trigger_error('ProfileSaveResponse::generate - skipping malformed inventory definition for slot #'.$slot.': '.Util::toString($itemData), E_USER_NOTICE);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($slot + 1 == array_sum($itemData)) // only slot definition set => empty slot
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_items WHERE `id` = ?d AND `slot` = ?d', $charId, $itemData[0]);
|
||||
|
||||
@@ -39,7 +39,7 @@ class ProfileStatusResponse extends TextResponse
|
||||
|
||||
if (!$ids)
|
||||
{
|
||||
trigger_error('ProfileStatusResponse - no profileIds to resync'.($this->_get['guild'] ? ' for guild #'.$this->_get['guild'] : ($this->_get['arena-team'] ? ' for areana team #'.$this->_get['arena-team'] : '')), E_USER_ERROR);
|
||||
trigger_error('ProfileStatusResponse - no profileIds to resync'.($this->_get['guild'] ? ' for guild #' : ($this->_get['arena-team'] ? ' for areana team #' : ' #')).Util::toString($this->_get['id']), E_USER_WARNING);
|
||||
$this->result = Util::toJSON([1, [PR_QUEUE_STATUS_ERROR, 0, 0, PR_QUEUE_ERROR_CHAR]]);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,12 @@ class ProfilesBaseResponse extends TemplateResponse implements IProfilerList
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new ProfileListFilter($this->_get['filter'] ?? '', ['realms' => $realms]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -64,8 +70,6 @@ class ProfilesBaseResponse extends TemplateResponse implements IProfilerList
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('profiles'));
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
@@ -94,8 +98,6 @@ class ProfilesBaseResponse extends TemplateResponse implements IProfilerList
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
$fiExtraCols = $this->filter->fiExtraCols;
|
||||
|
||||
$lvData = [];
|
||||
|
||||
@@ -10,7 +10,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'quest';
|
||||
protected string $pageName = 'quest';
|
||||
@@ -64,6 +64,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
$_flags = $this->subject->getField('flags');
|
||||
$_specialFlags = $this->subject->getField('specialFlags');
|
||||
$_side = ChrRace::sideFromMask($this->subject->getField('reqRaceMask'));
|
||||
$hasCompletion = !($_flags & QUEST_FLAG_UNAVAILABLE || $this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
|
||||
|
||||
/*************/
|
||||
@@ -271,8 +272,25 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
$infobox[] = Lang::game('difficulty').implode('[small] [/small]', $_);
|
||||
}
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::quest('id') . $this->typeId;
|
||||
|
||||
// profiler relateed (note that this is part of the cache. I don't think this is important enough to calc for every view)
|
||||
if (Cfg::get('PROFILER_ENABLE') && $hasCompletion)
|
||||
{
|
||||
$x = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_completion_quests WHERE `questId` = ?d', $this->typeId);
|
||||
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `custom` = 0 AND `stub` = 0');
|
||||
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
|
||||
|
||||
// completion row added by InfoboxMarkup
|
||||
}
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', $hasCompletion);
|
||||
|
||||
|
||||
/*******************/
|
||||
@@ -300,7 +318,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
$olItems[$i] = [$id, $qty, $id == $olItems[0][0]];
|
||||
}
|
||||
|
||||
if ($ids = array_column($olItems, 0))
|
||||
if ($ids = array_filter(array_column($olItems, 0)))
|
||||
{
|
||||
$olItemData = new ItemList(array(['id', $ids]));
|
||||
$this->extendGlobalData($olItemData->getJSGlobals(GLOBALINFO_SELF));
|
||||
@@ -478,7 +496,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
if ($_ = $this->subject->getField('sourceSpellId'))
|
||||
{
|
||||
$this->extendGlobalIds(Type::SPELL, $_);
|
||||
$this->objectiveList[] = [0, new IconElement(Type::SPELL, $_, SpellList::getName($_), extraText: Lang::quest('provided'), element: 'iconlist-icon')];
|
||||
$this->objectiveList[] = [0, new IconElement(Type::SPELL, $_, SpellList::getName($_), extraText: Lang::quest('provided'), element: 'iconlist-icon', size: IconElement::SIZE_SMALL)];
|
||||
}
|
||||
|
||||
// required money
|
||||
|
||||
@@ -32,7 +32,7 @@ class QuestsBaseResponse extends TemplateResponse implements ICache
|
||||
);
|
||||
|
||||
protected int $type = Type::QUEST;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'quests';
|
||||
protected string $pageName = 'quests';
|
||||
@@ -53,6 +53,12 @@ class QuestsBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new QuestListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -64,13 +70,9 @@ class QuestsBaseResponse extends TemplateResponse implements ICache
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
if (isset($this->category[1]))
|
||||
$conditions[] = ['zoneOrSort', $this->category[1]];
|
||||
else if (isset($this->category[0]))
|
||||
|
||||
@@ -16,7 +16,7 @@ class RaceBaseResponse extends TemplateResponse implements ICache
|
||||
[7952, 33554], null, [16264, 33557], [17584, 33657]
|
||||
);
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'race';
|
||||
@@ -99,6 +99,13 @@ class RaceBaseResponse extends TemplateResponse implements ICache
|
||||
$infobox[] = Lang::race('startZone').Lang::main('colon').'[zone='.$_.']';
|
||||
}
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::race('id') . $this->typeId;
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
@@ -108,12 +115,14 @@ class RaceBaseResponse extends TemplateResponse implements ICache
|
||||
/****************/
|
||||
|
||||
$this->expansion = Util::$expansionString[$this->subject->getField('expansion')];
|
||||
$this->headIcons = ['race_'.$ra->json().'_male', 'race_'.$ra->json().'_female'];
|
||||
$this->redButtons = array(
|
||||
BUTTON_WOWHEAD => true,
|
||||
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId]
|
||||
);
|
||||
|
||||
if ($_ = $ra->json())
|
||||
$this->headIcons = ['race_'.$_.'_male', 'race_'.$_.'_female'];
|
||||
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
|
||||
@@ -11,7 +11,7 @@ class RacesBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::CHR_RACE;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'races';
|
||||
|
||||
@@ -70,7 +70,7 @@ class SearchBaseResponse extends TemplateResponse implements ICache
|
||||
$this->lvTabs->addListviewTab(new Listview(...$lvData));
|
||||
|
||||
// we already have a target > can't have more targets > no redirects
|
||||
if ($canRedirect && $redirectTo)
|
||||
if (($canRedirect && $redirectTo) || count($lvData[0]['data']) > 1)
|
||||
$canRedirect = false;
|
||||
|
||||
if ($canRedirect) // note - we are very lucky that in case of searches $template is identical to the typeString
|
||||
|
||||
@@ -10,7 +10,7 @@ class SkillBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'skill';
|
||||
@@ -70,6 +70,9 @@ class SkillBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::skill('id') . $this->typeId;
|
||||
|
||||
// icon
|
||||
if ($_ = $this->subject->getField('iconId'))
|
||||
{
|
||||
@@ -77,6 +80,10 @@ class SkillBaseResponse extends TemplateResponse implements ICache
|
||||
$this->extendGlobalIds(Type::ICON, $_);
|
||||
}
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
|
||||
@@ -220,6 +227,26 @@ class SkillBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
// tab: modified by [spell]
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['AND', ['effect1AuraId', [SPELL_AURA_MOD_SKILL, SPELL_AURA_MOD_SKILL_TALENT]], ['effect1MiscValue', $this->typeId]],
|
||||
['AND', ['effect2AuraId', [SPELL_AURA_MOD_SKILL, SPELL_AURA_MOD_SKILL_TALENT]], ['effect2MiscValue', $this->typeId]],
|
||||
['AND', ['effect3AuraId', [SPELL_AURA_MOD_SKILL, SPELL_AURA_MOD_SKILL_TALENT]], ['effect3MiscValue', $this->typeId]]
|
||||
);
|
||||
$modBy = new SpellList($conditions);
|
||||
if (!$modBy->error)
|
||||
{
|
||||
$this->extendGlobalData($modBy->getJSGlobals());
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $modBy->getListviewData(),
|
||||
'id' => 'modified-by',
|
||||
'name' => '$LANG.tab_modifiedby',
|
||||
'hiddenCols' => ['skill'],
|
||||
), SpellList::$brickFile));
|
||||
}
|
||||
|
||||
// tab: spells [spells] (exclude first tab)
|
||||
$reqClass = 0x0;
|
||||
$reqRace = 0x0;
|
||||
|
||||
@@ -11,7 +11,7 @@ class SkillsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::SKILL;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'skills';
|
||||
|
||||
@@ -10,7 +10,7 @@ class SoundBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'sound';
|
||||
protected string $pageName = 'sound';
|
||||
@@ -212,7 +212,7 @@ class SoundBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
if ($worldStates = array_filter($zoneIds, function ($x) { return $x['worldStateId'] > 0; }))
|
||||
if ($worldStates = array_filter($zoneIds, fn($x) => $x['worldStateId'] > 0))
|
||||
{
|
||||
$tabData['extraCols'] = ['$Listview.extraCols.condition'];
|
||||
|
||||
@@ -222,7 +222,7 @@ class SoundBaseResponse extends TemplateResponse implements ICache
|
||||
Conditions::extendListviewRow($zoneData[$state['id']], Conditions::SRC_NONE, $this->typeId, [Conditions::WORLD_STATE, $state['worldStateId'], $state['worldStateValue']]);
|
||||
else
|
||||
foreach ($zoneData as &$d)
|
||||
if (in_array($state['id'], $d['subzones']))
|
||||
if (in_array($state['id'], $d['subzones'] ?? []))
|
||||
Conditions::extendListviewRow($d, Conditions::SRC_NONE, $this->typeId, [Conditions::WORLD_STATE, $state['worldStateId'], $state['worldStateValue']]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class SoundsBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::SOUND;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'sounds';
|
||||
protected string $pageName = 'sounds';
|
||||
@@ -34,6 +34,12 @@ class SoundsBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new SoundListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -41,18 +47,13 @@ class SoundsBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
$this->h1 = Util::ucFirst(Lang::game('sounds'));
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
$conditions = [];
|
||||
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
|
||||
/**************/
|
||||
/* Page Title */
|
||||
|
||||
@@ -14,9 +14,9 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
SPELL_AURA_ABILITY_PERIODIC_CRIT, SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL, SPELL_AURA_ABILITY_IGNORE_AURASTATE,
|
||||
SPELL_AURA_ALLOW_ONLY_ABILITY, SPELL_AURA_IGNORE_MELEE_RESET, SPELL_AURA_ABILITY_CONSUME_NO_AMMO,
|
||||
SPELL_AURA_MOD_IGNORE_SHAPESHIFT, SPELL_AURA_PERIODIC_HASTE, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS,
|
||||
SPELL_AURA_MOD_DAMAGE_FROM_CASTER, SPELL_AURA_ADD_TARGET_TRIGGER, /* SPELL_AURA_DUMMY ? */];
|
||||
SPELL_AURA_MOD_DAMAGE_FROM_CASTER, SPELL_AURA_ADD_TARGET_TRIGGER, SPELL_AURA_IGNORE_COMBAT_RESULT, /* SPELL_AURA_DUMMY ? */];
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'spell';
|
||||
protected string $pageName = 'spell';
|
||||
@@ -26,7 +26,6 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
public int $type = Type::SPELL;
|
||||
public int $typeId = 0;
|
||||
public array $reagents = [false, null];
|
||||
public array $scaling = [];
|
||||
public string $items = '';
|
||||
public array $tools = [];
|
||||
public array $effects = [];
|
||||
@@ -161,13 +160,6 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$this->createReagentList();
|
||||
|
||||
|
||||
/**********************/
|
||||
/* Spell Scaling Info */
|
||||
/**********************/
|
||||
|
||||
$this->createScalingData();
|
||||
|
||||
|
||||
/******************/
|
||||
/* Required Items */
|
||||
/******************/
|
||||
@@ -449,7 +441,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
['s.effect1Id', $this->subject->getField('effect1Id')],
|
||||
['s.effect2Id', $this->subject->getField('effect2Id')],
|
||||
['s.effect3Id', $this->subject->getField('effect3Id')],
|
||||
['s.id', $this->subject->id, '!'],
|
||||
['s.id', $this->typeId, '!'],
|
||||
['s.name_loc'.Lang::getLocale()->value, $this->subject->getField('name', true)]
|
||||
);
|
||||
|
||||
@@ -534,7 +526,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
// tab: used by - spell
|
||||
if ($so = DB::Aowow()->selectCell('SELECT `id` FROM ?_spelloverride WHERE `spellId1` = ?d OR `spellId2` = ?d OR `spellId3` = ?d OR `spellId4` = ?d OR `spellId5` = ?d', $this->subject->id, $this->subject->id, $this->subject->id, $this->subject->id, $this->subject->id))
|
||||
if ($so = DB::Aowow()->selectCell('SELECT `id` FROM ?_spelloverride WHERE `spellId1` = ?d OR `spellId2` = ?d OR `spellId3` = ?d OR `spellId4` = ?d OR `spellId5` = ?d', $this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId))
|
||||
{
|
||||
$conditions = array(
|
||||
'OR',
|
||||
@@ -559,8 +551,8 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: used by - itemset
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['spell1', $this->subject->id], ['spell2', $this->subject->id], ['spell3', $this->subject->id], ['spell4', $this->subject->id],
|
||||
['spell5', $this->subject->id], ['spell6', $this->subject->id], ['spell7', $this->subject->id], ['spell8', $this->subject->id]
|
||||
['spell1', $this->typeId], ['spell2', $this->typeId], ['spell3', $this->typeId], ['spell4', $this->typeId],
|
||||
['spell5', $this->typeId], ['spell6', $this->typeId], ['spell7', $this->typeId], ['spell8', $this->typeId]
|
||||
);
|
||||
|
||||
$ubSets = new ItemsetList($conditions);
|
||||
@@ -578,11 +570,11 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: used by - item
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['AND', ['spellTrigger1', SPELL_TRIGGER_LEARN, '!'], ['spellId1', $this->subject->id]],
|
||||
['AND', ['spellTrigger2', SPELL_TRIGGER_LEARN, '!'], ['spellId2', $this->subject->id]],
|
||||
['AND', ['spellTrigger3', SPELL_TRIGGER_LEARN, '!'], ['spellId3', $this->subject->id]],
|
||||
['AND', ['spellTrigger4', SPELL_TRIGGER_LEARN, '!'], ['spellId4', $this->subject->id]],
|
||||
['AND', ['spellTrigger5', SPELL_TRIGGER_LEARN, '!'], ['spellId5', $this->subject->id]]
|
||||
['AND', ['spellTrigger1', SPELL_TRIGGER_LEARN, '!'], ['spellId1', $this->typeId]],
|
||||
['AND', ['spellTrigger2', SPELL_TRIGGER_LEARN, '!'], ['spellId2', $this->typeId]],
|
||||
['AND', ['spellTrigger3', SPELL_TRIGGER_LEARN, '!'], ['spellId3', $this->typeId]],
|
||||
['AND', ['spellTrigger4', SPELL_TRIGGER_LEARN, '!'], ['spellId4', $this->typeId]],
|
||||
['AND', ['spellTrigger5', SPELL_TRIGGER_LEARN, '!'], ['spellId5', $this->typeId]]
|
||||
);
|
||||
|
||||
$ubItems = new ItemList($conditions);
|
||||
@@ -600,8 +592,8 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: used by - object
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['onUseSpell', $this->subject->id], ['onSuccessSpell', $this->subject->id],
|
||||
['auraSpell', $this->subject->id], ['triggeredSpell', $this->subject->id]
|
||||
['onUseSpell', $this->typeId], ['onSuccessSpell', $this->typeId],
|
||||
['auraSpell', $this->typeId], ['triggeredSpell', $this->typeId]
|
||||
);
|
||||
if (!empty($ubSAI[Type::OBJECT]))
|
||||
$conditions[] = ['id', $ubSAI[Type::OBJECT]];
|
||||
@@ -656,54 +648,53 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
// tab: contains
|
||||
// spell_loot_template & skill_extra_item_template
|
||||
$extraItem = DB::World()->selectRow('SELECT * FROM skill_extra_item_template WHERE `spellid` = ?d', $this->subject->id);
|
||||
// spell_loot_template
|
||||
$spellLoot = new Loot();
|
||||
|
||||
if ($spellLoot->getByContainer(LOOT_SPELL, $this->subject->id) || $extraItem)
|
||||
if ($spellLoot->getByContainer(LOOT_SPELL, $this->typeId))
|
||||
{
|
||||
$this->extendGlobalData($spellLoot->jsGlobals);
|
||||
|
||||
$lv = $spellLoot->getResult();
|
||||
$extraCols = $spellLoot->extraCols;
|
||||
$extraCols[] = '$Listview.extraCols.percent';
|
||||
$lvName = '$LANG.tab_contains';
|
||||
|
||||
if ($extraItem && $this->subject->canCreateItem())
|
||||
{
|
||||
$foo = $this->subject->relItems->getListviewData();
|
||||
|
||||
for ($i = 1; $i < 4; $i++)
|
||||
{
|
||||
if (($bar = $this->subject->getField('effect'.$i.'CreateItemId')) && isset($foo[$bar]))
|
||||
{
|
||||
$lvName = '$LANG.tab_bonusloot';
|
||||
$lv[$bar] = $foo[$bar];
|
||||
$lv[$bar]['percent'] = $extraItem['additionalCreateChance'];
|
||||
$lv[$bar]['pctstack'] = $this->buildPctStack($extraItem['additionalCreateChance'] / 100, $extraItem['additionalMaxNum']);
|
||||
if ($max = ($extraItem['additionalMaxNum'] - 1))
|
||||
$lv[$bar]['stack'] = [1, $max];
|
||||
|
||||
if (Conditions::extendListviewRow($lv[$bar], Conditions::SRC_NONE, $this->typeId, [Conditions::SPELL, $extraItem['requiredSpecialization']]))
|
||||
{
|
||||
$this->extendGlobalIds(Type::SPELL, $extraItem['requiredSpecialization']);
|
||||
$extraCols[] = '$Listview.extraCols.condition';
|
||||
}
|
||||
|
||||
break; // skill_extra_item_template can only contain 1 item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $lv,
|
||||
'name' => $lvName,
|
||||
'data' => $spellLoot->getResult(),
|
||||
'name' => '$LANG.tab_contains',
|
||||
'id' => 'contains',
|
||||
'hiddenCols' => ['side', 'slot', 'source', 'reqlevel'],
|
||||
'extraCols' => array_unique($extraCols)
|
||||
), ItemList::$brickFile));
|
||||
}
|
||||
|
||||
// tab: bonus loot
|
||||
if ($extraItemData = DB::World()->select('SELECT `spellId` AS ARRAY_KEY, `additionalCreateChance` AS "0", `additionalMaxNum` AS "1" FROM skill_extra_item_template WHERE `requiredSpecialization` = ?d', $this->typeId))
|
||||
{
|
||||
$extraSpells = new SpellList(array(['id', array_keys($extraItemData)]));
|
||||
if (!$extraSpells->error)
|
||||
{
|
||||
$this->extendGlobalData($extraSpells->getJSGlobals(GLOBALINFO_RELATED));
|
||||
$lvItems = $extraSpells->getListviewData();
|
||||
|
||||
foreach ($lvItems as $iId => $data)
|
||||
{
|
||||
[$chance, $maxItr] = $extraItemData[$iId];
|
||||
|
||||
$lvItems[$iId]['count'] = 1; // expected by js or the pct-col becomes unsortable
|
||||
$lvItems[$iId]['percent'] = $chance;
|
||||
$lvItems[$iId]['pctstack'] = $this->buildPctStack($chance / 100, $maxItr, $data['creates'][1]);
|
||||
$lvItems[$iId]['creates'][2] *= $maxItr;
|
||||
}
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $lvItems,
|
||||
'name' => '$LANG.tab_bonusloot',
|
||||
'id' => 'bonusloot',
|
||||
'hiddenCols' => ['side', 'reqlevel'],
|
||||
'extraCols' => ['$Listview.extraCols.percent']
|
||||
), SpellList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
// tab: exclusive with
|
||||
if ($this->firstRank && DB::World()->selectCell('SELECT 1 FROM spell_group WHERE `spell_id` = ?d', $this->firstRank))
|
||||
{
|
||||
@@ -819,9 +810,9 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: triggered by
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['AND', ['OR', ['effect1Id', SpellList::EFFECTS_TRIGGER], ['effect1AuraId', SpellList::AURAS_TRIGGER]], ['effect1TriggerSpell', $this->subject->id]],
|
||||
['AND', ['OR', ['effect2Id', SpellList::EFFECTS_TRIGGER], ['effect2AuraId', SpellList::AURAS_TRIGGER]], ['effect2TriggerSpell', $this->subject->id]],
|
||||
['AND', ['OR', ['effect3Id', SpellList::EFFECTS_TRIGGER], ['effect3AuraId', SpellList::AURAS_TRIGGER]], ['effect3TriggerSpell', $this->subject->id]],
|
||||
['AND', ['OR', ['effect1Id', SpellList::EFFECTS_TRIGGER], ['effect1AuraId', SpellList::AURAS_TRIGGER]], ['effect1TriggerSpell', $this->typeId]],
|
||||
['AND', ['OR', ['effect2Id', SpellList::EFFECTS_TRIGGER], ['effect2AuraId', SpellList::AURAS_TRIGGER]], ['effect2TriggerSpell', $this->typeId]],
|
||||
['AND', ['OR', ['effect3Id', SpellList::EFFECTS_TRIGGER], ['effect3AuraId', SpellList::AURAS_TRIGGER]], ['effect3TriggerSpell', $this->typeId]],
|
||||
);
|
||||
|
||||
$trigger = new SpellList($conditions);
|
||||
@@ -1057,15 +1048,16 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: taught by spell
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['AND', ['effect1Id', SpellList::EFFECTS_TEACH], ['effect1TriggerSpell', $this->subject->id]],
|
||||
['AND', ['effect2Id', SpellList::EFFECTS_TEACH], ['effect2TriggerSpell', $this->subject->id]],
|
||||
['AND', ['effect3Id', SpellList::EFFECTS_TEACH], ['effect3TriggerSpell', $this->subject->id]],
|
||||
['AND', ['effect1Id', SpellList::EFFECTS_TEACH], ['effect1TriggerSpell', $this->typeId]],
|
||||
['AND', ['effect2Id', SpellList::EFFECTS_TEACH], ['effect2TriggerSpell', $this->typeId]],
|
||||
['AND', ['effect3Id', SpellList::EFFECTS_TEACH], ['effect3TriggerSpell', $this->typeId]],
|
||||
);
|
||||
|
||||
$tbSpell = new SpellList($conditions);
|
||||
$tbsData = [];
|
||||
if (!$tbSpell->error)
|
||||
{
|
||||
$tbsData = $tbSpell->getFoundIDs();
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $tbSpell->getListviewData(),
|
||||
'id' => 'taught-by-spell',
|
||||
@@ -1076,15 +1068,14 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
// tab: taught by quest
|
||||
$conditions = ['OR', ['sourceSpellId', $this->typeId], ['rewardSpell', $this->typeId]];
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['sourceSpellId', $this->typeId],
|
||||
['rewardSpell', $this->typeId],
|
||||
['rewardSpellCast', $this->typeId]
|
||||
);
|
||||
if ($tbsData)
|
||||
{
|
||||
$conditions[] = ['rewardSpell', array_keys($tbsData)];
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = ['rewardSpellCast', array_keys($tbsData)];
|
||||
}
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = ['rewardSpellCast', $this->typeId];
|
||||
array_push($conditions, ['rewardSpell', $tbsData], ['rewardSpellCast', $tbsData]);
|
||||
|
||||
$tbQuest = new QuestList($conditions);
|
||||
if (!$tbQuest->error)
|
||||
@@ -1101,11 +1092,11 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: taught by item (i'd like to precheck $this->subject->sources, but there is no source:item only complicated crap like "drop" and "vendor")
|
||||
$conditions = array(
|
||||
'OR',
|
||||
['AND', ['spellTrigger1', SPELL_TRIGGER_LEARN], ['spellId1', $this->subject->id]],
|
||||
['AND', ['spellTrigger2', SPELL_TRIGGER_LEARN], ['spellId2', $this->subject->id]],
|
||||
['AND', ['spellTrigger3', SPELL_TRIGGER_LEARN], ['spellId3', $this->subject->id]],
|
||||
['AND', ['spellTrigger4', SPELL_TRIGGER_LEARN], ['spellId4', $this->subject->id]],
|
||||
['AND', ['spellTrigger5', SPELL_TRIGGER_LEARN], ['spellId5', $this->subject->id]],
|
||||
['AND', ['spellTrigger1', SPELL_TRIGGER_LEARN], ['spellId1', $this->typeId]],
|
||||
['AND', ['spellTrigger2', SPELL_TRIGGER_LEARN], ['spellId2', $this->typeId]],
|
||||
['AND', ['spellTrigger3', SPELL_TRIGGER_LEARN], ['spellId3', $this->typeId]],
|
||||
['AND', ['spellTrigger4', SPELL_TRIGGER_LEARN], ['spellId4', $this->typeId]],
|
||||
['AND', ['spellTrigger5', SPELL_TRIGGER_LEARN], ['spellId5', $this->typeId]],
|
||||
);
|
||||
|
||||
$tbItem = new ItemList($conditions);
|
||||
@@ -1166,6 +1157,55 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
// tab: unlocks (object or item)
|
||||
$lockIds = DB::Aowow()->selectCol(
|
||||
'SELECT `id` FROM ?_lock WHERE (`type1` = ?d AND `properties1` = ?d) OR
|
||||
(`type2` = ?d AND `properties2` = ?d) OR (`type3` = ?d AND `properties3` = ?d) OR
|
||||
(`type4` = ?d AND `properties4` = ?d) OR (`type5` = ?d AND `properties5` = ?d)',
|
||||
LOCK_TYPE_SPELL, $this->typeId, LOCK_TYPE_SPELL, $this->typeId,
|
||||
LOCK_TYPE_SPELL, $this->typeId, LOCK_TYPE_SPELL, $this->typeId,
|
||||
LOCK_TYPE_SPELL, $this->typeId
|
||||
);
|
||||
|
||||
// we know this spell effect is only in use on index 1
|
||||
if ($this->subject->getField('effect1Id') == SPELL_EFFECT_OPEN_LOCK && ($lockId = $this->subject->getField('effect1MiscValue')))
|
||||
$lockIds += DB::Aowow()->selectCol(
|
||||
'SELECT `id` FROM ?_lock WHERE (`type1` = ?d AND `properties1` = ?d) OR
|
||||
(`type2` = ?d AND `properties2` = ?d) OR (`type3` = ?d AND `properties3` = ?d) OR
|
||||
(`type4` = ?d AND `properties4` = ?d) OR (`type5` = ?d AND `properties5` = ?d)',
|
||||
LOCK_TYPE_SKILL, $lockId, LOCK_TYPE_SKILL, $lockId,
|
||||
LOCK_TYPE_SKILL, $lockId, LOCK_TYPE_SKILL, $lockId,
|
||||
LOCK_TYPE_SKILL, $lockId
|
||||
);
|
||||
|
||||
if ($lockIds)
|
||||
{
|
||||
// objects
|
||||
$lockedObj = new GameObjectList(array(Cfg::get('SQL_LIMIT_NONE'), ['lockId', $lockIds]));
|
||||
if (!$lockedObj->error)
|
||||
{
|
||||
$this->addDataLoader('zones');
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $lockedObj->getListviewData(),
|
||||
'name' => '$LANG.tab_unlocks',
|
||||
'id' => 'unlocks-object',
|
||||
'visibleCols' => $lockedObj->hasSetFields('reqSkill') ? ['skill'] : null
|
||||
), GameObjectList::$brickFile));
|
||||
}
|
||||
|
||||
$lockedItm = new ItemList(array(Cfg::get('SQL_LIMIT_NONE'), ['lockId', $lockIds]));
|
||||
if (!$lockedItm->error)
|
||||
{
|
||||
$this->extendGlobalData($lockedItm->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $lockedItm->getListviewData(),
|
||||
'name' => '$LANG.tab_unlocks',
|
||||
'id' => 'unlocks-item'
|
||||
), ItemList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
// find associated NPC, Item and merge results
|
||||
// taughtbypets (unused..?)
|
||||
// taughtbyquest (usually the spell casted as quest reward teaches something; exclude those seplls from taughtBySpell)
|
||||
@@ -1191,7 +1231,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
/* SpellLoot recursive dropchance builder */
|
||||
/******************************************/
|
||||
|
||||
private function buildPctStack(float $baseChance, int $maxStack) : string
|
||||
private function buildPctStack(float $baseChance, int $maxStack, int $baseCount = 1) : string
|
||||
{
|
||||
// note: pctStack does not contain absolute values but chances relative to the overall drop chance
|
||||
// e.g.: dropChance is 17% then [1 => 50, 2 => 25, 3 => 25] displays > Stack of 1: 8%; Stack of 2: 4%; Stack of 3: 4%
|
||||
@@ -1212,6 +1252,9 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
// cleanup tiny fractions
|
||||
$pctStack = array_filter($pctStack, fn($x) => ($x * $baseChance) >= 0.01);
|
||||
|
||||
if ($baseCount > 1)
|
||||
$pctStack = array_combine(array_map(fn($x) => $x * $baseCount, array_keys($pctStack)), $pctStack);
|
||||
|
||||
return json_encode($pctStack, JSON_NUMERIC_CHECK); // do not replace with Util::toJSON !
|
||||
}
|
||||
|
||||
@@ -1333,10 +1376,9 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
if (!$reagents)
|
||||
return;
|
||||
|
||||
foreach ($this->subject->relItems->iterate() as $iId => $__)
|
||||
foreach ($reagents as [$iId, $num])
|
||||
{
|
||||
if (!in_array($iId, array_keys($reagents)))
|
||||
continue;
|
||||
$relItem = $this->subject->relItems->getEntry($iId);
|
||||
|
||||
$data = array(
|
||||
'path' => Type::ITEM.'-'.$iId, // id of the html-element
|
||||
@@ -1345,11 +1387,12 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
'typeStr' => Type::getFileString(Type::ITEM),
|
||||
'icon' => new IconElement(
|
||||
Type::ITEM,
|
||||
$iId,
|
||||
$this->subject->relItems->getField('name', true),
|
||||
$reagents[$iId][1],
|
||||
quality: $this->subject->relItems->getField('quality'),
|
||||
is_null($relItem) ? 0 : $iId,
|
||||
is_null($relItem) ? 'Item #'.$iId : $this->subject->relItems->getField('name', true),
|
||||
$num,
|
||||
quality: $relItem['quality'] ?? 'q',
|
||||
size: IconElement::SIZE_SMALL,
|
||||
link: !is_null($relItem),
|
||||
align: 'right',
|
||||
element: 'iconlist-icon'
|
||||
)
|
||||
@@ -1372,9 +1415,15 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$this->reagents = [$enhanced, $reagentResult];
|
||||
}
|
||||
|
||||
private function createScalingData() : void // calculation mostly like seen in TC
|
||||
private function calculateEffectScaling() : array // calculation mostly like seen in TC
|
||||
{
|
||||
$scaling = ['directSP' => 0, 'dotSP' => 0, 'directAP' => 0, 'dotAP' => 0];
|
||||
if ($this->subject->getField('attributes3') & SPELL_ATTR3_NO_DONE_BONUS)
|
||||
return [0, 0, 0, 0];
|
||||
|
||||
if (!$this->subject->isScalableDamagingSpell() && !$this->subject->isScalableHealingSpell())
|
||||
return [0, 0, 0, 0];
|
||||
|
||||
$scaling = [0, 0, 0, 0];
|
||||
$pMask = $this->subject->periodicEffectsMask();
|
||||
$allDoTs = true;
|
||||
|
||||
@@ -1385,25 +1434,20 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
if ($pMask & 1 << ($i - 1))
|
||||
{
|
||||
$scaling['dotSP'] = $this->subject->getField('effect'.$i.'BonusMultiplier');
|
||||
$scaling[1] = $this->subject->getField('effect'.$i.'BonusMultiplier');
|
||||
continue;
|
||||
}
|
||||
else
|
||||
$scaling['directSP'] = $this->subject->getField('effect'.$i.'BonusMultiplier');
|
||||
else if ($this->subject->getField('damageClass') == SPELL_DAMAGE_CLASS_MAGIC)
|
||||
$scaling[0] = $this->subject->getField('effect'.$i.'BonusMultiplier');
|
||||
|
||||
$allDoTs = false;
|
||||
}
|
||||
|
||||
if ($s = DB::World()->selectRow('SELECT `direct_bonus` AS "directSP", `dot_bonus` AS "dotSP", `ap_bonus` AS "directAP", `ap_dot_bonus` AS "dotAP" FROM spell_bonus_data WHERE `entry` = ?d', $this->firstRank))
|
||||
if ($s = DB::World()->selectRow('SELECT `direct_bonus` AS "0", `dot_bonus` AS "1", `ap_bonus` AS "2", `ap_dot_bonus` AS "3" FROM spell_bonus_data WHERE `entry` = ?d', $this->firstRank))
|
||||
$scaling = $s;
|
||||
|
||||
if ((!$this->subject->isDamagingSpell() && !$this->subject->isHealingSpell()) ||
|
||||
!in_array($this->subject->getField('typeCat'), [-2, -3, -7, 7]) ||
|
||||
$this->subject->getField('damageClass') == SPELL_DAMAGE_CLASS_NONE)
|
||||
{
|
||||
$this->scaling = array_filter($scaling, fn($x) => $x > 0);
|
||||
return;
|
||||
}
|
||||
if (!in_array($this->subject->getField('typeCat'), [-2, -3, -7, 7]) || $this->subject->getField('damageClass') == SPELL_DAMAGE_CLASS_NONE)
|
||||
return array_map(fn($x) => $x < 0 ? 0 : $x, $scaling);
|
||||
|
||||
foreach ($scaling as $k => $v)
|
||||
{
|
||||
@@ -1412,15 +1456,15 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
continue;
|
||||
|
||||
// no known calculation for physical abilities
|
||||
if ($k == 'directAP' || $k == 'dotAP')
|
||||
if (in_array($k, [2, 3])) // [direct AP, DoT AP]
|
||||
continue;
|
||||
|
||||
// dont use spellPower to scale physical Abilities
|
||||
if ($this->subject->getField('schoolMask') == (1 << SPELL_SCHOOL_NORMAL) && ($k == 'directSP' || $k == 'dotSP'))
|
||||
if ($this->subject->getField('schoolMask') == (1 << SPELL_SCHOOL_NORMAL) && in_array($k, [0, 1]))
|
||||
continue;
|
||||
|
||||
$isDOT = false;
|
||||
if ($k == 'dotSP' || $k == 'dotAP')
|
||||
if (in_array($k, [1, 3])) // [DoT SP, DoT AP]
|
||||
{
|
||||
if ($pMask)
|
||||
$isDOT = true;
|
||||
@@ -1458,7 +1502,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->subject->isHealingSpell())
|
||||
if ($this->subject->isScalableHealingSpell())
|
||||
$castingTime *= 1.88;
|
||||
|
||||
// SPELL_SCHOOL_MASK_NORMAL
|
||||
@@ -1468,7 +1512,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$scaling[$k] = 0; // would be 1 ($dotFactor), but we dont want it to be displayed
|
||||
}
|
||||
|
||||
$this->scaling = array_filter($scaling, fn($x) => $x > 0);
|
||||
return array_map(fn($x) => $x < 0 ? 0 : $x, $scaling);
|
||||
}
|
||||
|
||||
private function createRequiredItems() : void
|
||||
@@ -1530,6 +1574,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$spellIdx = array_unique(array_merge($this->subject->canTriggerSpell(), $this->subject->canTeachSpell()));
|
||||
$itemIdx = $this->subject->canCreateItem();
|
||||
$perfItem = DB::World()->selectRow('SELECT `perfectItemType` AS "itemId", `requiredSpecialization` AS "reqSpellId", `perfectCreateChance` AS "chance" FROM skill_perfect_item_template WHERE `spellId` = ?d', $this->typeId);
|
||||
$scaling = $this->calculateEffectScaling();
|
||||
|
||||
// Iterate through all effects:
|
||||
for ($i = 1; $i < 4; $i++)
|
||||
@@ -1561,7 +1606,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
*/
|
||||
|
||||
$_nameEffect = $_nameAura = $_nameMV = $_nameMVB = $_markup = '';
|
||||
$_icon = $_perfItem = $_footer = [];
|
||||
$_icon = $_perfItem = $_footer = [];
|
||||
|
||||
$_footer['value'] = [0, 0];
|
||||
$valueFmt = '%s';
|
||||
@@ -1578,7 +1623,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
Type::ITEM,
|
||||
$itemId,
|
||||
$itemEntry ? $this->subject->relItems->getField('name', true) : Util::ucFirst(Lang::game('item')).' #'.$itemId,
|
||||
($effBP + 1) . ($effDS > 1 ? '-' . ($effBP + $effDS) : ''),
|
||||
$this->createNumRange($effBP, $effDS),
|
||||
quality: $itemEntry ? $this->subject->relItems->getField('quality') : '',
|
||||
link: !empty($itemEntry)
|
||||
);
|
||||
@@ -1591,7 +1636,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
if (!$cndSpell->error)
|
||||
{
|
||||
$_perfItem = array(
|
||||
'spellId' => $perfItem['reqSpellId'],
|
||||
'spellId' => $cndSpell->id,
|
||||
'spellName' => $cndSpell->getField('name', true),
|
||||
'icon' => $cndSpell->getField('iconString'),
|
||||
'chance' => $perfItem['chance'],
|
||||
@@ -1604,6 +1649,26 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ($extraItem = DB::World()->selectRow('SELECT * FROM skill_extra_item_template WHERE `spellid` = ?d', $this->typeId))
|
||||
{
|
||||
$cndSpell = new SpellList(array(['id', $extraItem['requiredSpecialization']]));
|
||||
if (!$cndSpell->error)
|
||||
{
|
||||
$_perfItem = array(
|
||||
'spellId' => $cndSpell->id,
|
||||
'spellName' => $cndSpell->getField('name', true),
|
||||
'icon' => $cndSpell->getField('iconString'),
|
||||
'chance' => $extraItem['additionalCreateChance'],
|
||||
'item' => new IconElement(
|
||||
Type::ITEM,
|
||||
$this->subject->relItems->id,
|
||||
$this->subject->relItems->getField('name', true),
|
||||
num: '+'.$this->createNumRange($effBP, $effDS, $extraItem['additionalMaxNum']),
|
||||
quality: $this->subject->relItems->getField('quality')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// .. from spell
|
||||
else if (in_array($i, $spellIdx) || $effId == SPELL_EFFECT_UNLEARN_SPECIALIZATION)
|
||||
@@ -1645,7 +1710,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
if (in_array($i, $this->subject->canTriggerSpell()) && $procData['chance'] && $procData['chance'] < 100)
|
||||
{
|
||||
$_footer['proc'] = $procData['chance'] < 0 ? Lang::spell('ppm', [Lang::nf(-$procData['chance'], 1)]) : Lang::spell('procChance') . $procData['chance'] . '%';
|
||||
$_footer['proc'] = $procData['chance'] < 0 ? Lang::spell('ppm', [-$procData['chance']]) : Lang::spell('procChance', [$procData['chance']]);
|
||||
if ($procData['cooldown'])
|
||||
$_footer['procCD'] = Lang::game('cooldown', [Util::formatTime($procData['cooldown'], true)]);
|
||||
}
|
||||
@@ -1892,6 +1957,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$_nameMV = $this->fmtStaffTip($_, 'MiscValue: '.$effMV);
|
||||
break;
|
||||
case SPELL_AURA_MOD_LANGUAGE:
|
||||
case SPELL_AURA_COMPREHEND_LANGUAGE:
|
||||
if ($_ = Lang::game('languages', $effMV))
|
||||
$_nameMV = $this->fmtStaffTip($_, 'MiscValue: '.$effMV);
|
||||
break;
|
||||
@@ -1967,8 +2033,9 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
if ($_ = Lang::getMagicSchools($effMV))
|
||||
$_nameMV = $this->fmtStaffTip($_, 'MiscValue: '.Util::asHex($effMV));
|
||||
break;
|
||||
case SPELL_AURA_MOD_SKILL:
|
||||
case SPELL_AURA_MOD_SKILL_TALENT:
|
||||
case SPELL_AURA_MOD_SKILL: // temp
|
||||
case SPELL_AURA_MOD_SKILL_TALENT: // perm
|
||||
$valueFmt = '%+d';
|
||||
if ($a = SkillList::makeLink($effMV))
|
||||
$_nameMV = $a;
|
||||
else
|
||||
@@ -2137,6 +2204,21 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
if (isset($_footer['value'][2]))
|
||||
$buffer .= $_footer['value'][2];
|
||||
|
||||
if (in_array($effId, SpellList::EFFECTS_SCALING_DAMAGE))
|
||||
{
|
||||
if ($scaling[2])
|
||||
$buffer .= Lang::spell('apMod', [$scaling[2]]);
|
||||
if ($scaling[0])
|
||||
$buffer .= Lang::spell('spMod', [$scaling[0]]);
|
||||
}
|
||||
if (in_array($effAura, SpellList::AURAS_SCALING_DAMAGE))
|
||||
{
|
||||
if ($scaling[3])
|
||||
$buffer .= Lang::spell('apMod', [$scaling[3]]);
|
||||
if ($scaling[1])
|
||||
$buffer .= Lang::spell('spMod', [$scaling[1]]);
|
||||
}
|
||||
|
||||
$_footer['value'] = $buffer;
|
||||
}
|
||||
else
|
||||
@@ -2197,10 +2279,16 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$this->attributes = $list;
|
||||
}
|
||||
|
||||
private function createNumRange(int $bp, int $ds, int $mult = 1) : string
|
||||
{
|
||||
return Util::createNumRange($bp + 1, ($bp + $ds) * $mult, '-');
|
||||
}
|
||||
|
||||
private function generatePath()
|
||||
{
|
||||
$cat = $this->subject->getField('typeCat');
|
||||
$cf = $this->subject->getField('cuFlags');
|
||||
$sl = $this->subject->getField('skillLines');
|
||||
|
||||
$this->breadcrumb[] = $cat;
|
||||
|
||||
@@ -2222,14 +2310,15 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
if ($cat == -13)
|
||||
$this->breadcrumb[] = ($cf & (SPELL_CU_GLYPH_MAJOR | SPELL_CU_GLYPH_MINOR)) >> 6;
|
||||
else
|
||||
$this->breadcrumb[] = $this->subject->getField('skillLines')[0];
|
||||
else if ($sl)
|
||||
$this->breadcrumb[] = $sl[0];
|
||||
|
||||
break;
|
||||
case 9:
|
||||
case -3:
|
||||
case 11:
|
||||
$this->breadcrumb[] = $this->subject->getField('skillLines')[0];
|
||||
if ($sl)
|
||||
$this->breadcrumb[] = $sl[0];
|
||||
|
||||
if ($cat == 11)
|
||||
if ($_ = $this->subject->getField('reqSpellId'))
|
||||
@@ -2238,7 +2327,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
break;
|
||||
case -11:
|
||||
foreach (SpellList::$skillLines as $line => $skills)
|
||||
if (in_array($this->subject->getField('skillLines')[0], $skills))
|
||||
if (in_array($sl[0] ?? [], $skills))
|
||||
$this->breadcrumb[] = $line;
|
||||
break;
|
||||
case -7: // only spells unique in skillLineAbility will always point to the right skillLine :/
|
||||
@@ -2263,8 +2352,9 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
private function createInfobox() : void
|
||||
{
|
||||
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
|
||||
$typeCat = $this->subject->getField('typeCat');
|
||||
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
|
||||
$typeCat = $this->subject->getField('typeCat');
|
||||
$hasCompletion = in_array($typeCat, [-5, -6]) && !($this->subject->getField('cuFlags') & CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
|
||||
// level
|
||||
if (!in_array($typeCat, [-5, -6])) // not mount or vanity pet
|
||||
@@ -2309,11 +2399,11 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
if (in_array($typeCat, [9, 11]))
|
||||
{
|
||||
// skill
|
||||
if ($_ = $this->subject->getField('skillLines')[0])
|
||||
if ($_ = $this->subject->getField('skillLines'))
|
||||
{
|
||||
$this->extendGlobalIds(Type::SKILL, $_);
|
||||
$this->extendGlobalIds(Type::SKILL, $_[0]);
|
||||
|
||||
$bar = Lang::game('requires', [' [skill='.$_.']']);
|
||||
$bar = Lang::game('requires', [' [skill='.$_[0].']']);
|
||||
if ($_ = $this->subject->getField('learnedAt'))
|
||||
$bar .= ' ('.$_.')';
|
||||
|
||||
@@ -2345,13 +2435,30 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
if ($cost = $this->subject->getField('trainingCost'))
|
||||
$infobox[] = Lang::spell('trainingCost').'[money='.$cost.']';
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::spell('id') . $this->typeId;
|
||||
|
||||
// icon
|
||||
if ($_ = $this->subject->getField('iconId'))
|
||||
{
|
||||
$infobox[] = Util::ucFirst(Lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$this->extendGlobalIds(Type::ICON, $_);
|
||||
$infobox[] = Util::ucFirst(lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
}
|
||||
|
||||
// profiler relateed (note that this is part of the cache. I don't think this is important enough to calc for every view)
|
||||
if (Cfg::get('PROFILER_ENABLE') && $hasCompletion)
|
||||
{
|
||||
$x = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_completion_spells WHERE `spellId` = ?d', $this->typeId);
|
||||
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `custom` = 0 AND `stub` = 0');
|
||||
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
|
||||
|
||||
// completion row added by InfoboxMarkup
|
||||
}
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
// used in mode
|
||||
foreach ($this->difficulties as $n => $id)
|
||||
if ($id == $this->typeId)
|
||||
@@ -2375,7 +2482,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$infobox[] = 'Script'.Lang::main('colon').$_;
|
||||
|
||||
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', $hasCompletion);
|
||||
|
||||
// append glyph symbol if available
|
||||
$glyphId = 0;
|
||||
|
||||
@@ -26,7 +26,7 @@ class SpellsBaseResponse extends TemplateResponse implements ICache
|
||||
);
|
||||
|
||||
protected int $type = Type::SPELL;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'spells';
|
||||
protected string $pageName = 'spells';
|
||||
@@ -99,6 +99,12 @@ class SpellsBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
$this->filter = new SpellListFilter($this->_get['filter'] ?? '', ['parentCats' => $this->category]);
|
||||
if ($this->filter->shouldReload)
|
||||
{
|
||||
$_SESSION['error']['fi'] = $this->filter::class;
|
||||
$get = $this->filter->buildGETParam();
|
||||
$this->forward('?' . $this->pageName . $this->subCat . ($get ? '&filter=' . $get : ''));
|
||||
}
|
||||
$this->filterError = $this->filter->error;
|
||||
}
|
||||
|
||||
@@ -110,13 +116,9 @@ class SpellsBaseResponse extends TemplateResponse implements ICache
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
$this->filter->evalCriteria();
|
||||
|
||||
if ($_ = $this->filter->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$this->filterError = $this->filter->error; // maybe the evalX() caused something
|
||||
|
||||
|
||||
/*************/
|
||||
/* Menu Path */
|
||||
|
||||
@@ -10,7 +10,7 @@ class TitleBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected array $breadcrumb = [0, 10];
|
||||
@@ -84,8 +84,25 @@ class TitleBaseResponse extends TemplateResponse implements ICache
|
||||
$infobox[] = Lang::game('eventShort', ['[event='.$eId.']']);
|
||||
}
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::title('id') . $this->typeId;
|
||||
|
||||
// profiler relateed (note that this is part of the cache. I don't think this is important enough to calc for every view)
|
||||
if (Cfg::get('PROFILER_ENABLE'))
|
||||
{
|
||||
$x = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_completion_titles WHERE `titleId` = ?d', $this->typeId);
|
||||
$y = DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_profiler_profiles WHERE `custom` = 0 AND `stub` = 0');
|
||||
$infobox[] = Lang::profiler('attainedBy', [round(($x ?: 0) * 100 / ($y ?: 1))]);
|
||||
|
||||
// completion row added by InfoboxMarkup
|
||||
}
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0', 1);
|
||||
|
||||
|
||||
/****************/
|
||||
|
||||
@@ -11,7 +11,7 @@ class TitlesBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::TITLE;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'titles';
|
||||
|
||||
@@ -42,6 +42,10 @@ class UserBaseResponse extends TemplateResponse
|
||||
$this->user = $user;
|
||||
else
|
||||
$this->generateNotFound(Lang::user('notFound', [$pageParam]));
|
||||
|
||||
// do not display system account
|
||||
if (!$this->user['id'])
|
||||
$this->generateNotFound(Lang::user('notFound', [$pageParam]));
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
@@ -229,30 +233,33 @@ class UserBaseResponse extends TemplateResponse
|
||||
|
||||
if (Cfg::get('PROFILER_ENABLE'))
|
||||
{
|
||||
$conditions = array(
|
||||
['OR', ['cuFlags', PROFILER_CU_PUBLISHED, '&'], ['ap.extraFlags', PROFILER_CU_PUBLISHED, '&']],
|
||||
[['cuFlags', PROFILER_CU_DELETED, '&'], 0],
|
||||
['OR', ['user', $this->user['id']], ['ap.accountId', $this->user['id']]]
|
||||
);
|
||||
|
||||
if (User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$conditions = array_slice($conditions, 2);
|
||||
else if (User::$id == $this->user['id'])
|
||||
array_shift($conditions);
|
||||
$conditions = [['user', $this->user['id']]];
|
||||
if (User::$id != $this->user['id'] && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$conditions[] = ['cuFlags', PROFILER_CU_PUBLISHED, '&'];
|
||||
if (!User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$conditions[] = ['deleted', 0];
|
||||
|
||||
$profiles = new LocalProfileList($conditions);
|
||||
if (!$profiles->error)
|
||||
{
|
||||
$this->addDataLoader('weight-presets');
|
||||
|
||||
// Characters
|
||||
if ($chars = $profiles->getListviewData(PROFILEINFO_CHARACTER | PROFILEINFO_USER))
|
||||
$this->charactersLvData = array_values($chars);
|
||||
|
||||
// Profiles
|
||||
if ($prof = $profiles->getListviewData(PROFILEINFO_PROFILE | PROFILEINFO_USER))
|
||||
$this->profilesLvData = array_values($prof);
|
||||
}
|
||||
|
||||
$conditions = [['ap.accountId', $this->user['id']]];
|
||||
if (User::$id != $this->user['id'] && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
$conditions[] = ['ap.extraFlags', PROFILER_CU_PUBLISHED, '&'];
|
||||
|
||||
$characters = new LocalProfileList($conditions);
|
||||
if (!$characters->error)
|
||||
{
|
||||
$this->addDataLoader('weight-presets');
|
||||
|
||||
if ($chars = $characters->getListviewData(PROFILEINFO_CHARACTER | PROFILEINFO_USER))
|
||||
$this->charactersLvData = array_values($chars);
|
||||
}
|
||||
}
|
||||
|
||||
// My Guides
|
||||
|
||||
@@ -10,7 +10,7 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
|
||||
{
|
||||
use TrDetailPage, TrCache;
|
||||
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_DETAIL_PAGE;
|
||||
|
||||
protected string $template = 'detail-page-generic';
|
||||
protected string $pageName = 'zone';
|
||||
@@ -188,6 +188,13 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
// id
|
||||
$infobox[] = Lang::zone('id') . $this->typeId;
|
||||
|
||||
// original name
|
||||
if (Lang::getLocale() != Locale::EN)
|
||||
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
|
||||
|
||||
if ($botRows = array_filter($quickFactsRows, fn($x) => $x > 0, ARRAY_FILTER_USE_KEY))
|
||||
$infobox = array_merge($infobox, $botRows);
|
||||
|
||||
@@ -561,10 +568,10 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: NPCs
|
||||
if ($cSpawns && !$creatureSpawns->error)
|
||||
{
|
||||
$tabData = array(
|
||||
'data' => $creatureSpawns->getListviewData(),
|
||||
'note' => sprintf(Util::$filterResultString, '?npcs&filter=cr=6;crs='.$this->typeId.';crv=0')
|
||||
);
|
||||
$tabData = ['data' => $creatureSpawns->getListviewData()];
|
||||
|
||||
if (!is_null(CreatureListFilter::getCriteriaIndex(6, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?npcs&filter=cr=6;crs='.$this->typeId.';crv=0');
|
||||
|
||||
if ($creatureSpawns->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
$tabData['_truncated'] = 1;
|
||||
@@ -577,10 +584,10 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: Objects
|
||||
if ($oSpawns && !$objectSpawns->error)
|
||||
{
|
||||
$tabData = array(
|
||||
'data' => $objectSpawns->getListviewData(),
|
||||
'note' => sprintf(Util::$filterResultString, '?objects&filter=cr=1;crs='.$this->typeId.';crv=0')
|
||||
);
|
||||
$tabData = ['data' => $objectSpawns->getListviewData()];
|
||||
|
||||
if (!is_null(GameObjectListFilter::getCriteriaIndex(1, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?objects&filter=cr=1;crs='.$this->typeId.';crv=0');
|
||||
|
||||
if ($objectSpawns->getMatches() > Cfg::get('SQL_LIMIT_DEFAULT'))
|
||||
$tabData['_truncated'] = 1;
|
||||
@@ -616,7 +623,10 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
|
||||
if (!in_array($this->typeId, $children))
|
||||
continue;
|
||||
|
||||
$tabData['note'] = '$$WH.sprintf(LANG.lvnote_zonequests, '.$parent.', '.$this->typeId.',"'.$this->subject->getField('name', true).'", '.$this->typeId.')';
|
||||
if (!is_null(ItemListFilter::getCriteriaIndex(126, $this->typeId)))
|
||||
$tabData['note'] = '$$WH.sprintf(LANG.lvnote_zonequests, '.$parent.', '.$this->typeId.',"'.$this->subject->getField('name', true).'", '.$this->typeId.')';
|
||||
else
|
||||
$tabData['note'] = '$$WH.sprintf(LANG.lvnote_questsind, '.$parent.', '.$this->typeId.',"'.$this->subject->getField('name', true).'")';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -655,11 +665,15 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
|
||||
$rewards = new ItemList(array(['id', array_unique($rewardsLV)]));
|
||||
if (!$rewards->error)
|
||||
{
|
||||
$note = null;
|
||||
if (!is_null(ItemListFilter::getCriteriaIndex(126, $this->typeId)))
|
||||
$note = sprintf(Util::$filterResultString, '?items&filter=cr=126;crs='.$this->typeId.';crv=0');
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $rewards->getListviewData(),
|
||||
'name' => '$LANG.tab_questrewards',
|
||||
'id' => 'quest-rewards',
|
||||
'note' => sprintf(Util::$filterResultString, '?items&filter=cr=126;crs='.$this->typeId.';crv=0')
|
||||
'note' => $note
|
||||
), ItemList::$brickFile));
|
||||
|
||||
$this->extendGlobalData($rewards->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
@@ -11,7 +11,7 @@ class ZonesBaseResponse extends TemplateResponse implements ICache
|
||||
use TrListPage, TrCache;
|
||||
|
||||
protected int $type = Type::ZONE;
|
||||
protected int $cacheType = CACHE_TYPE_PAGE;
|
||||
protected int $cacheType = CACHE_TYPE_LIST_PAGE;
|
||||
|
||||
protected string $template = 'list-page-generic';
|
||||
protected string $pageName = 'zones';
|
||||
|
||||
@@ -21,14 +21,10 @@ trait SmartHelper
|
||||
|
||||
private function numRange(int $min, int $max, bool $isTime) : string
|
||||
{
|
||||
if (!$min && !$max)
|
||||
return '';
|
||||
if ($isTime)
|
||||
return Util::createNumRange($min, $max, ' – ', fn($x) => Util::formatTime($x, true));
|
||||
|
||||
$str = $isTime ? Util::formatTime($min, true) : $min;
|
||||
if ($max > $min)
|
||||
$str .= ' – '.($isTime ? Util::formatTime($max, true) : $max);
|
||||
|
||||
return $str;
|
||||
return Util::createNumRange($min, $max, ' – ');
|
||||
}
|
||||
|
||||
private function formatTime(int $time, int $_, bool $isMilliSec) : string
|
||||
@@ -41,6 +37,12 @@ trait SmartHelper
|
||||
|
||||
private function castFlags(int $flags) : string
|
||||
{
|
||||
if ($x = ($flags & ~SmartAI::CAST_FLAG_VALIDATE))
|
||||
{
|
||||
trigger_error('SmartAI::castFlags - unknown SmartCastFlags '.Util::asBin($x).' set on id #'.$this->id, E_USER_NOTICE);
|
||||
$flags &= SmartAI::CAST_FLAG_VALIDATE;
|
||||
}
|
||||
|
||||
$cf = [];
|
||||
for ($i = 1; $i <= SmartAI::CAST_FLAG_COMBAT_MOVE; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::smartAI('castFlags', $i)))
|
||||
@@ -51,6 +53,12 @@ trait SmartHelper
|
||||
|
||||
private function npcFlags(int $flags) : string
|
||||
{
|
||||
if ($x = ($flags & ~NPC_FLAG_VALIDATE))
|
||||
{
|
||||
trigger_error('SmartAI::npcFlags - unknown NpcFlags '.Util::asBin($x).' set on id #'.$this->id, E_USER_NOTICE);
|
||||
$flags &= NPC_FLAG_VALIDATE;
|
||||
}
|
||||
|
||||
$nf = [];
|
||||
for ($i = 1; $i <= NPC_FLAG_MAILBOX; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::npc('npcFlags', $i)))
|
||||
@@ -61,6 +69,12 @@ trait SmartHelper
|
||||
|
||||
private function dynFlags(int $flags) : string
|
||||
{
|
||||
if ($x = ($flags & ~UNIT_DYNFLAG_VALIDATE))
|
||||
{
|
||||
trigger_error('SmartAI::dynFlags - unknown unit dynFlags '.Util::asBin($x).' set on id #'.$this->id, E_USER_NOTICE);
|
||||
$flags &= UNIT_DYNFLAG_VALIDATE;
|
||||
}
|
||||
|
||||
$df = [];
|
||||
for ($i = 1; $i <= UNIT_DYNFLAG_TAPPED_BY_ALL_THREAT_LIST; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::unit('dynFlags', $i)))
|
||||
@@ -71,6 +85,12 @@ trait SmartHelper
|
||||
|
||||
private function goFlags(int $flags) : string
|
||||
{
|
||||
if ($x = ($flags & ~GO_FLAG_VALIDATE))
|
||||
{
|
||||
trigger_error('SmartAI::goFlags - unknown GameobjectFlags '.Util::asBin($x).' set on id #'.$this->id, E_USER_NOTICE);
|
||||
$flags &= GO_FLAG_VALIDATE;
|
||||
}
|
||||
|
||||
$gf = [];
|
||||
for ($i = 1; $i <= GO_FLAG_DESTROYED; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::gameObject('goFlags', $i)))
|
||||
@@ -81,6 +101,12 @@ trait SmartHelper
|
||||
|
||||
private function spawnFlags(int $flags) : string
|
||||
{
|
||||
if ($x = ($flags & ~SmartAI::SPAWN_FLAG_VALIDATE))
|
||||
{
|
||||
trigger_error('SmartAI::spawnFlags - unknown SmartSpawnFlags '.Util::asBin($x).' set on id #'.$this->id, E_USER_NOTICE);
|
||||
$flags &= SmartAI::SPAWN_FLAG_VALIDATE;
|
||||
}
|
||||
|
||||
$sf = [];
|
||||
for ($i = 1; $i <= SmartAI::SPAWN_FLAG_NOSAVE_RESPAWN; $i <<= 1)
|
||||
if (($flags & $i) && ($x = Lang::smartAI('spawnFlags', $i)))
|
||||
@@ -91,6 +117,18 @@ trait SmartHelper
|
||||
|
||||
private function unitFlags(int $flags, int $flags2) : string
|
||||
{
|
||||
if ($x = ($flags & ~UNIT_FLAG_VALIDATE))
|
||||
{
|
||||
trigger_error('SmartAI::unitFlags - unknown UnitFlags '.Util::asBin($x).' set on id #'.$this->id, E_USER_NOTICE);
|
||||
$flags &= UNIT_FLAG_VALIDATE;
|
||||
}
|
||||
|
||||
if ($x = ($flags2 & ~UNIT_FLAG2_VALIDATE))
|
||||
{
|
||||
trigger_error('SmartAI::unitFlags - unknown UnitFlags2 '.Util::asBin($x).' set on id #'.$this->id, E_USER_NOTICE);
|
||||
$flags2 &= UNIT_FLAG2_VALIDATE;
|
||||
}
|
||||
|
||||
$field = $flags2 ? 'flags2' : 'flags';
|
||||
$max = $flags2 ? UNIT_FLAG2_ALLOW_CHEAT_SPELLS : UNIT_FLAG_UNK_31;
|
||||
$uf = [];
|
||||
@@ -185,6 +223,7 @@ class SmartAI
|
||||
// public const CAST_FORCE_TARGET_SELF = 0x10; // the target to cast this spell on itself
|
||||
public const CAST_FLAG_AURA_MISSING = 0x20; // Only casts the spell if the target does not have an aura from the spell
|
||||
public const CAST_FLAG_COMBAT_MOVE = 0x40; // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
public const CAST_FLAG_VALIDATE = self::CAST_FLAG_INTERRUPT_PREV | self::CAST_FLAG_TRIGGERED | self::CAST_FLAG_AURA_MISSING | self::CAST_FLAG_COMBAT_MOVE;
|
||||
|
||||
public const REACT_PASSIVE = 0;
|
||||
public const REACT_DEFENSIVE = 1;
|
||||
@@ -211,6 +250,7 @@ class SmartAI
|
||||
public const SPAWN_FLAG_IGNORE_RESPAWN = 0x01; // onSpawnIn - ignore & reset respawn timer
|
||||
public const SPAWN_FLAG_FORCE_SPAWN = 0x02; // onSpawnIn - force additional spawn if already in world
|
||||
public const SPAWN_FLAG_NOSAVE_RESPAWN = 0x04; // onDespawn - remove respawn time
|
||||
public const SPAWN_FLAG_VALIDATE = self::SPAWN_FLAG_IGNORE_RESPAWN | self::SPAWN_FLAG_FORCE_SPAWN | self::SPAWN_FLAG_NOSAVE_RESPAWN;
|
||||
|
||||
private array $jsGlobals = [];
|
||||
private array $rawData = [];
|
||||
|
||||
@@ -467,8 +467,8 @@ class SmartAction
|
||||
WHERE tp.`id` = ?d',
|
||||
Lang::getLocale()->value, Lang::getLocale()->value, Lang::getLocale()->value, Lang::getLocale()->value, $this->param[0]
|
||||
);
|
||||
$this->param[10] = Util::jsEscape(Util::localizedString($nodes, 'start'));
|
||||
$this->param[11] = Util::jsEscape(Util::localizedString($nodes, 'end'));
|
||||
$this->param[10] = Util::localizedString($nodes, 'start');
|
||||
$this->param[11] = Util::localizedString($nodes, 'end');
|
||||
break;
|
||||
case self::ACTION_SET_INGAME_PHASE_MASK: // 44 -> any target
|
||||
if ($this->param[0])
|
||||
|
||||
@@ -98,6 +98,10 @@ class SmartEvent
|
||||
public const EVENT_ON_SPELL_FAILED = 84; // On Unit::InterruptSpell
|
||||
public const EVENT_ON_SPELL_START = 85; // On Spell::prapare
|
||||
public const EVENT_ON_DESPAWN = 86; // On before creature removed
|
||||
public const EVENT_SEND_EVENT_TRIGGER = 87; // [RESERVED] UNUSED NEEDS CHERRYPICK
|
||||
public const EVENT_AREATRIGGER_EXIT = 88; // [RESERVED] don't use on 3.3.5a
|
||||
public const EVENT_ON_AURA_APPLIED = 89; //
|
||||
public const EVENT_ON_AURA_REMOVED = 90; //
|
||||
|
||||
public const FLAG_NO_REPEAT = 0x0001;
|
||||
public const FLAG_DIFFICULTY_0 = 0x0002;
|
||||
@@ -108,6 +112,7 @@ class SmartEvent
|
||||
public const FLAG_NO_RESET = 0x0100;
|
||||
public const FLAG_WHILE_CHARMED = 0x0200;
|
||||
public const FLAG_ALL_DIFFICULTIES = self::FLAG_DIFFICULTY_0 | self::FLAG_DIFFICULTY_1 | self::FLAG_DIFFICULTY_2 | self::FLAG_DIFFICULTY_3;
|
||||
public const FLAG_VALIDATE = self::FLAG_NO_REPEAT | self::FLAG_DEBUG_ONLY | self::FLAG_NO_RESET | self::FLAG_WHILE_CHARMED | self::FLAG_ALL_DIFFICULTIES;
|
||||
|
||||
private const EVENT_CELL_TPL = '[tooltip name=e-#rowIdx#]%1$s[/tooltip][span tooltip=e-#rowIdx#]%2$s[/span]';
|
||||
|
||||
@@ -198,7 +203,11 @@ class SmartEvent
|
||||
self::EVENT_ON_SPELL_CAST => [Type::SPELL, ['numRange', -1, true], null, null, null, 0], // SpellID, CooldownMin, CooldownMax
|
||||
self::EVENT_ON_SPELL_FAILED => [Type::SPELL, ['numRange', -1, true], null, null, null, 0], // SpellID, CooldownMin, CooldownMax
|
||||
self::EVENT_ON_SPELL_START => [Type::SPELL, ['numRange', -1, true], null, null, null, 0], // SpellID, CooldownMin, CooldownMax
|
||||
self::EVENT_ON_DESPAWN => [null, null, null, null, null, 0] // NONE
|
||||
self::EVENT_ON_DESPAWN => [null, null, null, null, null, 0], // NONE
|
||||
self::EVENT_SEND_EVENT_TRIGGER => [null, null, null, null, null, 2], // UNUSED NEEDS CHERRYPICK
|
||||
self::EVENT_AREATRIGGER_EXIT => [null, null, null, null, null, 2], // don't use on 3.3.5a
|
||||
self::EVENT_ON_AURA_APPLIED => [Type::SPELL, ['numRange', -1, true], null, null, null, 0], // SpellID, CooldownMin, CooldownMax
|
||||
self::EVENT_ON_AURA_REMOVED => [Type::SPELL, ['numRange', -1, true], null, null, null, 0] // SpellID, CooldownMin, CooldownMax
|
||||
);
|
||||
|
||||
private array $jsGlobals = [];
|
||||
@@ -296,7 +305,7 @@ class SmartEvent
|
||||
);
|
||||
|
||||
if ($gmo)
|
||||
$this->param[10] = Util::jsEscape(Util::localizedString($gmo, 'text'));
|
||||
$this->param[10] = Util::localizedString($gmo, 'text');
|
||||
else
|
||||
trigger_error('SmartAI::event - could not find gossip menu option for event #'.$this->type);
|
||||
break;
|
||||
@@ -366,6 +375,12 @@ class SmartEvent
|
||||
{
|
||||
$flags = $this->flags;
|
||||
|
||||
if ($x = ($flags & ~self::FLAG_VALIDATE))
|
||||
{
|
||||
trigger_error('SmartEvent::formatFlags - unused SmartEventFlags '.Util::asBin($x).' set on id #'.$this->id, E_USER_NOTICE);
|
||||
$flags &= self::FLAG_VALIDATE;
|
||||
}
|
||||
|
||||
if (($flags & self::FLAG_ALL_DIFFICULTIES) == self::FLAG_ALL_DIFFICULTIES)
|
||||
$flags &= ~self::FLAG_ALL_DIFFICULTIES;
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ abstract class Filter
|
||||
protected const PATTERN_NAME = '/[\p{C};%\\\\]/ui';
|
||||
protected const PATTERN_CRV = '/[\p{C};:%\\\\]/ui';
|
||||
protected const PATTERN_INT = '/\D/';
|
||||
public const PATTERN_PARAM = '/^[\p{L}\p{Sm} \d\p{P}]+$/i';
|
||||
public const PATTERN_PARAM = '/^[\p{L}\p{Sm} \d\p{P}]+$/ui';
|
||||
|
||||
protected const ENUM_FACTION = array( 469, 1037, 1106, 529, 1012, 87, 21, 910, 609, 942, 909, 530, 69, 577, 930, 1068, 1104, 729, 369, 92,
|
||||
54, 946, 67, 1052, 749, 47, 989, 1090, 1098, 978, 1011, 93, 1015, 1038, 76, 470, 349, 1031, 1077, 809,
|
||||
@@ -82,7 +82,7 @@ abstract class Filter
|
||||
3520, 3703, 3711, 1377, 3487, 130, 3679, 406, 1519, 4384, 33, 2017, 1477, 4075, 8, 440, 141, 3428, 3519, 3848,
|
||||
17, 2366, 3840, 3713, 3847, 3775, 4100, 1581, 3557, 3845, 4500, 4809, 47, 3849, 4265, 4493, 4228, 3698, 4406, 3714,
|
||||
3717, 3715, 717, 67, 3716, 457, 4415, 400, 1638, 1216, 85, 4723, 4722, 1337, 4273, 490, 1497, 206, 1196, 4603,
|
||||
718, 3277, 28, 40, 11, 4197, 618, 3521, 3805, 66, 1176, 1977);
|
||||
718, 3277, 28, 40, 11, 4197, 618, 3521, 3805, 66, 1176, 1977, 4987);
|
||||
protected const ENUM_HEROICDUNGEON = array( 4494, 3790, 4277, 4196, 4416, 4272, 4820, 4264, 3562, 4131, 3792, 2367, 4813, 3791, 3789, 3848, 2366, 3713, 3847, 4100,
|
||||
4809, 3849, 4265, 4228, 3714, 3717, 3715, 3716, 4415, 4723, 206, 1196);
|
||||
protected const ENUM_MULTIMODERAID = array( 4812, 3456, 2159, 4500, 4493, 4722, 4273, 4603, 4987);
|
||||
@@ -91,12 +91,13 @@ abstract class Filter
|
||||
protected const ENUM_RACE = array( null, 1, 2, 3, 4, 5, 6, 7, 8, null, 10, 11, true, false);
|
||||
protected const ENUM_PROFESSION = array( null, 171, 164, 185, 333, 202, 129, 755, 165, 186, 197, true, false, 356, 182, 773);
|
||||
|
||||
public bool $error = false; // erroneous search fields
|
||||
public bool $error = false;
|
||||
public bool $shouldReload = false; // erroneous params have been corrected. Build GET string and reload
|
||||
|
||||
// item related
|
||||
public array $upgrades = []; // [itemId => slotId]
|
||||
public array $extraOpts = []; // score for statWeights
|
||||
public array $wtCnd = []; // DBType condition for statWeights
|
||||
public array $upgrades = []; // [itemId => slotId]
|
||||
public array $extraOpts = []; // score for statWeights
|
||||
public array $wtCnd = []; // DBType condition for statWeights
|
||||
|
||||
private array $cndSet = []; // db type query storage
|
||||
private array $rawData = [];
|
||||
@@ -106,7 +107,7 @@ abstract class Filter
|
||||
[self::CR_FLAG, <string:colName>, <int:testBit>, <bool:matchAny>] # default param2: matchExact
|
||||
[self::CR_NUMERIC, <string:colName>, <int:NUM_FLAGS>, <bool:addExtraCol>]
|
||||
[self::CR_STRING, <string:colName>, <int:STR_FLAGS>, null]
|
||||
[self::CR_ENUM, <string:colName>, <bool:ANYNONE>, <bool:isEnumVal>] # param3 ? crv is val in enum : key in enum
|
||||
[self::CR_ENUM, <string:colName>, <bool:ANY_NONE>, <bool:isEnumVal>] # param3 ? crv is val in enum : key in enum
|
||||
[self::CR_STAFFFLAG, <string:colName>, null, null]
|
||||
[self::CR_CALLBACK, <string:fnName>, <mixed:param1>, <mixed:param2>]
|
||||
[self::CR_NYI_PH, null, <int:returnVal>, param2] # mostly 1: to ignore this criterium; 0: to fail the whole query
|
||||
@@ -126,8 +127,7 @@ abstract class Filter
|
||||
public array $fiReputationCols = []; // fn params ([[factionId, factionName], ...])
|
||||
public array $fiExtraCols = []; //
|
||||
public string $query = ''; // as in url query params
|
||||
public array $values = []; // old fiData['v']
|
||||
public array $criteria = []; // old fiData['c']
|
||||
public array $values = []; // prefiltered rawData
|
||||
|
||||
// parse the provided request into a usable format
|
||||
public function __construct(string|array $data, array $opts = [])
|
||||
@@ -157,6 +157,8 @@ abstract class Filter
|
||||
}
|
||||
|
||||
$this->initFields();
|
||||
$this->evalCriteria();
|
||||
$this->evalWeights();
|
||||
}
|
||||
|
||||
public function mergeCat(array &$cats) : void
|
||||
@@ -167,13 +169,13 @@ abstract class Filter
|
||||
|
||||
private function &criteriaIterator() : \Generator
|
||||
{
|
||||
if (!$this->criteria)
|
||||
if (empty($this->values['cr']))
|
||||
return;
|
||||
|
||||
for ($i = 0; $i < count($this->criteria['cr']); $i++)
|
||||
for ($i = 0; $i < count($this->values['cr']); $i++)
|
||||
{
|
||||
// throws a notice if yielded directly "Only variable references should be yielded by reference"
|
||||
$v = [&$this->criteria['cr'][$i], &$this->criteria['crs'][$i], &$this->criteria['crv'][$i]];
|
||||
$v = [&$this->values['cr'][$i], &$this->values['crs'][$i], &$this->values['crv'][$i]];
|
||||
yield $i => $v;
|
||||
}
|
||||
}
|
||||
@@ -195,7 +197,7 @@ abstract class Filter
|
||||
public function buildGETParam(array $override = [], array $addCr = []) : string
|
||||
{
|
||||
$get = [];
|
||||
foreach (array_merge($this->criteria, $this->values, $override) as $k => $v)
|
||||
foreach (array_merge($this->values, $override) as $k => $v)
|
||||
{
|
||||
if (isset($addCr[$k]))
|
||||
{
|
||||
@@ -228,7 +230,7 @@ abstract class Filter
|
||||
$this->cndSet = $this->createSQLForValues();
|
||||
|
||||
// criteria
|
||||
foreach ($this->criteriaIterator() as &$_cr)
|
||||
foreach ($this->criteriaIterator() as $_cr)
|
||||
if ($cnd = $this->createSQLForCriterium(...$_cr))
|
||||
$this->cndSet[] = $cnd;
|
||||
|
||||
@@ -241,10 +243,10 @@ abstract class Filter
|
||||
|
||||
public function getSetCriteria(int ...$cr) : array
|
||||
{
|
||||
if (!$cr || !$this->fiSetCriteria)
|
||||
return $this->fiSetCriteria;
|
||||
if (!$cr || empty($this->values['cr']))
|
||||
return [];
|
||||
|
||||
return array_values(array_intersect($this->fiSetCriteria['cr'], $cr));
|
||||
return array_values(array_intersect($this->values['cr'], $cr));
|
||||
}
|
||||
|
||||
|
||||
@@ -258,12 +260,17 @@ abstract class Filter
|
||||
return [];
|
||||
|
||||
$data = [];
|
||||
|
||||
// someone copy/pasted a WH filter
|
||||
$get = preg_replace('/^(\d+(:\d+)*);(\d+(:\d+)*);(\P{C}+(:\P{C}+)*)$/', 'cr=$1;crs=$3;crv=$5', $get);
|
||||
|
||||
foreach (explode(';', $get) as $field)
|
||||
{
|
||||
if (!strstr($field, '='))
|
||||
{
|
||||
trigger_error('Filter::transformGET - malformed GET string', E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
$this->error =
|
||||
$this->shouldReload = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -272,7 +279,8 @@ abstract class Filter
|
||||
if (!isset(static::$inputFields[$k]))
|
||||
{
|
||||
trigger_error('Filter::transformGET - GET param not in filter: '.$k, E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
$this->error =
|
||||
$this->shouldReload = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -286,13 +294,24 @@ abstract class Filter
|
||||
|
||||
private function initFields() : void
|
||||
{
|
||||
/* quirks:
|
||||
* - in the POST step there may be excess criteria selectors with a value of '', as unselecting a criteria that is not the last will not remove the row from the UI
|
||||
* - if there are no criteria selected, the placeholder selection will always be sent as ['', null, null], similar to the previous quirk
|
||||
*
|
||||
* same for stat weights on ItemListFilter
|
||||
*/
|
||||
if (!empty($this->rawData['cr']))
|
||||
$this->rawData['cr'] = array_filter($this->rawData['cr'], fn($x) => $x !== '') ?: null;
|
||||
|
||||
if (!empty($this->rawData['wt']))
|
||||
$this->rawData['wt'] = array_filter($this->rawData['wt'], fn($x) => $x !== '') ?: null;
|
||||
|
||||
$cleanupCr = [];
|
||||
foreach (static::$inputFields as $inp => [$type, $valid, $asArray])
|
||||
{
|
||||
$var = in_array($inp, ['cr', 'crs', 'crv']) ? 'criteria' : 'values';
|
||||
|
||||
if (!isset($this->rawData[$inp]) || $this->rawData[$inp] === '')
|
||||
{
|
||||
$this->$var[$inp] = $asArray ? [] : null;
|
||||
$this->values[$inp] = $asArray ? [] : null;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -300,42 +319,62 @@ abstract class Filter
|
||||
|
||||
if ($asArray)
|
||||
{
|
||||
// quirk: in the POST step criteria can be [[''], null, null] if not selected.
|
||||
$buff = [];
|
||||
foreach ((array)$val as $v) // can be string|int in POST step if only one value present
|
||||
if ($v !== '' && $this->checkInput($type, $valid, $v))
|
||||
foreach ((array)$val as $i => $v) // can be string|int in POST step if only one value present
|
||||
{
|
||||
if (in_array($inp, ['cr', 'crs', 'crv']))
|
||||
{
|
||||
if (!$this->checkInput($type, $valid, $v))
|
||||
$cleanupCr[] = $i;
|
||||
$buff[] = $v; // always assign, gets removed later as tuple
|
||||
}
|
||||
else if ($this->checkInput($type, $valid, $v))
|
||||
$buff[] = $v;
|
||||
}
|
||||
|
||||
$this->$var[$inp] = $buff;
|
||||
$this->values[$inp] = $buff;
|
||||
}
|
||||
else
|
||||
$this->$var[$inp] = $this->checkInput($type, $valid, $val) ? $val : null;
|
||||
$this->values[$inp] = $this->checkInput($type, $valid, $val) ? $val : null;
|
||||
}
|
||||
|
||||
if ($cleanupCr)
|
||||
{
|
||||
$this->error =
|
||||
$this->shouldReload = true;
|
||||
|
||||
foreach (array_unique($cleanupCr) as $i)
|
||||
unset($this->values['cr'][$i], $this->values['crs'][$i], $this->values['crv'][$i]);
|
||||
|
||||
$this->values['cr'] = array_values($this->values['cr']);
|
||||
$this->values['crs'] = array_values($this->values['crs']);
|
||||
$this->values['crv'] = array_values($this->values['crv']);
|
||||
}
|
||||
}
|
||||
|
||||
public function evalCriteria() : void // [cr]iterium, [cr].[s]ign, [cr].[v]alue
|
||||
private function evalCriteria() : void // [cr]iterium, [cr].[s]ign, [cr].[v]alue
|
||||
{
|
||||
if (empty($this->criteria['cr']) && empty($this->criteria['crs']) && empty($this->criteria['crv']))
|
||||
if (empty($this->values['cr']) && empty($this->values['crs']) && empty($this->values['crv']))
|
||||
return;
|
||||
else if (empty($this->criteria['cr']) || empty($this->criteria['crs']) || empty($this->criteria['crv']))
|
||||
{
|
||||
unset($this->criteria['cr']);
|
||||
unset($this->criteria['crs']);
|
||||
unset($this->criteria['crv']);
|
||||
|
||||
trigger_error('Filter::setCriteria - one of cr, crs, crv is missing', E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
if (empty($this->values['cr']) || empty($this->values['crs']) || empty($this->values['crv']))
|
||||
{
|
||||
trigger_error('Filter::evalCriteria - one of cr, crs, crv is missing', E_USER_NOTICE);
|
||||
unset($this->values['cr'], $this->values['crs'], $this->values['crv']);
|
||||
|
||||
$this->error =
|
||||
$this->shouldReload = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$_cr = &$this->criteria['cr'];
|
||||
$_crs = &$this->criteria['crs'];
|
||||
$_crv = &$this->criteria['crv'];
|
||||
$_cr = &$this->values['cr'];
|
||||
$_crs = &$this->values['crs'];
|
||||
$_crv = &$this->values['crv'];
|
||||
|
||||
if (count($_cr) != count($_crv) || count($_cr) != count($_crs) || count($_cr) > 5 || count($_crs) > 5 /*|| count($_crv) > 5*/)
|
||||
{
|
||||
// use min provided criterion as basis; 5 criteria at most
|
||||
$min = max(5, min(count($_cr), count($_crv), count($_crs)));
|
||||
$min = min(5, count($_cr), count($_crv), count($_crs));
|
||||
if (count($_cr) > $min)
|
||||
array_splice($_cr, $min);
|
||||
|
||||
@@ -345,70 +384,88 @@ abstract class Filter
|
||||
if (count($_crs) > $min)
|
||||
array_splice($_crs, $min);
|
||||
|
||||
trigger_error('Filter::setCriteria - cr, crs, crv are imbalanced', E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
trigger_error('Filter::evalCriteria - cr, crs, crv are imbalanced', E_USER_NOTICE);
|
||||
$this->error =
|
||||
$this->shouldReload = true;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < count($_cr); $i++)
|
||||
{
|
||||
// conduct filter specific checks & casts here
|
||||
$unsetme = false;
|
||||
if (isset(static::$genericFilter[$_cr[$i]]))
|
||||
if (!isset(static::$genericFilter[$_cr[$i]]) || $_crs[$i] === '' || $_crv[$i] === '')
|
||||
{
|
||||
$gf = static::$genericFilter[$_cr[$i]];
|
||||
switch ($gf[0])
|
||||
{
|
||||
case self::CR_NUMERIC:
|
||||
$_ = $_crs[$i];
|
||||
if (!Util::checkNumeric($_crv[$i], $gf[2]) || !$this->int2Op($_))
|
||||
$unsetme = true;
|
||||
break;
|
||||
case self::CR_BOOLEAN:
|
||||
case self::CR_FLAG:
|
||||
$_ = $_crs[$i];
|
||||
if (!$this->int2Bool($_))
|
||||
$unsetme = true;
|
||||
break;
|
||||
case self::CR_ENUM:
|
||||
case self::CR_STAFFFLAG:
|
||||
if (!Util::checkNumeric($_crs[$i], NUM_CAST_INT))
|
||||
$unsetme = true;
|
||||
break;
|
||||
}
|
||||
if ($_crs[$i] === '' || $_crv[$i] === '')
|
||||
trigger_error('Filter::evalCriteria - received malformed criterium ["'.$_cr[$i].'", "'.$_crs[$i].'", "'.$_crv[$i].'"]', E_USER_NOTICE);
|
||||
else
|
||||
trigger_error('Filter::evalCriteria - received unhandled criterium: '.$_cr[$i], E_USER_NOTICE);
|
||||
|
||||
unset($_cr[$i], $_crs[$i], $_crv[$i]);
|
||||
|
||||
$this->error =
|
||||
$this->shouldReload = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$unsetme && intval($_cr[$i]) && $_crs[$i] !== '' && $_crv[$i] !== '')
|
||||
continue;
|
||||
[$crType, $colOrFn, $param1, $param2] = array_pad(static::$genericFilter[$_cr[$i]], 4, null);
|
||||
|
||||
unset($_cr[$i]);
|
||||
unset($_crs[$i]);
|
||||
unset($_crv[$i]);
|
||||
// conduct filter specific checks & casts here
|
||||
switch ($crType)
|
||||
{
|
||||
case self::CR_NUMERIC:
|
||||
$_ = $_crs[$i];
|
||||
if (Util::checkNumeric($_crv[$i], $param1) && $this->int2Op($_))
|
||||
continue 2;
|
||||
break;
|
||||
case self::CR_BOOLEAN:
|
||||
case self::CR_FLAG:
|
||||
$_ = $_crs[$i];
|
||||
if ($this->int2Bool($_))
|
||||
continue 2;
|
||||
break;
|
||||
case self::CR_STAFFFLAG:
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE) && Util::checkNumeric($_crs[$i], NUM_CAST_INT))
|
||||
continue 2;
|
||||
break;
|
||||
case self::CR_ENUM:
|
||||
if (Util::checkNumeric($_crs[$i], NUM_CAST_INT) && (
|
||||
(!$param2 && isset(static::$enums[$_cr[$i]][$_crs[$i]])) ||
|
||||
($param2 && in_array($_crs[$i], static::$enums[$_cr[$i]])) ||
|
||||
($param1 && ($_crs[$i] == self::ENUM_ANY || $_crs[$i] == self::ENUM_NONE))
|
||||
))
|
||||
continue 2;
|
||||
break;
|
||||
case self::CR_STRING:
|
||||
case self::CR_CALLBACK:
|
||||
case self::CR_NYI_PH:
|
||||
continue 2;
|
||||
default:
|
||||
trigger_error('Filter::evalCriteria - unknown criteria type: '.$crType, E_USER_WARNING);
|
||||
break;
|
||||
}
|
||||
|
||||
trigger_error('Filter::setCriteria - generic check failed ["'.$_cr[$i].'", "'.$_crs[$i].'", "'.$_crv[$i].'"]', E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
trigger_error('Filter::evalCriteria - generic check failed ["'.$_cr[$i].'", "'.$_crs[$i].'", "'.$_crv[$i].'"]', E_USER_NOTICE);
|
||||
unset($_cr[$i], $_crs[$i], $_crv[$i]);
|
||||
|
||||
$this->error =
|
||||
$this->shouldReload = true;
|
||||
}
|
||||
|
||||
$this->fiSetCriteria = array(
|
||||
'cr' => $_cr,
|
||||
'crs' => $_crs,
|
||||
'crv' => $_crv
|
||||
);
|
||||
$this->fiSetCriteria = [$_cr, $_crs, $_crv];
|
||||
}
|
||||
|
||||
public function evalWeights() : void
|
||||
private function evalWeights() : void
|
||||
{
|
||||
// both empty: not in use; not an error
|
||||
if (!$this->values['wt'] && !$this->values['wtv'])
|
||||
if (empty($this->values['wt']) && empty($this->values['wtv']))
|
||||
return;
|
||||
|
||||
// one empty: erroneous manual input?
|
||||
if (!$this->values['wt'] || !$this->values['wtv'])
|
||||
{
|
||||
unset($this->values['wt']);
|
||||
unset($this->values['wtv']);
|
||||
|
||||
trigger_error('Filter::setWeights - one of wt, wtv is missing', E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
unset($this->values['wt'], $this->values['wtv']);
|
||||
|
||||
$this->error =
|
||||
$this->shouldReload = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -421,7 +478,8 @@ abstract class Filter
|
||||
if ($nwt != $nwtv)
|
||||
{
|
||||
trigger_error('Filter::setWeights - wt, wtv are imbalanced', E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
$this->error =
|
||||
$this->shouldReload = true;
|
||||
}
|
||||
|
||||
if ($nwt > $nwtv)
|
||||
@@ -452,20 +510,18 @@ abstract class Filter
|
||||
if (!Util::checkNumeric($val, NUM_CAST_INT))
|
||||
return false;
|
||||
|
||||
foreach ($valid as $k => $v)
|
||||
if (in_array($val, $valid))
|
||||
return true;
|
||||
|
||||
foreach ($valid as $v)
|
||||
{
|
||||
if (gettype($v) != 'array')
|
||||
continue;
|
||||
|
||||
if ($this->checkInput(self::V_RANGE, $v, $val, true))
|
||||
return true;
|
||||
|
||||
unset($valid[$k]);
|
||||
}
|
||||
|
||||
if (in_array($val, $valid))
|
||||
return true;
|
||||
|
||||
break;
|
||||
case self::V_RANGE:
|
||||
if (Util::checkNumeric($val, NUM_CAST_INT) && $val >= $valid[0] && $val <= $valid[1])
|
||||
@@ -486,7 +542,7 @@ abstract class Filter
|
||||
|
||||
if (!$recursive)
|
||||
{
|
||||
trigger_error('Filter::checkInput - check failed [type: '.$type.' valid: '.((string)$valid).' val: '.((string)$val).']', E_USER_NOTICE);
|
||||
trigger_error('Filter::checkInput - check failed [type: '.$type.' valid: '.Util::toString($valid).' val: '.((string)$val).']', E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
}
|
||||
|
||||
@@ -651,83 +707,72 @@ abstract class Filter
|
||||
return null;
|
||||
}
|
||||
|
||||
private function genericCriterion(int $cr, int $crs, string $crv) : ?array
|
||||
{
|
||||
[$crType, $colOrFn, $param1, $param2] = array_pad(static::$genericFilter[$cr], 4, null);
|
||||
$result = null;
|
||||
|
||||
switch ($crType)
|
||||
{
|
||||
case self::CR_NUMERIC:
|
||||
$result = $this->genericNumeric($colOrFn, $crv, $crs, $param1);
|
||||
break;
|
||||
case self::CR_FLAG:
|
||||
$result = $this->genericBooleanFlags($colOrFn, $param1, $crs, $param2);
|
||||
break;
|
||||
case self::CR_STAFFFLAG:
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE) && $crs > 0)
|
||||
$result = $this->genericBooleanFlags($colOrFn, (1 << ($crs - 1)), true);
|
||||
break;
|
||||
case self::CR_BOOLEAN:
|
||||
$result = $this->genericBoolean($colOrFn, $crs, !empty($param1));
|
||||
break;
|
||||
case self::CR_STRING:
|
||||
$result = $this->genericString($colOrFn, $crv, $param1);
|
||||
break;
|
||||
case self::CR_ENUM:
|
||||
if (!$param2 && isset(static::$enums[$cr][$crs]))
|
||||
$result = $this->genericEnum($colOrFn, static::$enums[$cr][$crs]);
|
||||
if ($param2 && in_array($crs, static::$enums[$cr]))
|
||||
$result = $this->genericEnum($colOrFn, $crs);
|
||||
else if ($param1 && ($crs == self::ENUM_ANY || $crs == self::ENUM_NONE))
|
||||
$result = $this->genericEnum($colOrFn, $crs);
|
||||
break;
|
||||
case self::CR_CALLBACK:
|
||||
$result = $this->{$colOrFn}($cr, $crs, $crv, $param1, $param2);
|
||||
break;
|
||||
case self::CR_NYI_PH: // do not limit with not implemented filters
|
||||
if (is_int($param1))
|
||||
return [$param1];
|
||||
|
||||
// for nonsensical values; compare against 0
|
||||
if ($this->int2Op($crs) && Util::checkNumeric($crv))
|
||||
{
|
||||
if ($crs == '=')
|
||||
$crs = '==';
|
||||
|
||||
return eval('return ('.$crv.' '.$crs.' 0);') ? [1] : [0];
|
||||
}
|
||||
else
|
||||
return [0];
|
||||
}
|
||||
|
||||
if ($result && $crType == self::CR_NUMERIC && !empty($param2))
|
||||
$this->fiExtraCols[] = $cr;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/***********************************/
|
||||
/* create conditions from */
|
||||
/* non-generic values and criteria */
|
||||
/***********************************/
|
||||
|
||||
protected function createSQLForCriterium(int &$cr, int &$crs, string &$crv) : array
|
||||
protected function createSQLForCriterium(int $cr, int $crs, string $crv) : array
|
||||
{
|
||||
if (!static::$genericFilter) // criteria not in use - no error
|
||||
return [];
|
||||
|
||||
if (isset(static::$genericFilter[$cr]))
|
||||
if ($genCr = $this->genericCriterion($cr, $crs, $crv))
|
||||
return $genCr;
|
||||
[$crType, $colOrFn, $param1, $param2] = array_pad(static::$genericFilter[$cr], 4, null);
|
||||
|
||||
trigger_error('Filter::createSQLForCriterium - received unhandled criterium: ["'.$cr.'", "'.$crs.'", "'.$crv.'"]', E_USER_NOTICE);
|
||||
$this->error = true;
|
||||
$handleEnum = function(int $cr, int $crs, string $col, ?bool $hasAnyNone, ?bool $crsAsVal) : ?array
|
||||
{
|
||||
if ($hasAnyNone && ($crs == self::ENUM_ANY || $crs == self::ENUM_NONE))
|
||||
return $this->genericEnum($col, $crs);
|
||||
else if (!$crsAsVal && isset(static::$enums[$cr][$crs]))
|
||||
return $this->genericEnum($col, static::$enums[$cr][$crs]);
|
||||
else if ($crsAsVal && in_array($crs, static::$enums[$cr]))
|
||||
return $this->genericEnum($col, $crs);
|
||||
|
||||
unset($cr, $crs, $crv);
|
||||
return null;
|
||||
};
|
||||
|
||||
return [];
|
||||
$handleNYIPH = function(int $crs, string $crv, ?int $forceResult) : ?array
|
||||
{
|
||||
if (is_int($forceResult))
|
||||
return [$forceResult];
|
||||
|
||||
// for nonsensical values; compare against 0
|
||||
if ($this->int2Op($crs) && Util::checkNumeric($crv))
|
||||
{
|
||||
if ($crs == '=')
|
||||
$crs = '==';
|
||||
|
||||
return eval('return ('.$crv.' '.$crs.' 0);') ? [1] : [0];
|
||||
}
|
||||
else
|
||||
return [0];
|
||||
};
|
||||
|
||||
$result = match ($crType)
|
||||
{
|
||||
self::CR_NUMERIC => $this->genericNumeric($colOrFn, $crv, $crs, $param1),
|
||||
self::CR_FLAG => $this->genericBooleanFlags($colOrFn, $param1, $crs, $param2),
|
||||
self::CR_STAFFFLAG => $this->genericBooleanFlags($colOrFn, (1 << ($crs - 1)), true),
|
||||
self::CR_BOOLEAN => $this->genericBoolean($colOrFn, $crs, !empty($param1)),
|
||||
self::CR_STRING => $this->genericString($colOrFn, $crv, $param1),
|
||||
self::CR_CALLBACK => $this->{$colOrFn}($cr, $crs, $crv, $param1, $param2),
|
||||
self::CR_ENUM => $handleEnum($cr, $crs, $colOrFn, $param1, $param2),
|
||||
self::CR_NYI_PH => $handleNYIPH($crs, $crv, $param1),
|
||||
default => null
|
||||
};
|
||||
|
||||
if (!$result)
|
||||
{
|
||||
// this really should not have happened. The relevant checks are run on __construct()
|
||||
trigger_error('Filter::createSQLForCriterium - failed to resolve criterium: ["'.$cr.'", "'.$crs.'", "'.$crv.'"]', E_USER_WARNING);
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($crType == self::CR_NUMERIC && !empty($param2))
|
||||
$this->fiExtraCols[] = $cr;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
abstract protected function createSQLForValues() : array;
|
||||
|
||||
@@ -15,12 +15,12 @@ class IconElement
|
||||
private const CREATE_ICON_TPL = "\$WH.ge('%s%d').appendChild(%s.createIcon(%s));\n";
|
||||
|
||||
private int $idx = 0;
|
||||
private string $href = '';
|
||||
private bool $noIcon = false;
|
||||
|
||||
public readonly string $quality;
|
||||
public readonly ?string $align;
|
||||
public readonly ?string $href;
|
||||
public readonly int $size;
|
||||
public readonly bool $noIcon;
|
||||
|
||||
public function __construct(
|
||||
public readonly int $type,
|
||||
@@ -70,6 +70,8 @@ class IconElement
|
||||
|
||||
if ($link || $url)
|
||||
$this->href = $url ?: '?'.Type::getFileString($this->type).'='.$this->typeId;
|
||||
else
|
||||
$this->href = null;
|
||||
|
||||
// see Spell/Tools having icon container but no actual icon and having to be inline with other IconElements
|
||||
$this->noIcon = !$typeId || !Type::hasIcon($type);
|
||||
@@ -102,7 +104,7 @@ class IconElement
|
||||
}
|
||||
|
||||
if ($this->href)
|
||||
($a = $dom->createElement('a', $this->text))->setAttribute('href', $this->href);
|
||||
($a = $dom->createElement('a', htmlentities($this->text)))->setAttribute('href', $this->href);
|
||||
else
|
||||
$a = $dom->createTextNode($this->text);
|
||||
|
||||
@@ -148,9 +150,9 @@ class IconElement
|
||||
|
||||
$params = [$this->typeId, $this->size];
|
||||
if ($this->num || $this->qty)
|
||||
$params[] = is_numeric($this->num) ? $this->num : "'".$this->num."'";
|
||||
$params[] = is_int($this->num) ? $this->num : "'".$this->num."'";
|
||||
if ($this->qty)
|
||||
$params[] = is_numeric($this->qty) ? $this->qty : "'".$this->qty."'";
|
||||
$params[] = is_int($this->qty) ? $this->qty : "'".$this->qty."'";
|
||||
|
||||
return str_repeat(' ', $lpad) . sprintf(self::CREATE_ICON_TPL, $this->element, $this->idx, Type::getJSGlobalString($this->type), implode(', ', $params));
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class InfoboxMarkup extends Markup
|
||||
{
|
||||
public function __construct(private array $items, array $opts, string $parent = '')
|
||||
public function __construct(private array $items, array $opts, string $parent = '', private int $completionRowType = 0)
|
||||
{
|
||||
parent::__construct('', $opts, $parent);
|
||||
}
|
||||
@@ -23,27 +23,48 @@ class InfoboxMarkup extends Markup
|
||||
|
||||
public function append(string $text) : self
|
||||
{
|
||||
if ($this->items && !$this->__text)
|
||||
$this->replace('[ul][li]' . implode('[/li][li]', $this->items) . '[/li][/ul]');
|
||||
if ($_ = $this->prepare())
|
||||
$this->replace($_);
|
||||
|
||||
return parent::append($text);
|
||||
}
|
||||
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($this->items && !$this->__text)
|
||||
$this->replace('[ul][li]' . implode('[/li][li]', $this->items) . '[/li][/ul]');
|
||||
// inject before output to avoid adding it to cache
|
||||
if ($this->completionRowType && User::getCharacters())
|
||||
$this->items[] = [Lang::profiler('completion') . '[span class="compact-completion-display"][/span]', ['style' => 'display:none']];
|
||||
|
||||
if ($_ = $this->prepare())
|
||||
$this->replace($_);
|
||||
|
||||
return parent::__toString();
|
||||
}
|
||||
|
||||
public function getJsGlobals() : array
|
||||
{
|
||||
if ($this->items && !$this->__text)
|
||||
$this->replace('[ul][li]' . implode('[/li][li]', $this->items) . '[/li][/ul]');
|
||||
if ($_ = $this->prepare())
|
||||
$this->replace($_);
|
||||
|
||||
return parent::getJsGlobals();
|
||||
}
|
||||
|
||||
private function prepare() : string
|
||||
{
|
||||
if (!$this->items || $this->__text)
|
||||
return '';
|
||||
|
||||
$buff = '';
|
||||
foreach ($this->items as $row)
|
||||
{
|
||||
if (is_array($row))
|
||||
$buff .= '[li'.Util::nodeAttributes($row[1]).']' . $row[0] . '[/li]';
|
||||
else if (is_string($row))
|
||||
$buff .= '[li]' . $row . '[/li]';
|
||||
}
|
||||
|
||||
return $buff ? '[ul]'.$buff.'[/ul]' : '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -146,9 +146,9 @@ class Listview implements \JsonSerializable
|
||||
$this->tabs = $tabVar;
|
||||
}
|
||||
|
||||
public function setError() : void
|
||||
public function setError(bool $enable) : void
|
||||
{
|
||||
$this->_errors = 1;
|
||||
$this->_errors = $enable ? 1 : null;
|
||||
}
|
||||
|
||||
public function jsonSerialize() : array
|
||||
@@ -164,10 +164,11 @@ class Listview implements \JsonSerializable
|
||||
|
||||
public function __toString() : string
|
||||
{
|
||||
$addIn = '';
|
||||
if ($this->__addIn)
|
||||
include($this->__addIn);
|
||||
$addIn = file_get_contents($this->__addIn).PHP_EOL;
|
||||
|
||||
return "new Listview(".Util::toJSON($this).");\n";
|
||||
return $addIn.'new Listview('.Util::toJSON($this).');'.PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,11 @@ class Tooltip implements \JsonSerializable
|
||||
private ?string $buff = null;
|
||||
private ?array $buffspells = null;
|
||||
|
||||
public function __construct(private string $__powerTpl, private string $__subject, array $opts = [])
|
||||
public function __construct(private string $__powerTpl, private int|string $__subject, array $opts = [])
|
||||
{
|
||||
if (!is_int($this->__subject))
|
||||
$this->__subject = Util::toJSON($this->__subject, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
foreach ($opts as $k => $v)
|
||||
{
|
||||
if (property_exists($this, $k))
|
||||
@@ -54,7 +57,7 @@ class Tooltip implements \JsonSerializable
|
||||
|
||||
public function __toString() : string
|
||||
{
|
||||
return sprintf($this->__powerTpl, Util::toJSON($this->__subject, JSON_AOWOW_POWER), Lang::getLocale()->value, Util::toJSON($this, JSON_AOWOW_POWER))."\n";
|
||||
return sprintf($this->__powerTpl, $this->__subject, Lang::getLocale()->value, Util::toJSON($this, JSON_AOWOW_POWER))."\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class LocString
|
||||
class LocString implements \JsonSerializable
|
||||
{
|
||||
private \WeakMap $store;
|
||||
|
||||
@@ -24,6 +24,11 @@ class LocString
|
||||
$this->store[$l] = (string)$callback($data[$key.'_loc'.$l->value] ?? '');
|
||||
}
|
||||
|
||||
public function jsonSerialize() : string
|
||||
{
|
||||
return $this->__toString();
|
||||
}
|
||||
|
||||
public function __toString() : string
|
||||
{
|
||||
if ($str = $this->store[Lang::getLocale()])
|
||||
|
||||
@@ -30,6 +30,8 @@ class PageTemplate
|
||||
private string $gStaticUrl;
|
||||
private string $gHost;
|
||||
private string $gServerTime;
|
||||
private string $gUser;
|
||||
private string $gFavorites;
|
||||
private ?string $analyticsTag = null;
|
||||
private bool $consentFooter = false;
|
||||
private string $dbProfiles = '';
|
||||
@@ -336,7 +338,7 @@ class PageTemplate
|
||||
$result[] = "var fi_type = '".$this->filter->fiType."'";
|
||||
|
||||
if ($this->filter->fiSetCriteria) // arr:criteria, arr:signs, arr:values
|
||||
$result[] = 'fi_setCriteria('.mb_substr(Util::toJSON(array_values($this->filter->fiSetCriteria)), 1, -1).");";
|
||||
$result[] = 'fi_setCriteria('.mb_substr(Util::toJSON($this->filter->fiSetCriteria), 1, -1).");";
|
||||
|
||||
/*
|
||||
nt: don't try to match provided weights on predefined weight sets (preselects preset from opt list and ..?)
|
||||
@@ -470,7 +472,7 @@ class PageTemplate
|
||||
private function update() : void
|
||||
{
|
||||
// analytics + consent
|
||||
if (!isset($_COOKIE['consent']))
|
||||
if ($this->analyticsTag && !isset($_COOKIE['consent']))
|
||||
{
|
||||
$this->addScript(SC_CSS_FILE, 'css/consent.css');
|
||||
$this->addScript(SC_JS_FILE, 'js/consent.js');
|
||||
@@ -484,6 +486,9 @@ class PageTemplate
|
||||
// js + css
|
||||
$this->prepareScripts();
|
||||
|
||||
$this->gUser = Util::toJSON(User::getUserGlobal());
|
||||
$this->gFavorites = Util::toJSON(User::getFavorites());
|
||||
|
||||
// db profiling
|
||||
if (Cfg::get('DEBUG') >= LOG_LEVEL_INFO && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
|
||||
$this->dbProfiles = \Aowow\DB::getProfiles();
|
||||
@@ -496,7 +501,7 @@ class PageTemplate
|
||||
|
||||
foreach ($this->lvTabs->iterate() as $lv)
|
||||
if ($lv instanceof \Aowow\Listview)
|
||||
$lv->setError();
|
||||
$lv->setError(true);
|
||||
}
|
||||
|
||||
// pre-serialization: if a var is relevant it was stored in $rawData
|
||||
@@ -505,6 +510,11 @@ class PageTemplate
|
||||
$this->context = null; // unlink from TemplateResponse
|
||||
$this->pageData = []; // clear modified data
|
||||
|
||||
if ($this->lvTabs) // do not store lvErrors in cache
|
||||
foreach ($this->lvTabs->iterate() as $lv)
|
||||
if ($lv instanceof \Aowow\Listview)
|
||||
$lv->setError(false);
|
||||
|
||||
$vars = [];
|
||||
foreach ($this as $k => $_)
|
||||
$vars[] = $k;
|
||||
@@ -536,7 +546,7 @@ class PageTemplate
|
||||
if (!$this->context)
|
||||
return null;
|
||||
|
||||
if (!property_exists($this->context, $var))
|
||||
if (!isset(get_object_vars($this->context)[$var]))
|
||||
return null;
|
||||
|
||||
$this->rawData[$var] = $this->context->$var;
|
||||
|
||||
@@ -8,10 +8,10 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class Profiler
|
||||
{
|
||||
public const PID_FILE = 'config/pr-queue-pid';
|
||||
public const CHAR_GMFLAGS = 0x1 | 0x8 | 0x10 | 0x20; // PLAYER_EXTRA_ :: GM_ON | TAXICHEAT | GM_INVISIBLE | GM_CHAT
|
||||
public const /* string */ PID_FILE = 'config/pr-queue-pid';
|
||||
public const /* int */ CHAR_GMFLAGS = 0x1 | 0x8 | 0x10 | 0x20; // PLAYER_EXTRA_ :: GM_ON | TAXICHEAT | GM_INVISIBLE | GM_CHAT
|
||||
|
||||
public const REGIONS = array( // see cfg_categories.dbc
|
||||
public const /* array */ REGIONS = array( // see cfg_categories.dbc
|
||||
'us' => [2, 3, 4, 5], // US (us, oceanic, latin america, americas - tournament)
|
||||
'kr' => [6, 7], // KR (kr, tournament)
|
||||
'eu' => [8, 9, 10, 11, 12, 13], // EU (english, german, french, spanish, russian, eu - tournament)
|
||||
@@ -20,9 +20,9 @@ class Profiler
|
||||
'dev' => [1, 26, 27, 28, 30] // Development, Test Server, Test Server - tournament, QA Server, Test Server 2
|
||||
);
|
||||
|
||||
private static $realms = [];
|
||||
private static array $realms = [];
|
||||
|
||||
public static $slot2InvType = array(
|
||||
public static array $slot2InvType = array(
|
||||
1 => [INVTYPE_HEAD], // head
|
||||
2 => [INVTYPE_NECK], // neck
|
||||
3 => [INVTYPE_SHOULDERS], // shoulder
|
||||
@@ -44,7 +44,7 @@ class Profiler
|
||||
19 => [INVTYPE_TABARD], // tabard
|
||||
);
|
||||
|
||||
public static $raidProgression = array( // statisticAchievement => relevantCriterium ; don't forget to enable this in /js/Profiler.js as well
|
||||
public static array $raidProgression = array( // statisticAchievement => relevantCriterium ; don't forget to enable this in /js/Profiler.js as well
|
||||
1361 => 5100, 1362 => 5101, 1363 => 5102, 1365 => 5104, 1366 => 5108, 1364 => 5110, 1369 => 5112, 1370 => 5113, 1371 => 5114, 1372 => 5117, 1373 => 5119, 1374 => 5120, 1375 => 7805, 1376 => 5122, 1377 => 5123, // Naxxramas 10
|
||||
1367 => 5103, 1368 => 5111, 1378 => 5124, 1379 => 5125, 1380 => 5126, 1381 => 5127, 1382 => 5128, 1383 => 7806, 1384 => 5130, 1385 => 5131, 1386 => 5132, 1387 => 5133, 1388 => 5134, 1389 => 5135, 1390 => 5136, // Naxxramas 25
|
||||
2856 => 9938, 2857 => 9939, 2858 => 9940, 2859 => 9941, 2861 => 9943, 2865 => 9947, 2866 => 9948, 2868 => 9950, 2869 => 9951, 2870 => 9952, 2863 => 10558, 2864 => 10559, 2862 => 10560, 2867 => 10565, 2860 => 10580, // Ulduar 10
|
||||
@@ -65,7 +65,7 @@ class Profiler
|
||||
4821 => 13466, // Ruby Sanctum 10 nh
|
||||
);
|
||||
|
||||
public static function getBuyoutForItem($itemId)
|
||||
public static function getBuyoutForItem(int $itemId) : int
|
||||
{
|
||||
if (!$itemId)
|
||||
return 0;
|
||||
@@ -75,7 +75,7 @@ class Profiler
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function queueStart(&$msg = '')
|
||||
public static function queueStart(?string &$msg = '') : bool
|
||||
{
|
||||
$queuePID = self::queueStatus();
|
||||
|
||||
@@ -100,7 +100,7 @@ class Profiler
|
||||
}
|
||||
}
|
||||
|
||||
public static function queueStatus()
|
||||
public static function queueStatus() : int
|
||||
{
|
||||
if (!file_exists(self::PID_FILE))
|
||||
return 0;
|
||||
@@ -117,7 +117,7 @@ class Profiler
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function queueLock($pid)
|
||||
public static function queueLock(int $pid) : bool
|
||||
{
|
||||
$queuePID = self::queueStatus();
|
||||
if ($queuePID && $queuePID != $pid)
|
||||
@@ -139,12 +139,12 @@ class Profiler
|
||||
return $ok;
|
||||
}
|
||||
|
||||
public static function queueFree()
|
||||
public static function queueFree() : void
|
||||
{
|
||||
unlink(self::PID_FILE);
|
||||
}
|
||||
|
||||
public static function urlize($str, $allowLocales = false, $profile = false)
|
||||
public static function urlize(string $str, bool $allowLocales = false, bool $profile = false) : string
|
||||
{
|
||||
$search = ['<', '>', ' / ', "'"];
|
||||
$replace = ['<', '>', '-', '' ];
|
||||
@@ -194,7 +194,7 @@ class Profiler
|
||||
if (!DB::isConnectable(DB_AUTH) || self::$realms)
|
||||
return self::$realms;
|
||||
|
||||
self::$realms = DB::Auth()->select(
|
||||
$realms = DB::Auth()->select(
|
||||
'SELECT `id` AS ARRAY_KEY,
|
||||
`name`,
|
||||
CASE WHEN `timezone` BETWEEN 2 AND 5 THEN "us" # US, Oceanic, Latin America, Americas-Tournament
|
||||
@@ -209,14 +209,14 @@ class Profiler
|
||||
WOW_BUILD
|
||||
);
|
||||
|
||||
foreach (self::$realms as $rId => &$rData)
|
||||
if (!$realms)
|
||||
return [];
|
||||
|
||||
foreach ($realms as $rId => $rData)
|
||||
{
|
||||
// realm in db but no connection info set
|
||||
if (!DB::isConnectable(DB_CHARACTERS . $rId))
|
||||
{
|
||||
unset(self::$realms[$rId]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// filter by access level
|
||||
if ($rData['access'] == SEC_ADMINISTRATOR && (CLI || User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN)))
|
||||
@@ -226,10 +226,7 @@ class Profiler
|
||||
else if ($rData['access'] == SEC_MODERATOR && (CLI || User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN | U_GROUP_MOD | U_GROUP_BUREAU)))
|
||||
$rData['access'] = U_GROUP_DEV | U_GROUP_ADMIN | U_GROUP_MOD | U_GROUP_BUREAU;
|
||||
else if ($rData['access'] > SEC_PLAYER && !CLI)
|
||||
{
|
||||
unset(self::$realms[$rId]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// filter dev realms
|
||||
if ($rData['region'] === 'dev')
|
||||
@@ -237,11 +234,10 @@ class Profiler
|
||||
if (CLI || User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
|
||||
$rData['access'] = U_GROUP_DEV | U_GROUP_ADMIN;
|
||||
else
|
||||
{
|
||||
unset(self::$realms[$rId]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
self::$realms[$rId] = $rData;
|
||||
}
|
||||
|
||||
return self::$realms;
|
||||
@@ -255,7 +251,7 @@ class Profiler
|
||||
return array_unique(array_column(self::$realms, 'region'));
|
||||
}
|
||||
|
||||
private static function queueInsert($realmId, $guid, $type, $localId)
|
||||
private static function queueInsert(int $realmId, int $guid, int $type, int $localId) : void
|
||||
{
|
||||
if ($rData = DB::Aowow()->selectRow('SELECT `requestTime` AS "time", `status` FROM ?_profiler_sync WHERE `realm` = ?d AND `realmGUID` = ?d AND `type` = ?d AND `typeId` = ?d AND `status` <> ?d', $realmId, $guid, $type, $localId, PR_QUEUE_STATUS_WORKING))
|
||||
{
|
||||
@@ -270,7 +266,7 @@ class Profiler
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_sync (`realm`, `realmGUID`, `type`, `typeId`, `requestTime`, `status`, `errorCode`) VALUES (?d, ?d, ?d, ?d, UNIX_TIMESTAMP(), ?d, 0)', $realmId, $guid, $type, $localId, PR_QUEUE_STATUS_WAITING);
|
||||
}
|
||||
|
||||
public static function scheduleResync($type, $realmId, $guid)
|
||||
public static function scheduleResync(int $type, int $realmId, int $guid) : int
|
||||
{
|
||||
$newId = 0;
|
||||
|
||||
@@ -339,7 +335,7 @@ class Profiler
|
||||
// error out all profiles with status WORKING, that are older than 60sec
|
||||
DB::Aowow()->query('UPDATE ?_profiler_sync SET `status` = ?d, `errorCode` = ?d WHERE `status` = ?d AND `requestTime` < ?d', PR_QUEUE_STATUS_ERROR, PR_QUEUE_ERROR_UNK, PR_QUEUE_STATUS_WORKING, time() - MINUTE);
|
||||
|
||||
$subjectStatus = DB::Aowow()->select('SELECT `typeId` AS ARRAY_KEY, `status`, `realm`, `errorCode` FROM ?_profiler_sync WHERE `type` = ?d AND `typeId` IN (?a)', $type, $subjectGUIDs);
|
||||
$subjectStatus = DB::Aowow()->select('SELECT `typeId` AS ARRAY_KEY, `status`, `realm`, `errorCode`, `requestTime` FROM ?_profiler_sync WHERE `type` = ?d AND `typeId` IN (?a)', $type, $subjectGUIDs);
|
||||
$queue = DB::Aowow()->selectCol('SELECT CONCAT(`type`, ":", `typeId`) FROM ?_profiler_sync WHERE `status` = ?d AND `requestTime` < UNIX_TIMESTAMP() ORDER BY `requestTime` ASC', PR_QUEUE_STATUS_WAITING);
|
||||
foreach ($subjectGUIDs as $guid)
|
||||
{
|
||||
@@ -347,6 +343,8 @@ class Profiler
|
||||
$response[] = [PR_QUEUE_STATUS_ERROR, 0, 0, PR_QUEUE_ERROR_UNK];
|
||||
else if ($subjectStatus[$guid]['status'] == PR_QUEUE_STATUS_ERROR)
|
||||
$response[] = [PR_QUEUE_STATUS_ERROR, 0, 0, $subjectStatus[$guid]['errorCode']];
|
||||
else if ($subjectStatus[$guid]['requestTime'] > time())
|
||||
$response[] = [PR_QUEUE_STATUS_READY, 0, 0, 0];
|
||||
else
|
||||
$response[] = array(
|
||||
$subjectStatus[$guid]['status'],
|
||||
@@ -361,7 +359,7 @@ class Profiler
|
||||
return Util::toJSON($response);
|
||||
}
|
||||
|
||||
public static function getCharFromRealm($realmId, $charGuid)
|
||||
public static function getCharFromRealm(int $realmId, int $charGuid) : bool
|
||||
{
|
||||
$char = DB::Characters($realmId)->selectRow('SELECT c.* FROM characters c WHERE c.`guid` = ?d', $charGuid);
|
||||
if (!$char)
|
||||
@@ -505,7 +503,7 @@ class Profiler
|
||||
// char is flagged for rename
|
||||
if ($char['at_login'] & 0x1)
|
||||
{
|
||||
$ri = DB::Aowow()->selectCell('SELECT MAX(`renameItr`) FROM ?_profiler_profiles WHERE `realm` = ?d AND `realmGUID` IS NOT NULL AND `name` = ?', $realmId, $char['name']);
|
||||
$ri = DB::Aowow()->selectCell('SELECT MAX(`renameItr`) FROM ?_profiler_profiles WHERE `realm` = ?d AND `custom` = 0 AND `name` = ?', $realmId, $char['name']);
|
||||
$data['renameItr'] = $ri ? ++$ri : 1;
|
||||
}
|
||||
|
||||
@@ -580,7 +578,7 @@ class Profiler
|
||||
// enchantId => multiple spells => multiple items with varying itemlevels, quality, whatevs
|
||||
// cant reasonably get to the castItem from enchantId and slot
|
||||
|
||||
$profSpec = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, `skillLevel` AS "1", `skillLine` AS "0" FROM ?_itemenchantment WHERE `id` IN (?a)', $permEnch);
|
||||
$profSpec = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `skillLevel` AS "1", `skillLine` AS "0" FROM ?_itemenchantment WHERE `id` IN (?a)', $permEnch);
|
||||
foreach ($permEnch as $slot => $eId)
|
||||
{
|
||||
if (!isset($profSpec[$eId]))
|
||||
@@ -623,7 +621,22 @@ class Profiler
|
||||
$petData['entry']
|
||||
);
|
||||
|
||||
$_ = DB::Aowow()->selectCol('SELECT `spell` AS ARRAY_KEY, MAX(IF(`spell` IN (?a), `rank`, 0)) FROM ?_talents WHERE `class` = 0 AND `petTypeMask` = ?d GROUP BY `row`, `col` ORDER BY `row`, `col` ASC', $petSpells ?: [0], 1 << $morePet['type']);
|
||||
if (!$morePet)
|
||||
{
|
||||
trigger_error('char #'.$charGuid.' on realm #'.$realmId.' owns pet #'.$petGuid.' (creature entry: #'.$petData['entry'].') without pet family. skipping...', E_USER_WARNING);
|
||||
continue;
|
||||
}
|
||||
|
||||
$_ = DB::Aowow()->selectCol(
|
||||
'SELECT IFNULL(t2.`rank`, 0)
|
||||
FROM ?_talents t1
|
||||
LEFT JOIN (SELECT `id`, `rank` FROM ?_talents WHERE `spell` IN (?a)) t2 ON t2.`id` = t1.`id`
|
||||
WHERE `class` = 0 AND `petTypeMask` = ?d
|
||||
GROUP BY t1.`id`
|
||||
ORDER BY t1.`row`, t1.`col`, t1.`id` ASC',
|
||||
$petSpells ?: [0], 1 << $morePet['type']
|
||||
);
|
||||
|
||||
$pet = array(
|
||||
'id' => $petGuid,
|
||||
'owner' => $profileId,
|
||||
@@ -692,10 +705,10 @@ class Profiler
|
||||
// get base values for this race/class
|
||||
$reputation = [];
|
||||
$baseRep = DB::Aowow()->selectCol(
|
||||
'SELECT `id` AS ARRAY_KEY, `baseRepValue1` FROM aowow_factions WHERE `baseRepValue1` AND (`baseRepRaceMask1` & ?d OR (`baseRepClassMask1` AND NOT `baseRepRaceMask1`)) AND ((`baseRepClassMask1` & ?d) OR NOT `baseRepClassMask1`) UNION
|
||||
SELECT `id` AS ARRAY_KEY, `baseRepValue2` FROM aowow_factions WHERE `baseRepValue2` AND (`baseRepRaceMask2` & ?d OR (`baseRepClassMask2` AND NOT `baseRepRaceMask2`)) AND ((`baseRepClassMask2` & ?d) OR NOT `baseRepClassMask2`) UNION
|
||||
SELECT `id` AS ARRAY_KEY, `baseRepValue3` FROM aowow_factions WHERE `baseRepValue3` AND (`baseRepRaceMask3` & ?d OR (`baseRepClassMask3` AND NOT `baseRepRaceMask3`)) AND ((`baseRepClassMask3` & ?d) OR NOT `baseRepClassMask3`) UNION
|
||||
SELECT `id` AS ARRAY_KEY, `baseRepValue4` FROM aowow_factions WHERE `baseRepValue4` AND (`baseRepRaceMask4` & ?d OR (`baseRepClassMask4` AND NOT `baseRepRaceMask4`)) AND ((`baseRepClassMask4` & ?d) OR NOT `baseRepClassMask4`)',
|
||||
'SELECT `id` AS ARRAY_KEY, `baseRepValue1` FROM ?_factions WHERE `baseRepValue1` AND (`baseRepRaceMask1` & ?d OR (`baseRepClassMask1` AND NOT `baseRepRaceMask1`)) AND ((`baseRepClassMask1` & ?d) OR NOT `baseRepClassMask1`) UNION
|
||||
SELECT `id` AS ARRAY_KEY, `baseRepValue2` FROM ?_factions WHERE `baseRepValue2` AND (`baseRepRaceMask2` & ?d OR (`baseRepClassMask2` AND NOT `baseRepRaceMask2`)) AND ((`baseRepClassMask2` & ?d) OR NOT `baseRepClassMask2`) UNION
|
||||
SELECT `id` AS ARRAY_KEY, `baseRepValue3` FROM ?_factions WHERE `baseRepValue3` AND (`baseRepRaceMask3` & ?d OR (`baseRepClassMask3` AND NOT `baseRepRaceMask3`)) AND ((`baseRepClassMask3` & ?d) OR NOT `baseRepClassMask3`) UNION
|
||||
SELECT `id` AS ARRAY_KEY, `baseRepValue4` FROM ?_factions WHERE `baseRepValue4` AND (`baseRepRaceMask4` & ?d OR (`baseRepClassMask4` AND NOT `baseRepRaceMask4`)) AND ((`baseRepClassMask4` & ?d) OR NOT `baseRepClassMask4`)',
|
||||
$ra->toMask(), $cl->toMask(), $ra->toMask(), $cl->toMask(), $ra->toMask(), $cl->toMask(), $ra->toMask(), $cl->toMask()
|
||||
);
|
||||
|
||||
@@ -814,7 +827,7 @@ class Profiler
|
||||
'realmGUID' => $guild['id'],
|
||||
'name' => $guild['name'],
|
||||
'nameUrl' => self::urlize($guild['name']),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
'stub' => 1
|
||||
);
|
||||
|
||||
$guildId = DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_guild (?#) VALUES (?a)', array_keys($gData), array_values($gData));
|
||||
@@ -840,7 +853,7 @@ class Profiler
|
||||
'name' => $t['name'],
|
||||
'nameUrl' => self::urlize($t['name']),
|
||||
'type' => $t['type'],
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
'stub' => 1
|
||||
);
|
||||
|
||||
$teamId = DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team (?#) VALUES (?a)', array_keys($team), array_values($team));
|
||||
@@ -876,12 +889,12 @@ class Profiler
|
||||
/*********************/
|
||||
|
||||
if (DB::Aowow()->query('UPDATE ?_profiler_profiles SET ?a WHERE `realm` = ?d AND `realmGUID` = ?d', $data, $realmId, $charGuid) !== null)
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET `cuFlags` = `cuFlags` & ?d WHERE `id` = ?d', ~PROFILER_CU_NEEDS_RESYNC, $profileId);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET `stub` = 0 WHERE `id` = ?d', $profileId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getGuildFromRealm($realmId, $guildGuid)
|
||||
public static function getGuildFromRealm(int $realmId, int $guildGuid) : bool
|
||||
{
|
||||
$guild = DB::Characters($realmId)->selectRow('SELECT `guildId`, `name`, `createDate`, `info`, `backgroundColor`, `emblemStyle`, `emblemColor`, `borderStyle`, `borderColor` FROM guild WHERE `guildId` = ?d', $guildGuid);
|
||||
if (!$guild)
|
||||
@@ -943,12 +956,12 @@ class Profiler
|
||||
/* mark guild as done */
|
||||
/*********************/
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_guild SET `cuFlags` = `cuFlags` & ?d WHERE `id` = ?d', ~PROFILER_CU_NEEDS_RESYNC, $guildId);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_guild SET `stub` = 0 WHERE `id` = ?d', $guildId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getArenaTeamFromRealm($realmId, $teamGuid)
|
||||
public static function getArenaTeamFromRealm(int $realmId, int $teamGuid) : bool
|
||||
{
|
||||
$team = DB::Characters($realmId)->selectRow('SELECT `arenaTeamId`, `name`, `type`, `captainGuid`, `rating`, `seasonGames`, `seasonWins`, `weekGames`, `weekWins`, `rank`, `backgroundColor`, `emblemStyle`, `emblemColor`, `borderStyle`, `borderColor` FROM arena_team WHERE `arenaTeamId` = ?d', $teamGuid);
|
||||
if (!$team)
|
||||
@@ -1043,7 +1056,7 @@ class Profiler
|
||||
/* mark team as done */
|
||||
/*********************/
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_arena_team SET `cuFlags` = `cuFlags` & ?d WHERE `id` = ?d', ~PROFILER_CU_NEEDS_RESYNC, $teamId);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_arena_team SET `stub` = 0 WHERE `id` = ?d', $teamId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -144,11 +144,11 @@ class Report
|
||||
$this->subject ??= 0; // 0 for utility, tools and misc pages?
|
||||
}
|
||||
|
||||
private function checkTargetContext() : int
|
||||
private function checkTargetContext(?string $url) : int
|
||||
{
|
||||
// check already reported
|
||||
$field = User::isLoggedIn() ? 'userId' : 'ip';
|
||||
if (DB::Aowow()->selectCell('SELECT 1 FROM ?_reports WHERE `mode` = ?d AND `reason`= ?d AND `subject` = ?d AND ?# = ?', $this->mode, $this->reason, $this->subject, $field, User::$id ?: User::$ip))
|
||||
if (DB::Aowow()->selectCell('SELECT 1 FROM ?_reports WHERE `mode` = ?d AND `reason`= ?d AND `subject` = ?d{ AND `url` = ?} AND ?# = ?', $this->mode, $this->reason, $this->subject, $url ?: DBSIMPLE_SKIP, $field, User::$id ?: User::$ip))
|
||||
return self::ERR_ALREADY_REPORTED;
|
||||
|
||||
// check targeted post/postOwner staff status
|
||||
@@ -190,7 +190,28 @@ class Report
|
||||
return false;
|
||||
}
|
||||
|
||||
if($err = $this->checkTargetContext())
|
||||
// clean up src url: dont use anchors, clean up query
|
||||
if ($pageUrl)
|
||||
{
|
||||
$urlParts = parse_url($pageUrl);
|
||||
if (!empty($urlParts['query']))
|
||||
{
|
||||
parse_str($urlParts['query'], $query); // kills redundant param declarations
|
||||
unset($query['locale']); // locale param shouldn't be needed. more..?
|
||||
$urlParts['query'] = http_build_query($query);
|
||||
}
|
||||
|
||||
$pageUrl = '';
|
||||
if (isset($urlParts['scheme']))
|
||||
$pageUrl .= $urlParts['scheme'].':';
|
||||
|
||||
$pageUrl .= '//'.($urlParts['host'] ?? '').($urlParts['path'] ?? '');
|
||||
|
||||
if (isset($urlParts['query']))
|
||||
$pageUrl .= '?'.$urlParts['query'];
|
||||
}
|
||||
|
||||
if ($err = $this->checkTargetContext($pageUrl))
|
||||
{
|
||||
$this->errorCode = $err;
|
||||
return false;
|
||||
|
||||
@@ -201,9 +201,9 @@ trait TrCache
|
||||
{
|
||||
$this->initCache();
|
||||
|
||||
// type+typeId+catg; 3+6+10
|
||||
// type+typeId/catg+mode; 3+10+1
|
||||
$cKey = $this->formatCacheKey();
|
||||
$cKey[2] = substr($cKey[2], 0, 19);
|
||||
$cKey[2] = substr($cKey[2], 0, 13);
|
||||
|
||||
if ($modeMask & CACHE_MODE_MEMCACHED)
|
||||
foreach ($this->memcached()?->getAllKeys() ?? [] as $k)
|
||||
@@ -265,29 +265,27 @@ trait TrCache
|
||||
// https://stackoverflow.com/questions/466521
|
||||
private function formatCacheKey() : array
|
||||
{
|
||||
[$dbType, $dbTypeId, $category, $staffMask, $miscInfo] = $this->getCacheKeyComponents();
|
||||
[$dbType, $dbTypeIdOrCat, $staffMask, $miscInfo] = $this->getCacheKeyComponents();
|
||||
|
||||
$fileKey = '';
|
||||
// DBType: 3
|
||||
$fileKey .= str_pad(dechex($dbType & 0xFFF), 3, 0, STR_PAD_LEFT);
|
||||
// DBTypeId: 6
|
||||
$fileKey .= str_pad(dechex($dbTypeId & 0xFFFFFF), 6, 0, STR_PAD_LEFT);
|
||||
// category: (2+4+4)
|
||||
$fileKey .= str_pad(dechex($category & 0xFFFFFFFFFF), 2+4+4, 0, STR_PAD_LEFT);
|
||||
// DBTypeId: 6 / category: (2+4+4)
|
||||
$fileKey .= str_pad(dechex($dbTypeIdOrCat & 0xFFFFFFFFFF), 2+4+4, 0, STR_PAD_LEFT);
|
||||
// cacheType: 1
|
||||
$fileKey .= str_pad(dechex($this->_cacheType & 0xF), 1, 0, STR_PAD_LEFT);
|
||||
// localeId: 2,
|
||||
$fileKey .= str_pad(dechex(Lang::getLocale()->value & 0xFF), 2, 0, STR_PAD_LEFT);
|
||||
// staff mask: 4
|
||||
$fileKey .= str_pad(dechex($staffMask & 0xFFFFFFFF), 4, 0, STR_PAD_LEFT);
|
||||
// optioal: miscInfo
|
||||
// optional: miscInfo
|
||||
if ($miscInfo)
|
||||
$fileKey .= '-'.$miscInfo;
|
||||
|
||||
// topDir, 2ndDir, file
|
||||
return array(
|
||||
str_pad(dechex($dbType & 0xFF), 2, 0, STR_PAD_LEFT),
|
||||
str_pad(dechex(($dbTypeId > 0 ? $dbTypeId : $category) & 0xFF), 2, 0, STR_PAD_LEFT),
|
||||
str_pad(dechex(($dbTypeIdOrCat) & 0xFF), 2, 0, STR_PAD_LEFT),
|
||||
$fileKey
|
||||
);
|
||||
}
|
||||
@@ -325,12 +323,17 @@ trait TrSearch
|
||||
|
||||
public function getCacheKeyComponents() : array
|
||||
{
|
||||
$misc = $this->query . // can be empty for upgrade search
|
||||
serialize($this->_get['wt'] ?? null) . // extra &_GET not expected for normal and opensearch
|
||||
serialize($this->_get['wtv'] ?? null) .
|
||||
serialize($this->_get['type'] ?? null) .
|
||||
serialize($this->_get['slots'] ?? null);
|
||||
|
||||
return array(
|
||||
-1, // DBType
|
||||
-1, // DBTypeId
|
||||
$this->searchMask, // category
|
||||
$this->searchMask, // DBTypeId/category
|
||||
User::$groups, // staff mask
|
||||
md5($this->query) // misc (here search query)
|
||||
md5($misc) // misc
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -645,6 +648,13 @@ abstract class BaseResponse
|
||||
return preg_replace('/ +/', ' ', trim($str));
|
||||
}
|
||||
|
||||
protected static function checkLocale(string $localeId) : ?Locale
|
||||
{
|
||||
if (Util::checkNumeric($localeId, NUM_CAST_INT))
|
||||
return Locale::tryFrom($localeId);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/********************/
|
||||
/* child implements */
|
||||
|
||||
@@ -21,8 +21,7 @@ trait TrDetailPage
|
||||
{
|
||||
return array(
|
||||
$this->type, // DBType
|
||||
$this->typeId, // DBTypeId
|
||||
-1, // category
|
||||
$this->typeId, // DBTypeId/category
|
||||
User::$groups, // staff mask
|
||||
'' // misc (here unused)
|
||||
);
|
||||
@@ -54,8 +53,7 @@ trait TrListPage
|
||||
|
||||
return array(
|
||||
$this->type, // DBType
|
||||
-1, // DBTypeId
|
||||
$catg ?? -1, // category
|
||||
$catg ?? -1, // DBTypeId/category
|
||||
User::$groups, // staff mask
|
||||
$misc ?? '' // misc (here filter)
|
||||
);
|
||||
@@ -217,7 +215,7 @@ class TemplateResponse extends BaseResponse
|
||||
if (!$this->result)
|
||||
$this->dataLoader = array_merge($this->dataLoader, $dataFiles);
|
||||
else
|
||||
$this->result->addDataLoader($dataFiles);
|
||||
$this->result->addDataLoader(...$dataFiles);
|
||||
}
|
||||
|
||||
public static function pageStatsHook(Template\PageTemplate &$pt, array &$stats) : void
|
||||
@@ -420,7 +418,7 @@ class TemplateResponse extends BaseResponse
|
||||
if (isset($this->guideRevision))
|
||||
$article = DB::Aowow()->selectRow('SELECT `article`, `locale`, `editAccess` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d AND `rev` = ?d',
|
||||
Type::GUIDE, $this->typeId, $this->guideRevision);
|
||||
if (!$article && $this->gPageInfo['articleUrl'])
|
||||
if (!$article && !empty($this->gPageInfo['articleUrl']))
|
||||
$article = DB::Aowow()->selectRow('SELECT `article`, `locale`, `editAccess` FROM ?_articles WHERE `url` = ? AND `locale` IN (?a) ORDER BY `locale` DESC, `rev` DESC LIMIT 1',
|
||||
$this->gPageInfo['articleUrl'], [Lang::getLocale()->value, Locale::EN->value]);
|
||||
if (!$article && !empty($this->type) && isset($this->typeId))
|
||||
@@ -625,7 +623,14 @@ class TemplateResponse extends BaseResponse
|
||||
// as this may be loaded from cache, it will be unlinked from its response
|
||||
if ($ptJSG = $this->result->jsGlobals)
|
||||
{
|
||||
Util::mergeJsGlobals($ptJSG, $this->jsGlobals);
|
||||
foreach ($this->jsGlobals as $type => [, $data, ])
|
||||
{
|
||||
if (!isset($ptJSG[$type]) || $type == Type::USER)
|
||||
$ptJSG[$type] = $this->jsGlobals[$type];
|
||||
else
|
||||
Util::mergeJsGlobals($ptJSG[$type][1], $data);
|
||||
}
|
||||
|
||||
$this->result->jsGlobals = $ptJSG;
|
||||
}
|
||||
else if ($this->jsGlobals)
|
||||
|
||||
@@ -14,14 +14,13 @@ trait TrTooltip
|
||||
{
|
||||
$key = array(
|
||||
$this->type, // DBType
|
||||
$this->typeId, // DBTypeId
|
||||
-1, // category
|
||||
$this->typeId, // DBTypeId/category
|
||||
User::$groups, // staff mask
|
||||
'' // misc (here tooltip)
|
||||
);
|
||||
|
||||
if ($this->enhancedTT)
|
||||
$key[4] = md5(serialize($this->enhancedTT));
|
||||
$key[3] = md5(serialize($this->enhancedTT));
|
||||
|
||||
return $key;
|
||||
}
|
||||
@@ -90,7 +89,7 @@ trait TrCommunityHelper
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TextResponse extends BaseResponse
|
||||
class TextResponse extends BaseResponse
|
||||
{
|
||||
protected string $contentType = MIME_TYPE_JAVASCRIPT;
|
||||
protected ?string $redirectTo = null;
|
||||
@@ -164,6 +163,8 @@ abstract class TextResponse extends BaseResponse
|
||||
|
||||
echo $out;
|
||||
}
|
||||
|
||||
protected function generate() : void {}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -108,7 +108,7 @@ class Search
|
||||
{
|
||||
$clean = str_replace(['\\', '%'], '', $raw);
|
||||
|
||||
if (!$clean === '')
|
||||
if ($clean === '')
|
||||
continue;
|
||||
|
||||
if ($clean[0] == '-')
|
||||
|
||||
@@ -235,7 +235,7 @@ class RemoteArenaTeamList extends ArenaTeamList
|
||||
'nameUrl' => Profiler::urlize($this->getField('name')),
|
||||
'type' => $this->getField('type'),
|
||||
'rating' => $this->getField('rating'),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
'stub' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class CreatureList extends DBTypeList
|
||||
|
||||
protected string $queryBase = 'SELECT ct.*, ct.`id` AS ARRAY_KEY FROM ?_creature ct';
|
||||
public array $queryOpts = array(
|
||||
'ct' => [['ft', 'qse', 'dct1', 'dct2', 'dct3'], 's' => ', IFNULL(dct1.`id`, IFNULL(dct2.`id`, IFNULL(dct3.`id`, 0))) AS "parentId", IFNULL(dct1.`name_loc0`, IFNULL(dct2.`name_loc0`, IFNULL(dct3.`name_loc0`, ""))) AS "parent_loc0", IFNULL(dct1.`name_loc2`, IFNULL(dct2.`name_loc2`, IFNULL(dct3.`name_loc2`, ""))) AS "parent_loc2", IFNULL(dct1.`name_loc3`, IFNULL(dct2.`name_loc3`, IFNULL(dct3.`name_loc3`, ""))) AS "parent_loc3", IFNULL(dct1.`name_loc4`, IFNULL(dct2.`name_loc4`, IFNULL(dct3.`name_loc4`, ""))) AS "`parent_loc4`", IFNULL(dct1.`name_loc6`, IFNULL(dct2.`name_loc6`, IFNULL(dct3.`name_loc6`, ""))) AS "`parent_loc6`", IFNULL(dct1.name_loc8, IFNULL(dct2.`name_loc8`, IFNULL(dct3.`name_loc8`, ""))) AS "parent_loc8", IF(dct1.`difficultyEntry1` = ct.`id`, 1, IF(dct2.`difficultyEntry2` = ct.`id`, 2, IF(dct3.`difficultyEntry3` = ct.`id`, 3, 0))) AS "difficultyMode"'],
|
||||
'ct' => [['ft', 'qse', 'dct1', 'dct2', 'dct3'], 's' => ', IFNULL(dct1.`id`, IFNULL(dct2.`id`, IFNULL(dct3.`id`, 0))) AS "parentId", IFNULL(dct1.`name_loc0`, IFNULL(dct2.`name_loc0`, IFNULL(dct3.`name_loc0`, ""))) AS "parent_loc0", IFNULL(dct1.`name_loc2`, IFNULL(dct2.`name_loc2`, IFNULL(dct3.`name_loc2`, ""))) AS "parent_loc2", IFNULL(dct1.`name_loc3`, IFNULL(dct2.`name_loc3`, IFNULL(dct3.`name_loc3`, ""))) AS "parent_loc3", IFNULL(dct1.`name_loc4`, IFNULL(dct2.`name_loc4`, IFNULL(dct3.`name_loc4`, ""))) AS "parent_loc4", IFNULL(dct1.`name_loc6`, IFNULL(dct2.`name_loc6`, IFNULL(dct3.`name_loc6`, ""))) AS "parent_loc6", IFNULL(dct1.name_loc8, IFNULL(dct2.`name_loc8`, IFNULL(dct3.`name_loc8`, ""))) AS "parent_loc8", IF(dct1.`difficultyEntry1` = ct.`id`, 1, IF(dct2.`difficultyEntry2` = ct.`id`, 2, IF(dct3.`difficultyEntry3` = ct.`id`, 3, 0))) AS "difficultyMode"'],
|
||||
'dct1' => ['j' => ['?_creature dct1 ON ct.`cuFlags` & 0x02 AND dct1.`difficultyEntry1` = ct.`id`', true]],
|
||||
'dct2' => ['j' => ['?_creature dct2 ON ct.`cuFlags` & 0x02 AND dct2.`difficultyEntry2` = ct.`id`', true]],
|
||||
'dct3' => ['j' => ['?_creature dct3 ON ct.`cuFlags` & 0x02 AND dct3.`difficultyEntry3` = ct.`id`', true]],
|
||||
@@ -332,8 +332,8 @@ class CreatureListFilter extends Filter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // also match subname
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'fa' => [parent::V_CALLBACK, 'cbPetFamily', true ], // pet family [list] - cat[0] == 1
|
||||
'minle' => [parent::V_RANGE, [1, 99], false], // min level [int]
|
||||
'maxle' => [parent::V_RANGE, [1, 99], false], // max level [int]
|
||||
'minle' => [parent::V_RANGE, [0, 99], false], // min level [int]
|
||||
'maxle' => [parent::V_RANGE, [0, 99], false], // max level [int]
|
||||
'cl' => [parent::V_RANGE, [0, 4], true ], // classification [list]
|
||||
'ra' => [parent::V_LIST, [-1, 0, 1], false], // react alliance [int]
|
||||
'rh' => [parent::V_LIST, [-1, 0, 1], false] // react horde [int]
|
||||
@@ -376,11 +376,11 @@ class CreatureListFilter extends Filter
|
||||
$parts[] = ['rank', $_v['cl']];
|
||||
|
||||
// react Alliance [int]
|
||||
if ($_v['ra'])
|
||||
if (!is_null($_v['ra']))
|
||||
$parts[] = ['ft.A', $_v['ra']];
|
||||
|
||||
// react Horde [int]
|
||||
if ($_v['rh'])
|
||||
if (!is_null($_v['rh']))
|
||||
$parts[] = ['ft.H', $_v['rh']];
|
||||
|
||||
return $parts;
|
||||
|
||||
@@ -56,17 +56,23 @@ class EnchantmentList extends DBTypeList
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// issue with scaling stats enchantments
|
||||
// stats are stored as NOT NULL to be usable by the search filters and such become indistinguishable from scaling enchantments that _actually_ use the value 0
|
||||
// so filter the stats container and if it is empty, rebuild from self. .. there are no mixed scaling/static enchantments, right!?
|
||||
$this->jsonStats[$this->id] = (new StatsContainer)->fromJson($curTpl, true)->filter();
|
||||
if (!count($this->jsonStats[$this->id]))
|
||||
$this->jsonStats[$this->id]->fromEnchantment($curTpl);
|
||||
}
|
||||
|
||||
if ($relSpells)
|
||||
$this->relSpells = new SpellList(array(['id', $relSpells]));
|
||||
|
||||
// issue with scaling stats enchantments
|
||||
// stats are stored as NOT NULL to be usable by the search filters and such become indistinguishable from scaling enchantments that _actually_ use the value 0
|
||||
// so we can't rely on ?_item_stats and always have to calc stats
|
||||
foreach ($this->iterate() as $ench)
|
||||
{
|
||||
$relSpells = [];
|
||||
foreach ($ench['spells'] as $s)
|
||||
if ($_ = $this->relSpells->getEntry($s[0]))
|
||||
$relSpells[$s[0]] = $_;
|
||||
|
||||
$this->jsonStats[$this->id] = (new StatsContainer($relSpells))->fromEnchantment($ench);
|
||||
}
|
||||
}
|
||||
|
||||
public function getListviewData(int $addInfoMask = 0x0) : array
|
||||
@@ -122,7 +128,7 @@ class EnchantmentList extends DBTypeList
|
||||
|
||||
public function getStatGainForCurrent() : array
|
||||
{
|
||||
return $this->jsonStats[$this->id]->toJson(includeEmpty: false);
|
||||
return $this->jsonStats[$this->id]->toJson(includeEmpty: true);
|
||||
}
|
||||
|
||||
public function getRelSpell(int $id) : ?array
|
||||
|
||||
@@ -99,7 +99,7 @@ class GameObjectList extends DBTypeList
|
||||
if (isset($this->curTpl['lockId']))
|
||||
if ($locks = Lang::getLocks($this->curTpl['lockId']))
|
||||
foreach ($locks as $l)
|
||||
$x .= '<tr><td>'.sprintf(Lang::game('requires'), $l).'</td></tr>';
|
||||
$x .= '<tr><td>'.Lang::game('requires', [$l]).'</td></tr>';
|
||||
|
||||
$x .= '</table>';
|
||||
|
||||
|
||||
@@ -48,18 +48,16 @@ class GuildList extends DBTypeList
|
||||
if (!$guilds)
|
||||
return;
|
||||
|
||||
$stats = DB::Aowow()->select('SELECT `guild` AS ARRAY_KEY, `id` AS ARRAY_KEY2, `level`, `gearscore`, `achievementpoints`, IF(`cuFlags` & ?d, 0, 1) AS "synced" FROM ?_profiler_profiles WHERE `guild` IN (?a) ORDER BY `gearscore` DESC', PROFILER_CU_NEEDS_RESYNC, $guilds);
|
||||
$stats = DB::Aowow()->select('SELECT `guild` AS ARRAY_KEY, `id` AS ARRAY_KEY2, `level`, `gearscore`, `achievementpoints` FROM ?_profiler_profiles WHERE `guild` IN (?a) AND `stub` = 0 ORDER BY `gearscore` DESC', $guilds);
|
||||
foreach ($this->iterate() as &$_curTpl)
|
||||
{
|
||||
$id = $_curTpl['id'];
|
||||
if (empty($stats[$id]))
|
||||
continue;
|
||||
|
||||
$guildStats = array_filter($stats[$id], function ($x) { return $x['synced']; } );
|
||||
if (!$guildStats)
|
||||
continue;
|
||||
$guildStats = $stats[$id];
|
||||
|
||||
$nMaxLevel = count(array_filter($stats[$id], function ($x) { return $x['level'] >= MAX_LEVEL; } ));
|
||||
$nMaxLevel = count(array_filter($stats[$id], fn($x) => $x['level'] >= MAX_LEVEL));
|
||||
$levelMod = 1.0;
|
||||
|
||||
if ($nMaxLevel < 25)
|
||||
@@ -227,7 +225,7 @@ class RemoteGuildList extends GuildList
|
||||
'realmGUID' => $this->getField('guildid'),
|
||||
'name' => $this->getField('name'),
|
||||
'nameUrl' => Profiler::urlize($this->getField('name')),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
'stub' => 1
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,12 @@ class ItemList extends DBTypeList
|
||||
public array $rndEnchIds = [];
|
||||
public array $subItems = [];
|
||||
|
||||
private array $ssd = [];
|
||||
private array $vendors = [];
|
||||
private array $jsGlobals = []; // getExtendedCost creates some and has no access to template
|
||||
private array $enhanceR = [];
|
||||
private array $relEnchant = [];
|
||||
private array $randPropPoints = [];
|
||||
private array $ssd = [];
|
||||
private array $vendors = [];
|
||||
private array $jsGlobals = []; // getExtendedCost creates some and has no access to template
|
||||
private array $enhanceR = [];
|
||||
private array $relEnchant = [];
|
||||
|
||||
protected string $queryBase = 'SELECT i.*, i.`block` AS "tplBlock", i.`armor` AS tplArmor, i.`dmgMin1` AS "tplDmgMin1", i.`dmgMax1` AS "tplDmgMax1", i.`id` AS ARRAY_KEY, i.`id` AS "id" FROM ?_items i';
|
||||
protected array $queryOpts = array( // 3 => Type::ITEM
|
||||
@@ -486,6 +487,11 @@ class ItemList extends DBTypeList
|
||||
'quality' => $this->curTpl['quality'],
|
||||
'icon' => $this->curTpl['iconString']
|
||||
);
|
||||
|
||||
if ($this->curTpl['class'] == ITEM_CLASS_RECIPE)
|
||||
$data[Type::ITEM][$id]['completion_category'] = $this->curTpl['class'];
|
||||
else if ($this->curTpl['class'] == ITEM_CLASS_MISC && in_array($this->curTpl['subClass'], [2, 5, -7]))
|
||||
$data[Type::ITEM][$id]['completion_category'] = $this->curTpl['class'].'-'.$this->curTpl['subClass'];
|
||||
}
|
||||
|
||||
if ($addMask & GLOBALINFO_EXTRA)
|
||||
@@ -753,6 +759,13 @@ class ItemList extends DBTypeList
|
||||
case Stat::INTELLECT:
|
||||
case Stat::SPIRIT:
|
||||
case Stat::STAMINA:
|
||||
// case Stat::ARMOR: // unused by 335a client, still set in item_template
|
||||
// case Stat::FIRE_RESISTANCE:
|
||||
// case Stat::FROST_RESISTANCE:
|
||||
// case Stat::HOLY_RESISTANCE:
|
||||
// case Stat::SHADOW_RESISTANCE:
|
||||
// case Stat::NATURE_RESISTANCE:
|
||||
// case Stat::ARCANE_RESISTANCE:
|
||||
$x .= '<span><!--stat'.$statId.'-->'.Lang::item('statType', $type, [ord($qty > 0 ? '+' : '-'), abs($qty)]).'</span><br />';
|
||||
break;
|
||||
default: // rating with % for reqLevel
|
||||
@@ -929,7 +942,7 @@ class ItemList extends DBTypeList
|
||||
|
||||
// locked or openable
|
||||
if ($locks = Lang::getLocks($this->curTpl['lockId'], $arr, true))
|
||||
$x .= '<span class="q0">'.Lang::item('locked').'<br />'.implode('<br />', array_map(function($x) { return sprintf(Lang::game('requires'), $x); }, $locks)).'</span><br />';
|
||||
$x .= '<span class="q0">'.Lang::item('locked').'<br />'.implode('<br />', array_map(fn($x) => Lang::game('requires', [$x]), $locks)).'</span><br />';
|
||||
else if ($this->curTpl['flags'] & ITEM_FLAG_OPENABLE)
|
||||
$x .= '<span class="q2">'.Lang::item('openClick').'</span><br />';
|
||||
|
||||
@@ -1221,76 +1234,55 @@ class ItemList extends DBTypeList
|
||||
}
|
||||
|
||||
// from Trinity
|
||||
public function generateEnchSuffixFactor() : int
|
||||
public function generateEnchSuffixFactor() : float
|
||||
{
|
||||
$rpp = DB::Aowow()->selectRow('SELECT * FROM ?_itemrandomproppoints WHERE `id` = ?', $this->curTpl['itemLevel']);
|
||||
if (!$rpp)
|
||||
return 0;
|
||||
if (empty($this->randPropPoints[$this->curTpl['itemLevel']]))
|
||||
$this->randPropPoints[$this->curTpl['itemLevel']] = DB::Aowow()->selectRow('SELECT * FROM ?_itemrandomproppoints WHERE `id` = ?', $this->curTpl['itemLevel']);
|
||||
|
||||
switch ($this->curTpl['slot'])
|
||||
$rpp = &$this->randPropPoints[$this->curTpl['itemLevel']];
|
||||
|
||||
if (!$rpp)
|
||||
return 0.0;
|
||||
|
||||
$fieldIdx = match((int)$this->curTpl['slot'])
|
||||
{
|
||||
// Items of that type don`t have points
|
||||
case INVTYPE_NON_EQUIP:
|
||||
case INVTYPE_BAG:
|
||||
case INVTYPE_TABARD:
|
||||
case INVTYPE_AMMO:
|
||||
case INVTYPE_QUIVER:
|
||||
case INVTYPE_RELIC:
|
||||
return 0;
|
||||
// Select point coefficient
|
||||
case INVTYPE_HEAD:
|
||||
case INVTYPE_BODY:
|
||||
case INVTYPE_CHEST:
|
||||
case INVTYPE_LEGS:
|
||||
case INVTYPE_2HWEAPON:
|
||||
case INVTYPE_ROBE:
|
||||
$suffixFactor = 1;
|
||||
break;
|
||||
case INVTYPE_SHOULDERS:
|
||||
case INVTYPE_WAIST:
|
||||
case INVTYPE_FEET:
|
||||
case INVTYPE_HANDS:
|
||||
case INVTYPE_TRINKET:
|
||||
$suffixFactor = 2;
|
||||
break;
|
||||
case INVTYPE_NECK:
|
||||
case INVTYPE_WRISTS:
|
||||
case INVTYPE_FINGER:
|
||||
case INVTYPE_SHIELD:
|
||||
case INVTYPE_CLOAK:
|
||||
case INVTYPE_HOLDABLE:
|
||||
$suffixFactor = 3;
|
||||
break;
|
||||
case INVTYPE_WEAPON:
|
||||
case INVTYPE_WEAPONMAINHAND:
|
||||
case INVTYPE_WEAPONOFFHAND:
|
||||
$suffixFactor = 4;
|
||||
break;
|
||||
case INVTYPE_RANGED:
|
||||
case INVTYPE_THROWN:
|
||||
case INVTYPE_RANGEDRIGHT:
|
||||
$suffixFactor = 5;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
INVTYPE_HEAD,
|
||||
INVTYPE_BODY,
|
||||
INVTYPE_CHEST,
|
||||
INVTYPE_LEGS,
|
||||
INVTYPE_2HWEAPON,
|
||||
INVTYPE_ROBE => 1,
|
||||
INVTYPE_SHOULDERS,
|
||||
INVTYPE_WAIST,
|
||||
INVTYPE_FEET,
|
||||
INVTYPE_HANDS,
|
||||
INVTYPE_TRINKET => 2,
|
||||
INVTYPE_NECK,
|
||||
INVTYPE_WRISTS,
|
||||
INVTYPE_FINGER,
|
||||
INVTYPE_SHIELD,
|
||||
INVTYPE_CLOAK,
|
||||
INVTYPE_HOLDABLE => 3,
|
||||
INVTYPE_WEAPON,
|
||||
INVTYPE_WEAPONMAINHAND,
|
||||
INVTYPE_WEAPONOFFHAND => 4,
|
||||
INVTYPE_RANGED,
|
||||
INVTYPE_THROWN,
|
||||
INVTYPE_RANGEDRIGHT => 5,
|
||||
default => 0 // inv types that don`t have points
|
||||
};
|
||||
|
||||
if (!$fieldIdx)
|
||||
return 0.0;
|
||||
|
||||
// Select rare/epic modifier
|
||||
switch ($this->curTpl['quality'])
|
||||
return match((int)$this->curTpl['quality'])
|
||||
{
|
||||
case ITEM_QUALITY_UNCOMMON:
|
||||
return $rpp['uncommon'.$suffixFactor] / 10000;
|
||||
case ITEM_QUALITY_RARE:
|
||||
return $rpp['rare'.$suffixFactor] / 10000;
|
||||
case ITEM_QUALITY_EPIC:
|
||||
return $rpp['epic'.$suffixFactor] / 10000;
|
||||
case ITEM_QUALITY_LEGENDARY:
|
||||
case ITEM_QUALITY_ARTIFACT:
|
||||
return 0; // not have random properties
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
ITEM_QUALITY_UNCOMMON => $rpp['uncommon'.$fieldIdx] / 10000,
|
||||
ITEM_QUALITY_RARE => $rpp['rare'.$fieldIdx] / 10000,
|
||||
ITEM_QUALITY_EPIC => $rpp['epic'.$fieldIdx] / 10000,
|
||||
default => 0.0 // qualities that don't have random properties
|
||||
};
|
||||
}
|
||||
|
||||
public function extendJsonStats() : void
|
||||
@@ -1664,7 +1656,7 @@ class ItemList extends DBTypeList
|
||||
$mh = $j;
|
||||
else if ($j['id'] == $ohItem)
|
||||
$oh = $j;
|
||||
else if ($j['gearscore'])
|
||||
else if (!empty($j['gearscore']))
|
||||
{
|
||||
if ($j['slot'] == INVTYPE_RELIC)
|
||||
$score += 20;
|
||||
@@ -2021,10 +2013,10 @@ class ItemListFilter extends Filter
|
||||
'ty' => [parent::V_CALLBACK, 'cbTypeCheck', true ], // item type - dynamic by current group
|
||||
'sl' => [parent::V_CALLBACK, 'cbSlotCheck', true ], // item slot - dynamic by current group
|
||||
'si' => [parent::V_LIST, [-SIDE_HORDE, -SIDE_ALLIANCE, SIDE_ALLIANCE, SIDE_HORDE, SIDE_BOTH], false], // side
|
||||
'minle' => [parent::V_RANGE, [1, 999], false], // item level min
|
||||
'maxle' => [parent::V_RANGE, [1, 999], false], // item level max
|
||||
'minrl' => [parent::V_RANGE, [1, MAX_LEVEL], false], // required level min
|
||||
'maxrl' => [parent::V_RANGE, [1, MAX_LEVEL], false] // required level max
|
||||
'minle' => [parent::V_RANGE, [0, 999], false], // item level min
|
||||
'maxle' => [parent::V_RANGE, [0, 999], false], // item level max
|
||||
'minrl' => [parent::V_RANGE, [0, MAX_LEVEL], false], // required level min
|
||||
'maxrl' => [parent::V_RANGE, [0, MAX_LEVEL], false] // required level max
|
||||
);
|
||||
|
||||
public array $extraOpts = []; // score for statWeights
|
||||
|
||||
@@ -187,10 +187,10 @@ class ItemsetListFilter extends Filter
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'qu' => [parent::V_RANGE, [0, 7], true ], // quality
|
||||
'ty' => [parent::V_RANGE, [1, 12], true ], // set type
|
||||
'minle' => [parent::V_RANGE, [1, 999], false], // min item level
|
||||
'maxle' => [parent::V_RANGE, [1, 999], false], // max itemlevel
|
||||
'minrl' => [parent::V_RANGE, [1, MAX_LEVEL], false], // min required level
|
||||
'maxrl' => [parent::V_RANGE, [1, MAX_LEVEL], false], // max required level
|
||||
'minle' => [parent::V_RANGE, [0, 999], false], // min item level
|
||||
'maxle' => [parent::V_RANGE, [0, 999], false], // max itemlevel
|
||||
'minrl' => [parent::V_RANGE, [0, MAX_LEVEL], false], // min required level
|
||||
'maxrl' => [parent::V_RANGE, [0, MAX_LEVEL], false], // max required level
|
||||
'cl' => [parent::V_LIST, [[1, 9], 11], false], // class
|
||||
'ta' => [parent::V_RANGE, [1, 30], false] // tag / content group
|
||||
);
|
||||
|
||||
@@ -83,7 +83,7 @@ class ProfileList extends DBTypeList
|
||||
if ($this->getField('cuFlags') & PROFILER_CU_PINNED)
|
||||
$data[$this->id]['pinned'] = 1;
|
||||
|
||||
if ($this->getField('cuFlags') & PROFILER_CU_DELETED)
|
||||
if ($this->getField('deleted'))
|
||||
$data[$this->id]['deleted'] = 1;
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ class ProfileList extends DBTypeList
|
||||
|
||||
public function isCustom() : bool
|
||||
{
|
||||
return $this->getField('cuFlags') & PROFILER_CU_PROFILE;
|
||||
return $this->getField('custom');
|
||||
}
|
||||
|
||||
public function isVisibleToUser() : bool
|
||||
@@ -176,7 +176,7 @@ class ProfileList extends DBTypeList
|
||||
if (!$this->isCustom() || User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
return true;
|
||||
|
||||
if ($this->getField('cuFlags') & PROFILER_CU_DELETED)
|
||||
if ($this->getField('deleted'))
|
||||
return false;
|
||||
|
||||
if (User::$id == $this->getField('user'))
|
||||
@@ -269,8 +269,8 @@ class ProfileListFilter extends Filter
|
||||
{
|
||||
parent::__construct($data, $opts);
|
||||
|
||||
if (!empty($this->criteria['cr']))
|
||||
if (array_intersect($this->criteria['cr'], [2, 5, 6, 7, 21]))
|
||||
if (!empty($this->values['cr']))
|
||||
if (array_intersect($this->values['cr'], [2, 5, 6, 7, 21]))
|
||||
$this->useLocalList = true;
|
||||
}
|
||||
|
||||
@@ -515,7 +515,7 @@ class RemoteProfileList extends ProfileList
|
||||
if ($curTpl['at_login'] & 0x1)
|
||||
{
|
||||
if (!isset($this->rnItr[$curTpl['name']]))
|
||||
$this->rnItr[$curTpl['name']] = DB::Aowow()->selectCell('SELECT MAX(`renameItr`) FROM ?_profiler_profiles WHERE `realm` = ?d AND `realmGUID` IS NOT NULL AND `name` = ?', $r, $curTpl['name']) ?: 0;
|
||||
$this->rnItr[$curTpl['name']] = DB::Aowow()->selectCell('SELECT MAX(`renameItr`) FROM ?_profiler_profiles WHERE `realm` = ?d AND `custom` = 0 AND `name` = ?', $r, $curTpl['name']) ?: 0;
|
||||
|
||||
// already saved as "pending rename"
|
||||
if ($rnItr = DB::Aowow()->selectCell('SELECT `renameItr` FROM ?_profiler_profiles WHERE `realm` = ?d AND `realmGUID` = ?d', $r, $g))
|
||||
@@ -606,7 +606,7 @@ class RemoteProfileList extends ProfileList
|
||||
'gender' => $this->getField('gender'),
|
||||
'guild' => $guildGUID ?: null,
|
||||
'guildrank' => $guildGUID ? $this->getField('guildrank') : null,
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
'stub' => 1
|
||||
);
|
||||
|
||||
if ($guildGUID && empty($guildData[$realmId.'-'.$guildGUID]))
|
||||
@@ -615,7 +615,7 @@ class RemoteProfileList extends ProfileList
|
||||
'realmGUID' => $guildGUID,
|
||||
'name' => $this->getField('guildname'),
|
||||
'nameUrl' => Profiler::urlize($this->getField('guildname')),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
'stub' => 1
|
||||
);
|
||||
}
|
||||
|
||||
@@ -643,8 +643,7 @@ class RemoteProfileList extends ProfileList
|
||||
|
||||
// merge back local ids
|
||||
$localIds = DB::Aowow()->select(
|
||||
'SELECT CONCAT(`realm`, ":", `realmGUID`) AS ARRAY_KEY, `id`, `gearscore` FROM ?_profiler_profiles WHERE (`cuFlags` & ?d) = 0 AND `realm` IN (?a) AND `realmGUID` IN (?a)',
|
||||
PROFILER_CU_PROFILE,
|
||||
'SELECT CONCAT(`realm`, ":", `realmGUID`) AS ARRAY_KEY, `id`, `gearscore` FROM ?_profiler_profiles WHERE `custom` = 0 AND `realm` IN (?a) AND `realmGUID` IN (?a)',
|
||||
array_column($baseData, 'realm'),
|
||||
array_column($baseData, 'realmGUID')
|
||||
);
|
||||
@@ -662,7 +661,7 @@ class LocalProfileList extends ProfileList
|
||||
protected string $queryBase = 'SELECT p.*, p.`id` AS ARRAY_KEY FROM ?_profiler_profiles p';
|
||||
protected array $queryOpts = array(
|
||||
'p' => [['g'], 'g' => 'p.`id`'],
|
||||
'ap' => ['j' => ['?_account_profiles ap ON ap.`profileId` = p.`id`', true], 's' => ', (IFNULL(ap.`ExtraFlags`, 0) | p.`cuFlags`) AS "cuFlags"'],
|
||||
'ap' => ['j' => ['?_account_profiles ap ON ap.`profileId` = p.`id`', true], 's' => ', (IFNULL(ap.`extraFlags`, 0) | p.`cuFlags`) AS "cuFlags"'],
|
||||
'atm' => ['j' => ['?_profiler_arena_team_member atm ON atm.`profileId` = p.`id`', true], 's' => ', atm.`captain`, atm.`personalRating` AS "rating", atm.`seasonGames`, atm.`seasonWins`'],
|
||||
'at' => [['atm'], 'j' => ['?_profiler_arena_team at ON at.`id` = atm.`arenaTeamId`', true], 's' => ', at.`type`'],
|
||||
'g' => ['j' => ['?_profiler_guild g ON g.`id` = p.`guild`', true], 's' => ', g.`name` AS "guildname"']
|
||||
|
||||
@@ -415,7 +415,15 @@ class QuestList extends DBTypeList
|
||||
}
|
||||
|
||||
if ($addMask & GLOBALINFO_SELF)
|
||||
{
|
||||
$data[Type::QUEST][$this->id] = ['name' => $this->getField('name', true)];
|
||||
|
||||
if ($this->curTpl['flags'] & QUEST_FLAG_DAILY)
|
||||
$data[Type::QUEST][$this->id]['daily'] = true;
|
||||
|
||||
if ($this->curTpl['flags'] & QUEST_FLAG_WEEKLY)
|
||||
$data[Type::QUEST][$this->id]['weekly'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
@@ -478,10 +486,10 @@ class QuestListFilter extends Filter
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name / text - only printable chars, no delimiter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // also match subname
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'minle' => [parent::V_RANGE, [1, 99], false], // min quest level
|
||||
'maxle' => [parent::V_RANGE, [1, 99], false], // max quest level
|
||||
'minrl' => [parent::V_RANGE, [1, 99], false], // min required level
|
||||
'maxrl' => [parent::V_RANGE, [1, 99], false], // max required level
|
||||
'minle' => [parent::V_RANGE, [0, 99], false], // min quest level
|
||||
'maxle' => [parent::V_RANGE, [0, 99], false], // max quest level
|
||||
'minrl' => [parent::V_RANGE, [0, 99], false], // min required level
|
||||
'maxrl' => [parent::V_RANGE, [0, 99], false], // max required level
|
||||
'si' => [parent::V_LIST, [-SIDE_HORDE, -SIDE_ALLIANCE, SIDE_ALLIANCE, SIDE_HORDE, SIDE_BOTH], false], // side
|
||||
'ty' => [parent::V_LIST, [0, 1, 21, 41, 62, [81, 85], 88, 89], true ] // type
|
||||
);
|
||||
|
||||
@@ -23,12 +23,11 @@ class SpellList extends DBTypeList
|
||||
11 => SKILLS_TRADE_PRIMARY // prim. Professions
|
||||
);
|
||||
|
||||
public const EFFECTS_HEAL = array(
|
||||
SPELL_EFFECT_NONE, /*SPELL_EFFECT_DUMMY*/ SPELL_EFFECT_HEAL, SPELL_EFFECT_HEAL_MAX_HEALTH, SPELL_EFFECT_HEAL_MECHANICAL,
|
||||
SPELL_EFFECT_HEAL_PCT
|
||||
public const EFFECTS_SCALING_HEAL = array( // as per Unit::SpellHealingBonusDone() calls in TC
|
||||
SPELL_EFFECT_HEAL, SPELL_EFFECT_HEAL_PCT, SPELL_EFFECT_HEAL_MECHANICAL, SPELL_EFFECT_HEALTH_LEECH
|
||||
);
|
||||
public const EFFECTS_DAMAGE = array(
|
||||
SPELL_EFFECT_NONE, SPELL_EFFECT_DUMMY, SPELL_EFFECT_SCHOOL_DAMAGE, SPELL_EFFECT_HEALTH_LEECH, SPELL_EFFECT_POWER_BURN
|
||||
public const EFFECTS_SCALING_DAMAGE = array( // as per Unit::SpellDamageBonusDone() calls in TC
|
||||
SPELL_EFFECT_SCHOOL_DAMAGE, SPELL_EFFECT_HEALTH_LEECH, SPELL_EFFECT_POWER_BURN
|
||||
);
|
||||
public const EFFECTS_ITEM_CREATE = array(
|
||||
SPELL_EFFECT_CREATE_ITEM, SPELL_EFFECT_SUMMON_CHANGE_ITEM, SPELL_EFFECT_CREATE_RANDOM_ITEM, SPELL_EFFECT_CREATE_MANA_GEM, SPELL_EFFECT_CREATE_ITEM_2
|
||||
@@ -48,21 +47,19 @@ class SpellList extends DBTypeList
|
||||
public const EFFECTS_MODEL_NPC = array(
|
||||
SPELL_EFFECT_SUMMON, SPELL_EFFECT_SUMMON_PET, SPELL_EFFECT_SUMMON_DEMON, SPELL_EFFECT_KILL_CREDIT, SPELL_EFFECT_KILL_CREDIT2
|
||||
);
|
||||
public const EFFECTS_DIRECT_SCALING = array(
|
||||
public const EFFECTS_DIRECT_SCALING = array( // as per Unit::GetCastingTimeForBonus()
|
||||
SPELL_EFFECT_SCHOOL_DAMAGE, SPELL_EFFECT_ENVIRONMENTAL_DAMAGE, SPELL_EFFECT_POWER_DRAIN, SPELL_EFFECT_HEALTH_LEECH, SPELL_EFFECT_POWER_BURN,
|
||||
SPELL_EFFECT_HEAL_MAX_HEALTH
|
||||
SPELL_EFFECT_HEAL
|
||||
);
|
||||
public const EFFECTS_ENCHANTMENT = array(
|
||||
SPELL_EFFECT_ENCHANT_ITEM, SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY, SPELL_EFFECT_ENCHANT_HELD_ITEM, SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
|
||||
);
|
||||
|
||||
public const AURAS_HEAL = array(
|
||||
SPELL_AURA_DUMMY, SPELL_AURA_PERIODIC_HEAL, SPELL_AURA_PERIODIC_HEALTH_FUNNEL, SPELL_AURA_SCHOOL_ABSORB, SPELL_AURA_MANA_SHIELD,
|
||||
SPELL_AURA_PERIODIC_DUMMY
|
||||
public const AURAS_SCALING_HEAL = array( // as per Unit::SpellHealingBonusDone() calls in TC (SPELL_AURA_SCHOOL_ABSORB + SPELL_AURA_MANA_SHIELD priest/mage cases are scripted)
|
||||
SPELL_AURA_PERIODIC_HEAL, SPELL_AURA_PERIODIC_LEECH, SPELL_AURA_OBS_MOD_HEALTH
|
||||
);
|
||||
public const AURAS_DAMAGE = array(
|
||||
SPELL_AURA_PERIODIC_DAMAGE, SPELL_AURA_DUMMY, SPELL_AURA_DAMAGE_SHIELD, SPELL_AURA_PERIODIC_LEECH, SPELL_AURA_PERIODIC_DAMAGE_PERCENT,
|
||||
SPELL_AURA_POWER_BURN, SPELL_AURA_PERIODIC_DUMMY
|
||||
public const AURAS_SCALING_DAMAGE = array( // as per Unit::SpellDamageBonusDone() calls in TC
|
||||
SPELL_AURA_PERIODIC_DAMAGE, SPELL_AURA_PERIODIC_LEECH, SPELL_AURA_DAMAGE_SHIELD, SPELL_AURA_PROC_TRIGGER_DAMAGE
|
||||
);
|
||||
public const AURAS_ITEM_CREATE = array(
|
||||
SPELL_AURA_CHANNEL_DEATH_ITEM
|
||||
@@ -75,7 +72,7 @@ class SpellList extends DBTypeList
|
||||
SPELL_AURA_TRANSFORM, SPELL_AURA_MOUNTED, SPELL_AURA_CHANGE_MODEL_FOR_ALL_HUMANOIDS, SPELL_AURA_X_RAY,
|
||||
SPELL_AURA_MOD_FAKE_INEBRIATE
|
||||
);
|
||||
public const AURAS_PERIODIC_SCALING = array(
|
||||
public const AURAS_PERIODIC_SCALING = array( // as per Unit::GetCastingTimeForBonus()
|
||||
SPELL_AURA_PERIODIC_DAMAGE, SPELL_AURA_PERIODIC_HEAL, SPELL_AURA_PERIODIC_LEECH
|
||||
);
|
||||
|
||||
@@ -230,56 +227,48 @@ class SpellList extends DBTypeList
|
||||
// <statistic> => [123, 'add']
|
||||
// <statistic> => <value> ... as from getStatGain()
|
||||
|
||||
$modXByStat = function (&$arr, $stat, $pts) use (&$mv)
|
||||
$modXByStat = function (array &$arr, int $srcStat, ?string $destStat, int $pts) : void
|
||||
{
|
||||
if ($mv == STAT_STRENGTH)
|
||||
$arr[$stat ?: 'str'] = [$pts / 100, 'percentOf', 'str'];
|
||||
else if ($mv == STAT_AGILITY)
|
||||
$arr[$stat ?: 'agi'] = [$pts / 100, 'percentOf', 'agi'];
|
||||
else if ($mv == STAT_STAMINA)
|
||||
$arr[$stat ?: 'sta'] = [$pts / 100, 'percentOf', 'sta'];
|
||||
else if ($mv == STAT_INTELLECT)
|
||||
$arr[$stat ?: 'int'] = [$pts / 100, 'percentOf', 'int'];
|
||||
else if ($mv == STAT_SPIRIT)
|
||||
$arr[$stat ?: 'spi'] = [$pts / 100, 'percentOf', 'spi'];
|
||||
match ($srcStat)
|
||||
{
|
||||
STAT_STRENGTH => $arr[$destStat ?: 'str'] = [$pts / 100, 'percentOf', 'str'],
|
||||
STAT_AGILITY => $arr[$destStat ?: 'agi'] = [$pts / 100, 'percentOf', 'agi'],
|
||||
STAT_STAMINA => $arr[$destStat ?: 'sta'] = [$pts / 100, 'percentOf', 'sta'],
|
||||
STAT_INTELLECT => $arr[$destStat ?: 'int'] = [$pts / 100, 'percentOf', 'int'],
|
||||
STAT_SPIRIT => $arr[$destStat ?: 'spi'] = [$pts / 100, 'percentOf', 'spi']
|
||||
};
|
||||
};
|
||||
|
||||
$modXBySchool = function (&$arr, $stat, $val, $mask = null) use (&$mv)
|
||||
$modXBySchool = function (array &$arr, int $srcStat, string $destStat, array|int $val) : void
|
||||
{
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_HOLY))
|
||||
$arr['hol'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'hol'.$stat];
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_FIRE))
|
||||
$arr['fir'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'fir'.$stat];
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_NATURE))
|
||||
$arr['nat'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'nat'.$stat];
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_FROST))
|
||||
$arr['fro'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'fro'.$stat];
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_SHADOW))
|
||||
$arr['sha'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'sha'.$stat];
|
||||
if (($mask ?: $mv) & (1 << SPELL_SCHOOL_ARCANE))
|
||||
$arr['arc'.$stat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'arc'.$stat];
|
||||
if ($srcStat & (1 << SPELL_SCHOOL_HOLY))
|
||||
$arr['hol'.$destStat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'hol'.$destStat];
|
||||
if ($srcStat & (1 << SPELL_SCHOOL_FIRE))
|
||||
$arr['fir'.$destStat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'fir'.$destStat];
|
||||
if ($srcStat & (1 << SPELL_SCHOOL_NATURE))
|
||||
$arr['nat'.$destStat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'nat'.$destStat];
|
||||
if ($srcStat & (1 << SPELL_SCHOOL_FROST))
|
||||
$arr['fro'.$destStat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'fro'.$destStat];
|
||||
if ($srcStat & (1 << SPELL_SCHOOL_SHADOW))
|
||||
$arr['sha'.$destStat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'sha'.$destStat];
|
||||
if ($srcStat & (1 << SPELL_SCHOOL_ARCANE))
|
||||
$arr['arc'.$destStat] = is_array($val) ? $val : [$val / 100, 'percentOf', 'arc'.$destStat];
|
||||
};
|
||||
|
||||
$jsonStat = function ($stat)
|
||||
$jsonStat = function (int $statId) : string
|
||||
{
|
||||
if ($stat == STAT_STRENGTH)
|
||||
return 'str';
|
||||
if ($stat == STAT_AGILITY)
|
||||
return 'agi';
|
||||
if ($stat == STAT_STAMINA)
|
||||
return 'sta';
|
||||
if ($stat == STAT_INTELLECT)
|
||||
return 'int';
|
||||
if ($stat == STAT_SPIRIT)
|
||||
return 'spi';
|
||||
return match ($statId)
|
||||
{
|
||||
STAT_STRENGTH => Stat::getJsonString(Stat::STRENGTH),
|
||||
STAT_AGILITY => Stat::getJsonString(Stat::AGILITY),
|
||||
STAT_STAMINA => Stat::getJsonString(Stat::STAMINA),
|
||||
STAT_INTELLECT => Stat::getJsonString(Stat::INTELLECT),
|
||||
STAT_SPIRIT => Stat::getJsonString(Stat::SPIRIT)
|
||||
};
|
||||
};
|
||||
|
||||
foreach ($this->iterate() as $id => $__)
|
||||
{
|
||||
// kept for reference - if (($this->getField('cuFlags') & SPELL_CU_TALENTSPELL) && $id != 20711)
|
||||
if (!($this->getField('attributes0') & SPELL_ATTR0_PASSIVE))
|
||||
continue;
|
||||
|
||||
// Shaman - Spirit Weapons (16268) (parry is normaly stored in g_statistics)
|
||||
// i should recurse into SPELL_EFFECT_LEARN_SPELL and apply SPELL_EFFECT_PARRY from there
|
||||
if ($id == 16268)
|
||||
@@ -288,6 +277,9 @@ class SpellList extends DBTypeList
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!($this->getField('attributes0') & SPELL_ATTR0_PASSIVE))
|
||||
continue;
|
||||
|
||||
for ($i = 1; $i < 4; $i++)
|
||||
{
|
||||
$pts = $this->calculateAmountForCurrent($i)[1];
|
||||
@@ -311,18 +303,18 @@ class SpellList extends DBTypeList
|
||||
if ($mv == (1 << SPELL_SCHOOL_NORMAL))
|
||||
$data[$id]['armor'] = [$pts / 100, 'percentOf', ['armor', 0]];
|
||||
else if ($mv)
|
||||
$modXBySchool($data[$id], 'res', $pts);
|
||||
$modXBySchool($data[$id], $mv, 'res', $pts);
|
||||
break;
|
||||
case SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT:
|
||||
// Armor only if explicitly specified
|
||||
if ($mv == (1 << SPELL_SCHOOL_NORMAL))
|
||||
$data[$id]['armor'] = [$pts / 100, 'percentOf', $jsonStat($mvB)];
|
||||
else if ($mv)
|
||||
$modXBySchool($data[$id], 'res', [$pts / 100, 'percentOf', $jsonStat($mvB)]);
|
||||
$modXBySchool($data[$id], $mv, 'res', [$pts / 100, 'percentOf', $jsonStat($mvB)]);
|
||||
break;
|
||||
case SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE:
|
||||
if ($mv > -1) // one stat
|
||||
$modXByStat($data[$id], null, $pts);
|
||||
$modXByStat($data[$id], $mv, null, $pts);
|
||||
else if ($mv < 0) // all stats
|
||||
for ($iMod = ITEM_MOD_AGILITY; $iMod <= ITEM_MOD_STAMINA; $iMod++)
|
||||
if ($idx = Stat::getIndexFrom(Stat::IDX_ITEM_MOD, $iMod))
|
||||
@@ -331,19 +323,19 @@ class SpellList extends DBTypeList
|
||||
break;
|
||||
case SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT:
|
||||
$mv = $mv ?: SPELL_MAGIC_SCHOOLS;
|
||||
$modXBySchool($data[$id], 'spldmg', [$pts / 100, 'percentOf', $jsonStat($mvB)]);
|
||||
$modXBySchool($data[$id], $mv, 'spldmg', [$pts / 100, 'percentOf', $jsonStat($mvB)]);
|
||||
break;
|
||||
case SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT:
|
||||
$modXByStat($data[$id], 'rgdatkpwr', $pts);
|
||||
$modXByStat($data[$id], $mv, 'rgdatkpwr', $pts);
|
||||
break;
|
||||
case SPELL_AURA_MOD_ATTACK_POWER_OF_STAT_PERCENT:
|
||||
$modXByStat($data[$id], 'mleatkpwr', $pts);
|
||||
$modXByStat($data[$id], $mv, 'mleatkpwr', $pts);
|
||||
break;
|
||||
case SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT:
|
||||
$modXByStat($data[$id], 'splheal', $pts);
|
||||
$modXByStat($data[$id], $mv, 'splheal', $pts);
|
||||
break;
|
||||
case SPELL_AURA_MOD_MANA_REGEN_FROM_STAT:
|
||||
$modXByStat($data[$id], 'manargn', $pts);
|
||||
$modXByStat($data[$id], $mv, 'manargn', $pts);
|
||||
break;
|
||||
case SPELL_AURA_MOD_MANA_REGEN_INTERRUPT:
|
||||
$data[$id]['icmanargn'] = [$pts / 100, 'percentOf', 'oocmanargn'];
|
||||
@@ -351,7 +343,7 @@ class SpellList extends DBTypeList
|
||||
case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
|
||||
case SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL:
|
||||
$mv = $mv ?: SPELL_MAGIC_SCHOOLS;
|
||||
$modXBySchool($data[$id], 'splcritstrkpct', [$pts, 'add']);
|
||||
$modXBySchool($data[$id], $mv, 'splcritstrkpct', [$pts, 'add']);
|
||||
if (($mv & SPELL_MAGIC_SCHOOLS) == SPELL_MAGIC_SCHOOLS)
|
||||
$data[$id]['splcritstrkpct'] = [$pts, 'add'];
|
||||
break;
|
||||
@@ -392,7 +384,7 @@ class SpellList extends DBTypeList
|
||||
$data[$id]['health'] = [$pts / 100, 'percentOf', 'health'];
|
||||
break;
|
||||
case SPELL_AURA_MOD_BASE_HEALTH_PCT: // only Tauren - Endurance (20550) ... if you are looking for something elegant, look away!
|
||||
$data[$id]['health'] = [$pts / 100, 'functionOf', '$function(p) { return g_statistics.combo[p.classs][p.level][5]; }'];
|
||||
$data[$id]['health'] = [$pts / 100, 'functionOf', '$(x) => g_statistics.combo[x.classs][x.level][5]'];
|
||||
break;
|
||||
case SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT:
|
||||
$data[$id]['block'] = [$pts / 100, 'percentOf', 'block'];
|
||||
@@ -404,7 +396,7 @@ class SpellList extends DBTypeList
|
||||
break;
|
||||
case SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER:
|
||||
$mv = $mv ?: SPELL_MAGIC_SCHOOLS;
|
||||
$modXBySchool($data[$id], 'spldmg', [$pts / 100, 'percentOf', 'mleatkpwr']);
|
||||
$modXBySchool($data[$id], $mv, 'spldmg', [$pts / 100, 'percentOf', 'mleatkpwr']);
|
||||
break;
|
||||
case SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER:
|
||||
$data[$id]['splheal'] = [$pts / 100, 'percentOf', 'mleatkpwr'];
|
||||
@@ -775,22 +767,22 @@ class SpellList extends DBTypeList
|
||||
return $this->curTpl['attributes1'] & (SPELL_ATTR1_CHANNELED_1 | SPELL_ATTR1_CHANNELED_2);
|
||||
}
|
||||
|
||||
public function isHealingSpell() : bool
|
||||
public function isScalableHealingSpell() : bool
|
||||
{
|
||||
for ($i = 1; $i < 4; $i++)
|
||||
if (!in_array($this->curTpl['effect'.$i.'Id'], SpellList::EFFECTS_HEAL) && !in_array($this->curTpl['effect'.$i.'AuraId'], SpellList::AURAS_HEAL))
|
||||
return false;
|
||||
if (in_array($this->curTpl['effect'.$i.'Id'], SpellList::EFFECTS_SCALING_HEAL) || in_array($this->curTpl['effect'.$i.'AuraId'], SpellList::AURAS_SCALING_HEAL))
|
||||
return true;
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isDamagingSpell() : bool
|
||||
public function isScalableDamagingSpell() : bool
|
||||
{
|
||||
for ($i = 1; $i < 4; $i++)
|
||||
if (!in_array($this->curTpl['effect'.$i.'Id'], SpellList::EFFECTS_DAMAGE) && !in_array($this->curTpl['effect'.$i.'AuraId'], SpellList::AURAS_DAMAGE))
|
||||
return false;
|
||||
if (in_array($this->curTpl['effect'.$i.'Id'], SpellList::EFFECTS_SCALING_DAMAGE) || in_array($this->curTpl['effect'.$i.'AuraId'], SpellList::AURAS_SCALING_DAMAGE))
|
||||
return true;
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function periodicEffectsMask() : int
|
||||
@@ -910,7 +902,11 @@ class SpellList extends DBTypeList
|
||||
$formula = preg_replace('/(\+|-|\*|\/)(\+|-|\*|\/)/i', '\1 \2', $formula);
|
||||
|
||||
// there should not be any letters without a leading $
|
||||
return eval('return '.$formula.';');
|
||||
try { $formula = eval('return '.$formula.';'); }
|
||||
// but there can be if we are non-interactive
|
||||
catch (\Throwable $e) { }
|
||||
|
||||
return $formula;
|
||||
}
|
||||
|
||||
// description-, buff-parsing component
|
||||
@@ -1840,8 +1836,13 @@ class SpellList extends DBTypeList
|
||||
|
||||
// get reagents
|
||||
$reagents = $this->getReagentsForCurrent();
|
||||
foreach ($reagents as &$r)
|
||||
$r[2] = ItemList::getName($r[0]);
|
||||
foreach ($reagents as $k => $r)
|
||||
{
|
||||
if ($item = $this->relItems->getEntry($r[0]))
|
||||
$reagents[$k] += [2 => new LocString($item), 3 => true];
|
||||
else
|
||||
$reagents[$k] += [2 => 'Item #'.$r[0], 3 => false];
|
||||
}
|
||||
|
||||
$reagents = array_reverse($reagents);
|
||||
|
||||
@@ -1941,11 +1942,11 @@ class SpellList extends DBTypeList
|
||||
if ($reagents)
|
||||
{
|
||||
$_ = Lang::spell('reagents').':<br/><div class="indent q1">';
|
||||
while ($reagent = array_pop($reagents))
|
||||
while ([$iId, $qty, $text, $exists] = array_pop($reagents))
|
||||
{
|
||||
$_ .= '<a href="?item='.$reagent[0].'">'.$reagent[2].'</a>';
|
||||
if ($reagent[1] > 1)
|
||||
$_ .= ' ('.$reagent[1].')';
|
||||
$_ .= $exists ? '<a href="?item='.$iId.'">'.$text.'</a>' : $text;
|
||||
if ($qty > 1)
|
||||
$_ .= ' ('.$qty.')';
|
||||
|
||||
$_ .= empty($reagents) ? '<br />' : ', ';
|
||||
}
|
||||
@@ -2149,8 +2150,11 @@ class SpellList extends DBTypeList
|
||||
{
|
||||
$data[Type::SPELL][$id] = array(
|
||||
'icon' => $this->curTpl['iconStringAlt'] ?: $this->curTpl['iconString'],
|
||||
'name' => $this->getField('name', true),
|
||||
'name' => $this->getField('name', true)
|
||||
);
|
||||
|
||||
if (($_ = $this->curTpl['typeCat']) && in_array($_, [-5, -6, 9, 11]))
|
||||
$data[Type::SPELL][$id]['completion_category'] = $_;
|
||||
}
|
||||
|
||||
if ($addMask & GLOBALINFO_EXTRA)
|
||||
@@ -2523,10 +2527,10 @@ class SpellListFilter extends Filter
|
||||
'na' => [parent::V_REGEX, parent::PATTERN_NAME, false], // name / text - only printable chars, no delimiter
|
||||
'ex' => [parent::V_EQUAL, 'on', false], // extended name search
|
||||
'ma' => [parent::V_EQUAL, 1, false], // match any / all filter
|
||||
'minle' => [parent::V_RANGE, [1, 99], false], // spell level min
|
||||
'maxle' => [parent::V_RANGE, [1, 99], false], // spell level max
|
||||
'minrs' => [parent::V_RANGE, [1, 999], false], // required skill level min
|
||||
'maxrs' => [parent::V_RANGE, [1, 999], false], // required skill level max
|
||||
'minle' => [parent::V_RANGE, [0, 99], false], // spell level min
|
||||
'maxle' => [parent::V_RANGE, [0, 99], false], // spell level max
|
||||
'minrs' => [parent::V_RANGE, [0, 999], false], // required skill level min
|
||||
'maxrs' => [parent::V_RANGE, [0, 999], false], // required skill level max
|
||||
'ra' => [parent::V_LIST, [[1, 8], 10, 11], false], // races
|
||||
'cl' => [parent::V_CALLBACK, 'cbClasses', true ], // classes
|
||||
'gl' => [parent::V_CALLBACK, 'cbGlyphs', true ], // glyph type
|
||||
|
||||
@@ -91,7 +91,7 @@ class WorldEventList extends DBTypeList
|
||||
if ($rec < 0 || $date['lastDate'] < time())
|
||||
return true;
|
||||
|
||||
$nIntervals = ceil((time() - $start) / $rec);
|
||||
$nIntervals = (int)ceil((time() - $end) / $rec);
|
||||
|
||||
$start += $nIntervals * $rec;
|
||||
$end += $nIntervals * $rec;
|
||||
@@ -157,9 +157,9 @@ class WorldEventList extends DBTypeList
|
||||
|
||||
// use string-placeholder for dates
|
||||
// start
|
||||
$x .= Lang::event('start').Lang::main('colon').'%s<br />';
|
||||
$x .= Lang::event('start').'%s<br />';
|
||||
// end
|
||||
$x .= Lang::event('end').Lang::main('colon').'%s';
|
||||
$x .= Lang::event('end').'%s';
|
||||
|
||||
$x .= '</td></tr></table>';
|
||||
|
||||
|
||||
@@ -41,6 +41,8 @@ define('CACHE_TYPE_PAGE', 1);
|
||||
define('CACHE_TYPE_TOOLTIP', 2);
|
||||
define('CACHE_TYPE_SEARCH', 3);
|
||||
define('CACHE_TYPE_XML', 4); // only used by items
|
||||
define('CACHE_TYPE_LIST_PAGE', 5);
|
||||
define('CACHE_TYPE_DETAIL_PAGE', 6);
|
||||
|
||||
define('CACHE_MODE_FILECACHE', 0x1);
|
||||
define('CACHE_MODE_MEMCACHED', 0x2);
|
||||
@@ -372,9 +374,9 @@ define('QUEST_CU_PART_OF_SERIES', 0x0200);
|
||||
|
||||
define('PROFILER_CU_PUBLISHED', 0x01);
|
||||
define('PROFILER_CU_PINNED', 0x02);
|
||||
define('PROFILER_CU_DELETED', 0x04);
|
||||
define('PROFILER_CU_PROFILE', 0x08);
|
||||
define('PROFILER_CU_NEEDS_RESYNC', 0x10);
|
||||
// define('PROFILER_CU_DELETED', 0x04); // migrated to separate db cols
|
||||
// define('PROFILER_CU_PROFILE', 0x08);
|
||||
// define('PROFILER_CU_NEEDS_RESYNC', 0x10);
|
||||
|
||||
define('GUIDE_CU_NO_QUICKFACTS', 0x100); // merge with CC_FLAG_*
|
||||
define('GUIDE_CU_NO_RATING', 0x200);
|
||||
@@ -492,6 +494,15 @@ define('ITEM_MOD_SPELL_POWER', 45);
|
||||
define('ITEM_MOD_HEALTH_REGEN', 46);
|
||||
define('ITEM_MOD_SPELL_PENETRATION', 47);
|
||||
define('ITEM_MOD_BLOCK_VALUE', 48);
|
||||
// unknown by 335a client but still used by several item_templates
|
||||
// define('ITEM_MOD_MASTERY_RATING', 49);
|
||||
// define('ITEM_MOD_EXTRA_ARMOR', 50);
|
||||
// define('ITEM_MOD_FIRE_RESISTANCE', 51);
|
||||
// define('ITEM_MOD_FROST_RESISTANCE', 52);
|
||||
// define('ITEM_MOD_HOLY_RESISTANCE', 53);
|
||||
// define('ITEM_MOD_SHADOW_RESISTANCE', 54);
|
||||
// define('ITEM_MOD_NATURE_RESISTANCE', 55);
|
||||
// define('ITEM_MOD_ARCANE_RESISTANCE', 56);
|
||||
|
||||
// Combat Ratings
|
||||
define('CR_WEAPON_SKILL', 0);
|
||||
@@ -598,6 +609,7 @@ define('TEAM_NEUTRAL', 2);
|
||||
// Lock Types
|
||||
define('LOCK_TYPE_ITEM', 1);
|
||||
define('LOCK_TYPE_SKILL', 2);
|
||||
define('LOCK_TYPE_SPELL', 3);
|
||||
|
||||
// Lock-Properties (also categorizes GOs)
|
||||
define('LOCK_PROPERTY_FOOTLOCKER', 1);
|
||||
@@ -669,6 +681,7 @@ define('NPC_FLAG_STABLE_MASTER', 0x00400000);
|
||||
define('NPC_FLAG_GUILD_BANK', 0x00800000);
|
||||
define('NPC_FLAG_SPELLCLICK', 0x01000000);
|
||||
define('NPC_FLAG_MAILBOX', 0x04000000);
|
||||
define('NPC_FLAG_VALIDATE', 0x05FFFFF3);
|
||||
|
||||
define('CREATURE_FLAG_EXTRA_INSTANCE_BIND', 0x00000001); // creature kill binds instance to killer and killer's group
|
||||
define('CREATURE_FLAG_EXTRA_CIVILIAN', 0x00000002); // creature does not aggro (ignore faction/reputation hostility)
|
||||
@@ -728,6 +741,7 @@ define('UNIT_FLAG_UNK_28', 0x10000000); // (PreventKneelingW
|
||||
define('UNIT_FLAG_UNK_29', 0x20000000); // Used in Feign Death spell or NPC will play dead. (PreventEmotes)
|
||||
define('UNIT_FLAG_SHEATHE', 0x40000000); //
|
||||
define('UNIT_FLAG_UNK_31', 0x80000000); //
|
||||
define('UNIT_FLAG_VALIDATE', 0x7FFFFFFF); //
|
||||
|
||||
define('UNIT_FLAG2_FEIGN_DEATH', 0x00000001); //
|
||||
define('UNIT_FLAG2_UNK1', 0x00000002); // Hide unit model (show only player equip)
|
||||
@@ -747,6 +761,7 @@ define('UNIT_FLAG2_DISABLE_TURN', 0x00008000); //
|
||||
define('UNIT_FLAG2_UNK2', 0x00010000); //
|
||||
define('UNIT_FLAG2_PLAY_DEATH_ANIM', 0x00020000); // Plays special death animation upon death
|
||||
define('UNIT_FLAG2_ALLOW_CHEAT_SPELLS', 0x00040000); // allows casting spells with AttributesEx7 & SPELL_ATTR7_IS_CHEAT_SPELL
|
||||
define('UNIT_FLAG2_VALIDATE', 0x0006FDFF); //
|
||||
|
||||
// UNIT_FIELD_BYTES_1 - idx 0 (UnitStandStateType)
|
||||
define('UNIT_STAND_STATE_STAND', 0);
|
||||
@@ -782,6 +797,7 @@ define('UNIT_DYNFLAG_SPECIALINFO', 0x10); //
|
||||
define('UNIT_DYNFLAG_DEAD', 0x20); // Makes the creature appear dead (this DOES NOT make the creature's name grey or not attack players).
|
||||
define('UNIT_DYNFLAG_REFER_A_FRIEND', 0x40); //
|
||||
define('UNIT_DYNFLAG_TAPPED_BY_ALL_THREAT_LIST', 0x80); // Lua_UnitIsTappedByAllThreatList
|
||||
define('UNIT_DYNFLAG_VALIDATE', 0xFF); //
|
||||
|
||||
define('PET_TALENT_TYPE_FEROCITY', 0);
|
||||
define('PET_TALENT_TYPE_TENACITY', 1);
|
||||
@@ -851,9 +867,11 @@ define('GO_FLAG_INTERACT_COND', 0x0004); // Untargetable, can
|
||||
define('GO_FLAG_TRANSPORT', 0x0008); // Gameobject can transport (boat, elevator, car)
|
||||
define('GO_FLAG_NOT_SELECTABLE', 0x0010); // Not selectable (Not even in GM-mode)
|
||||
define('GO_FLAG_NODESPAWN', 0x0020); // Never despawns. Typical for gameobjects with on/off state (doors for example)
|
||||
define('GO_FLAG_TRIGGERED', 0x0040); // typically, summoned objects. Triggered by spell or other events
|
||||
define('GO_FLAG_AI_OBSTACLE', 0x0040); // makes the client register the object in something called AIObstacleMgr, unknown what it does
|
||||
define('GO_FLAG_FREEZE_ANIMATION',0x0080); //
|
||||
define('GO_FLAG_DAMAGED', 0x0200); // Gameobject has been siege damaged
|
||||
define('GO_FLAG_DESTROYED', 0x0400); // Gameobject has been destroyed
|
||||
define('GO_FLAG_VALIDATE', 0x06FF); //
|
||||
|
||||
define('GO_STATE_ACTIVE', 0); // show in world as used and not reset (closed door open)
|
||||
define('GO_STATE_READY', 1); // show in world as ready (closed door close)
|
||||
|
||||
@@ -8,20 +8,31 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
enum ChrRace : int
|
||||
{
|
||||
case HUMAN = 1;
|
||||
case ORC = 2;
|
||||
case DWARF = 3;
|
||||
case NIGHTELF = 4;
|
||||
case UNDEAD = 5;
|
||||
case TAUREN = 6;
|
||||
case GNOME = 7;
|
||||
case TROLL = 8;
|
||||
case BLOODELF = 10;
|
||||
case DRAENEI = 11;
|
||||
case HUMAN = 1;
|
||||
case ORC = 2;
|
||||
case DWARF = 3;
|
||||
case NIGHTELF = 4;
|
||||
case UNDEAD = 5;
|
||||
case TAUREN = 6;
|
||||
case GNOME = 7;
|
||||
case TROLL = 8;
|
||||
case GOBLIN = 9;
|
||||
case BLOODELF = 10;
|
||||
case DRAENEI = 11;
|
||||
case FEL_ORC = 12;
|
||||
case NAGA = 13;
|
||||
case BROKEN = 14;
|
||||
case SKELETON = 15;
|
||||
case VRYKUL = 16;
|
||||
case TUSKARR = 17;
|
||||
case FOREST_TROLL = 18;
|
||||
case TAUNKA = 19;
|
||||
case NORTHREND_SKELETON = 20;
|
||||
case ICE_TROLL = 21;
|
||||
|
||||
public const MASK_ALLIANCE = 0x44D;
|
||||
public const MASK_HORDE = 0x2B2;
|
||||
public const MASK_ALL = 0x6FF;
|
||||
public const MASK_ALLIANCE = 0x44D; // HUMAN, DWARF, NIGHTELF, GNOME, DRAENEI
|
||||
public const MASK_HORDE = 0x2B2; // ORC, UNDEAD, TAUREN, TROLL, BLOODELF
|
||||
public const MASK_ALL = self::MASK_ALLIANCE | self::MASK_HORDE;
|
||||
|
||||
public function matches(int $raceMask) : bool
|
||||
{
|
||||
@@ -80,7 +91,8 @@ enum ChrRace : int
|
||||
self::GNOME => 'gnome',
|
||||
self::TROLL => 'troll',
|
||||
self::BLOODELF => 'bloodelf',
|
||||
self::DRAENEI => 'draenei'
|
||||
self::DRAENEI => 'draenei',
|
||||
default => ''
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user