mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Compare commits
128 Commits
v2.0
...
10ef33f709
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10ef33f709 | ||
|
|
ae1b6c59b1 | ||
|
|
b764200c2a | ||
|
|
c0454917ac | ||
|
|
b3e215cc40 | ||
|
|
d4694cd2db | ||
|
|
a5051c9bf5 | ||
|
|
be3701df91 | ||
|
|
9b905883df | ||
|
|
9db3e766da | ||
|
|
7f29c1d4b7 | ||
|
|
57665aaa9e | ||
|
|
4cb544182d | ||
|
|
a2b87da285 | ||
|
|
03bab92cb8 | ||
|
|
103287f91b | ||
|
|
82f36fd342 | ||
|
|
f5654ae21f | ||
|
|
1fe3690244 | ||
|
|
45417122c2 | ||
|
|
7cf5dded98 | ||
|
|
31f51276b2 | ||
|
|
643c3c2a83 | ||
|
|
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
|
||||
|
||||
@@ -112,7 +112,7 @@ class AccountBaseResponse extends TemplateResponse
|
||||
|
||||
// Username
|
||||
$this->curName = User::$username;
|
||||
$this->renameCD = Util::formatTime(Cfg::get('ACC_RENAME_DECAY') * 1000);
|
||||
$this->renameCD = DateTime::formatTimeElapsedFloat(Cfg::get('ACC_RENAME_DECAY') * 1000);
|
||||
if ($user['renameCooldown'] > time())
|
||||
{
|
||||
$locCode = implode('_', str_split(Lang::getLocale()->json(), 2)); // ._.
|
||||
|
||||
@@ -76,7 +76,7 @@ class AccountforgotpasswordResponse extends TemplateResponse
|
||||
|
||||
// on cooldown pretend we dont know the email address
|
||||
if ($timeout && $timeout > time())
|
||||
return Cfg::get('DEBUG') ? 'resend on cooldown: '.Util::formatTimeDiff($timeout).' remaining' : Lang::account('inputbox', 'error', 'emailNotFound');
|
||||
return Cfg::get('DEBUG') ? 'resend on cooldown: '.DateTime::formatTimeElapsed($timeout * 1000).' remaining' : Lang::account('inputbox', 'error', 'emailNotFound');
|
||||
|
||||
// pretend recovery started
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE `email` = ?', $this->_post['email']))
|
||||
|
||||
@@ -75,7 +75,7 @@ class AccountforgotusernameResponse extends TemplateResponse
|
||||
|
||||
// on cooldown pretend we dont know the email address
|
||||
if ($timeout && $timeout > time())
|
||||
return Cfg::get('DEBUG') ? 'resend on cooldown: '.Util::formatTimeDiff($timeout).' remaining' : Lang::account('inputbox', 'error', 'emailNotFound');
|
||||
return Cfg::get('DEBUG') ? 'resend on cooldown: '.DateTime::formatTimeElapsed($timeout * 1000).' remaining' : Lang::account('inputbox', 'error', 'emailNotFound');
|
||||
|
||||
// pretend recovery started
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_account WHERE `email` = ?', $this->_post['email']))
|
||||
|
||||
@@ -73,7 +73,7 @@ class AccountResendResponse extends TemplateResponse
|
||||
|
||||
// on cooldown pretend we dont know the email address
|
||||
if ($timeout && $timeout > time())
|
||||
return Cfg::get('DEBUG') ? 'resend on cooldown: '.Util::formatTimeDiff($timeout).' remaining' : Lang::account('inputbox', 'error', 'emailNotFound');
|
||||
return Cfg::get('DEBUG') ? 'resend on cooldown: '.DateTime::formatTimeElapsed($timeout * 1000).' remaining' : Lang::account('inputbox', 'error', 'emailNotFound');
|
||||
|
||||
// check email and account status
|
||||
if ($token = DB::Aowow()->selectCell('SELECT `token` FROM ?_account WHERE `email` = ? AND `status` = ?d', $this->_post['email'], ACC_STATUS_NEW))
|
||||
|
||||
@@ -25,7 +25,7 @@ class AccountresetpasswordResponse extends TemplateResponse
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']],
|
||||
'next' => ['filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FLAG_STRIP_AOWOW ]
|
||||
'next' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[[:print:]]+$/' ]]
|
||||
);
|
||||
protected array $expectedPOST = array(
|
||||
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']],
|
||||
|
||||
@@ -28,7 +28,7 @@ class AccountSigninResponse extends TemplateResponse
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'key' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[a-zA-Z0-9]{40}$/']],
|
||||
'next' => ['filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FLAG_STRIP_AOWOW ]
|
||||
'next' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[[:print:]]+$/'] ]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
@@ -99,7 +99,7 @@ class AccountSigninResponse extends TemplateResponse
|
||||
// AUTH_BANNED => Lang::account('accBanned'); // ToDo: should this return an error? the actual account functionality should be blocked elsewhere
|
||||
AUTH_WRONGUSER => Lang::account('userNotFound'),
|
||||
AUTH_WRONGPASS => Lang::account('wrongPass'),
|
||||
AUTH_IPBANNED => Lang::account('inputbox', 'error', 'loginExceeded', [Util::formatTime(Cfg::get('ACC_FAILED_AUTH_BLOCK') * 1000)]),
|
||||
AUTH_IPBANNED => Lang::account('inputbox', 'error', 'loginExceeded', [DateTime::formatTimeElapsedFloat(Cfg::get('ACC_FAILED_AUTH_BLOCK') * 1000)]),
|
||||
AUTH_INTERNAL_ERR => Lang::main('intError'),
|
||||
default => Lang::main('intError')
|
||||
};
|
||||
|
||||
@@ -11,8 +11,8 @@ class AccountSignoutResponse extends TextResponse
|
||||
use TrGetNext;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'next' => ['filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH],
|
||||
'global' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet'] ]
|
||||
'next' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[[:print:]]+$/']],
|
||||
'global' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet'] ]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
|
||||
@@ -26,7 +26,7 @@ class AccountSignupResponse extends TemplateResponse
|
||||
);
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'next' => ['filter' => FILTER_SANITIZE_URL, 'flags' => FILTER_FLAG_STRIP_AOWOW]
|
||||
'next' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[[:print:]]+$/']]
|
||||
);
|
||||
|
||||
private bool $success = false;
|
||||
@@ -112,7 +112,7 @@ class AccountSignupResponse extends TemplateResponse
|
||||
if (DB::Aowow()->selectRow('SELECT 1 FROM ?_account_bannedips WHERE `type` = ?d AND `ip` = ? AND `count` >= ?d AND `unbanDate` >= UNIX_TIMESTAMP()', IP_BAN_TYPE_REGISTRATION_ATTEMPT, User::$ip, Cfg::get('ACC_FAILED_AUTH_COUNT')))
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_account_bannedips SET `count` = `count` + 1, `unbanDate` = UNIX_TIMESTAMP() + ?d WHERE `ip` = ? AND `type` = ?d', Cfg::get('ACC_FAILED_AUTH_BLOCK'), User::$ip, IP_BAN_TYPE_REGISTRATION_ATTEMPT);
|
||||
return Lang::account('inputbox', 'error', 'signupExceeded', [Util::formatTime(Cfg::get('ACC_FAILED_AUTH_BLOCK') * 1000)]);
|
||||
return Lang::account('inputbox', 'error', 'signupExceeded', [DateTime::formatTimeElapsedFloat(Cfg::get('ACC_FAILED_AUTH_BLOCK') * 1000)]);
|
||||
}
|
||||
|
||||
// username / email taken
|
||||
|
||||
@@ -53,7 +53,7 @@ class AccountUpdateemailResponse extends TextResponse
|
||||
|
||||
$status = DB::Aowow()->selectCell('SELECT `status` FROM ?_account WHERE `statusTimer` > UNIX_TIMESTAMP() AND `id` = ?d', User::$id);
|
||||
if ($status != ACC_STATUS_NONE && $status != ACC_STATUS_CHANGE_EMAIL)
|
||||
return Lang::account('isRecovering', [Util::formatTime(Cfg::get('ACC_RECOVERY_DECAY') * 1000)]);
|
||||
return Lang::account('inputbox', 'error', 'isRecovering', [DateTime::formatTimeElapsedFloat(Cfg::get('ACC_RECOVERY_DECAY') * 1000)]);
|
||||
|
||||
$oldEmail = DB::Aowow()->selectCell('SELECT `email` FROM ?_account WHERE `id` = ?d', User::$id);
|
||||
if ($this->_post['newemail'] == $oldEmail)
|
||||
|
||||
@@ -55,7 +55,7 @@ class AccountUpdatepasswordResponse extends TextResponse
|
||||
|
||||
$userData = DB::Aowow()->selectRow('SELECT `status`, `passHash`, `statusTimer` FROM ?_account WHERE `id` = ?d', User::$id);
|
||||
if ($userData['status'] != ACC_STATUS_NONE && $userData['status'] != ACC_STATUS_CHANGE_PASS && $userData['statusTimer'] > time())
|
||||
return Lang::account('isRecovering', [Util::formatTime(Cfg::get('ACC_RECOVERY_DECAY') * 1000)]);
|
||||
return Lang::account('inputbox', 'error', 'isRecovering', [DateTime::formatTimeElapsedFloat(Cfg::get('ACC_RECOVERY_DECAY') * 1000)]);
|
||||
|
||||
if (!User::verifyCrypt($this->_post['currentPassword'], $userData['passHash']))
|
||||
return Lang::account('wrongPass');
|
||||
|
||||
@@ -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';
|
||||
@@ -105,7 +105,7 @@ class AreatriggerBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
// tab: conditions
|
||||
$cnd = new Conditions();
|
||||
$cnd->getBySourceEntry($this->typeId, Conditions::SRC_AREATRIGGER_CLIENT)->prepare();
|
||||
$cnd->getBySource(Conditions::SRC_AREATRIGGER_CLIENT, entry: $this->typeId)->prepare();
|
||||
if ($tab = $cnd->toListviewTab())
|
||||
{
|
||||
$this->extendGlobalData($cnd->getJsGlobals());
|
||||
|
||||
@@ -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 = array_pop($subject);
|
||||
$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;
|
||||
|
||||
@@ -9,15 +9,15 @@ if (!defined('AOWOW_REVISION'))
|
||||
class ContactusBaseResponse extends TextResponse
|
||||
{
|
||||
protected array $expectedPOST = array(
|
||||
'mode' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'reason' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'ua' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']],
|
||||
'appname' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']],
|
||||
'page' => ['filter' => FILTER_SANITIZE_URL ],
|
||||
'desc' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob']],
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'relatedurl' => ['filter' => FILTER_SANITIZE_URL ],
|
||||
'email' => ['filter' => FILTER_SANITIZE_EMAIL ]
|
||||
'mode' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'reason' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'ua' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'appname' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine'] ],
|
||||
'page' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[[:print:]]+$/']],
|
||||
'desc' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ],
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'relatedurl' => ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => '/^[[:print:]]+$/']],
|
||||
'email' => ['filter' => FILTER_SANITIZE_EMAIL ]
|
||||
);
|
||||
|
||||
/* responses
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -110,9 +117,9 @@ class CurrencyBaseResponse extends TemplateResponse implements ICache
|
||||
if ($this->typeId != CURRENCY_HONOR_POINTS && $this->typeId != CURRENCY_ARENA_POINTS)
|
||||
{
|
||||
// tabs: this currency is contained in..
|
||||
$lootTabs = new Loot();
|
||||
$lootTabs = new LootByItem($_relItemId);
|
||||
|
||||
if ($lootTabs->getByItem($_relItemId))
|
||||
if ($lootTabs->getByItem())
|
||||
{
|
||||
$this->extendGlobalData($lootTabs->jsGlobals);
|
||||
|
||||
@@ -121,6 +128,15 @@ class CurrencyBaseResponse extends TemplateResponse implements ICache
|
||||
if ($template == 'npc' || $template == 'object')
|
||||
$this->addDataLoader('zones');
|
||||
|
||||
if ($template != 'quest')
|
||||
{
|
||||
foreach ($tabData['data'] as &$row)
|
||||
if (!empty($row['stack']))
|
||||
$row['currency'] = [[$this->typeId, $row['stack'][0]]];
|
||||
|
||||
$tabData['extraCols'][] = '$Listview.extraCols.currency';
|
||||
}
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, $template));
|
||||
}
|
||||
}
|
||||
@@ -182,7 +198,7 @@ class CurrencyBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
// tab: created by (spell) [for items its handled in Loot::getByContainer()]
|
||||
// tab: created by (spell) [for items its handled in LootByItem]
|
||||
if ($this->typeId == CURRENCY_HONOR_POINTS)
|
||||
{
|
||||
$createdBy = new SpellList(array(['effect1Id', SPELL_EFFECT_ADD_HONOR], ['effect2Id', SPELL_EFFECT_ADD_HONOR], ['effect3Id', SPELL_EFFECT_ADD_HONOR], 'OR'));
|
||||
|
||||
@@ -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');
|
||||
@@ -320,7 +327,7 @@ class EventBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
// interval
|
||||
if ($rec > 0)
|
||||
$infobox[] = Lang::event('interval').Util::formatTime($rec * 1000);
|
||||
$infobox[] = Lang::event('interval').DateTime::formatTimeElapsed($rec * 1000);
|
||||
|
||||
// in progress
|
||||
if ($start < time() && $end > time())
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -21,8 +21,9 @@ class GotocommentBaseResponse extends TextResponse
|
||||
return;
|
||||
}
|
||||
|
||||
// type <> 0 AND typeId <> 0 AND replyTo = 0 for comments
|
||||
$comment = DB::Aowow()->selectRow('SELECT `id`, `type`, `typeId` FROM ?_comments WHERE `replyTo` = 0 AND `id` = ?d', $this->_get['id']);
|
||||
// the reputation-history listview only creates go-to-comment links. So either upvoting replies does not grant reputation, or.... bug.?
|
||||
|
||||
$comment = DB::Aowow()->selectRow('SELECT IFNULL(c2.`id`, c1.`id`) AS "id", IFNULL(c2.`type`, c1.`type`) AS "type", IFNULL(c2.`typeId`, c1.`typeId`) AS "typeId" FROM ?_comments c1 LEFT JOIN ?_comments c2 ON c1.`replyTo` = c2.`id` WHERE c1.`id` = ?d', $this->_get['id']);
|
||||
if (!$comment)
|
||||
{
|
||||
trigger_error('GotocommentBaseResponse - comment #'.$this->_get['id'].' not found', E_USER_ERROR);
|
||||
@@ -36,6 +37,8 @@ class GotocommentBaseResponse extends TextResponse
|
||||
}
|
||||
|
||||
$this->redirectTo = sprintf('?%s=%d#comments:id=%d', Type::getFileString($comment['type']), $comment['typeId'], $comment['id']);
|
||||
if ($comment['id'] != $this->_get['id']) // i am reply
|
||||
$this->redirectTo .= ':reply='.$this->_get['id'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -79,20 +79,21 @@ class GuideChangelogResponse extends TemplateResponse
|
||||
|
||||
$buff = '<ul>';
|
||||
$inp = fn($rev) => User::isInGroup(U_GROUP_STAFF) && false ? ($rev !== null ? '<input name="a" value="'.$rev.'" type="radio"/><input name="b" value="'.$rev.'" type="radio"/><b>' : '<b style="margin-left:38px;">') : '';
|
||||
$now = new DateTime();
|
||||
|
||||
$logEntries = DB::Aowow()->select('SELECT a.`username` AS `name`, gcl.`date`, gcl.`status`, gcl.`msg`, gcl.`rev` FROM ?_guides_changelog gcl JOIN ?_account a ON a.`id` = gcl.`userId` WHERE gcl.`id` = ?d ORDER BY gcl.`date` DESC', $this->_get['id']);
|
||||
foreach ($logEntries as $log)
|
||||
{
|
||||
if ($log['status'] != GuideMgr::STATUS_NONE)
|
||||
$buff .= '<li class="guide-changelog-status-change">'.$inp($log['rev']).'<b>'.Lang::guide('clStatusSet', [Lang::guide('status', $log['status'])]).'</b>'.Util::formatTimeDiff($log['date'])."</li>\n";
|
||||
$buff .= '<li class="guide-changelog-status-change">'.$inp($log['rev']).'<b>'.Lang::guide('clStatusSet', [Lang::guide('status', $log['status'])]).'</b>'.$now->formatDate($log['date'], true)."</li>\n";
|
||||
else if ($log['msg'])
|
||||
$buff .= '<li>'.$inp($log['rev']).'<b>'.Util::formatTimeDiff($log['date']).Lang::main('colon').'</b>'.$log['msg'].' <i class="q0">'.Lang::main('byUser', [$log['name'], 'style="text-decoration:underline"'])."</i></li>\n";
|
||||
$buff .= '<li>'.$inp($log['rev']).'<b>'.$now->formatDate($log['date'], true).Lang::main('colon').'</b>'.$log['msg'].' <i class="q0">'.Lang::main('byUser', [$log['name'], 'style="text-decoration:underline"'])."</i></li>\n";
|
||||
else
|
||||
$buff .= '<li class="guide-changelog-minor-edit">'.$inp($log['rev']).'<b>'.Util::formatTimeDiff($log['date']).Lang::main('colon').'</b><i>'.Lang::guide('clMinorEdit').'</i> <i class="q0">'.Lang::main('byUser', [$log['name'], 'style="text-decoration:underline"'])."</i></li>\n";
|
||||
$buff .= '<li class="guide-changelog-minor-edit">'.$inp($log['rev']).'<b>'.$now->formatDate($log['date'], true).Lang::main('colon').'</b><i>'.Lang::guide('clMinorEdit').'</i> <i class="q0">'.Lang::main('byUser', [$log['name'], 'style="text-decoration:underline"'])."</i></li>\n";
|
||||
}
|
||||
|
||||
// append creation
|
||||
$buff .= '<li class="guide-changelog-created">'.$inp(0).'<b>'.Lang::guide('clCreated').'</b>'.Util::formatTimeDiff($guide->getField('date'))."</li>\n</ul>\n";
|
||||
$buff .= '<li class="guide-changelog-created">'.$inp(0).'<b>'.Lang::guide('clCreated').'</b>'.$now->formatDate($guide->getField('date'), true)."</li>\n</ul>\n";
|
||||
|
||||
if (User::isInGroup(U_GROUP_STAFF) && false)
|
||||
$buff .= '<input type="button" value="Compare" onclick="alert(\'NYI\');" style="margin-left: 40px;"/>';
|
||||
|
||||
@@ -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 = array_pop($subject);
|
||||
$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);
|
||||
|
||||
|
||||
/****************/
|
||||
@@ -433,9 +443,9 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
// tabs: this item is contained in..
|
||||
$lootTabs = new Loot();
|
||||
$lootTabs = new LootByItem($this->typeId);
|
||||
$createdBy = [];
|
||||
if ($lootTabs->getByItem($this->typeId))
|
||||
if ($lootTabs->getByItem())
|
||||
{
|
||||
$this->extendGlobalData($lootTabs->jsGlobals);
|
||||
|
||||
@@ -444,23 +454,44 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
if (!$tabData['data'])
|
||||
continue;
|
||||
|
||||
if ($idx == 16)
|
||||
if ($idx == LootByItem::SPELL_CREATED)
|
||||
$createdBy = array_column($tabData['data'], 'id');
|
||||
|
||||
if ($idx == 1)
|
||||
if ($idx == LootByItem::ITEM_DISENCHANTED)
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?items&filter=cr=163;crs='.$this->typeId.';crv=0');
|
||||
|
||||
if ($idx == 4 && $this->subject->getSources($s, $sm) && $s[0] == SRC_DROP && isset($sm[0]['dd']))
|
||||
{
|
||||
switch ($sm[0]['dd'])
|
||||
if ($idx == LootByItem::NPC_DROPPED && $this->subject->getSources($s, $sm) && $s[0] == SRC_DROP && isset($sm[0]['dd']))
|
||||
$tabData['note'] = match($sm[0]['dd'])
|
||||
{
|
||||
case -1: $tabData['note'] = '$LANG.lvnote_itemdropsinnormalonly'; break;
|
||||
case -2: $tabData['note'] = '$LANG.lvnote_itemdropsinheroiconly'; break;
|
||||
case -3: $tabData['note'] = '$LANG.lvnote_itemdropsinnormalheroic'; break;
|
||||
case 1: $tabData['note'] = '$LANG.lvnote_itemdropsinnormal10only'; break;
|
||||
case 2: $tabData['note'] = '$LANG.lvnote_itemdropsinnormal25only'; break;
|
||||
case 3: $tabData['note'] = '$LANG.lvnote_itemdropsinheroic10only'; break;
|
||||
case 4: $tabData['note'] = '$LANG.lvnote_itemdropsinheroic25only'; break;
|
||||
-1 => '$LANG.lvnote_itemdropsinnormalonly',
|
||||
-2 => '$LANG.lvnote_itemdropsinheroiconly',
|
||||
-3 => '$LANG.lvnote_itemdropsinnormalheroic',
|
||||
1 => '$LANG.lvnote_itemdropsinnormal10only',
|
||||
2 => '$LANG.lvnote_itemdropsinnormal25only',
|
||||
3 => '$LANG.lvnote_itemdropsinheroic10only',
|
||||
4 => '$LANG.lvnote_itemdropsinheroic25only',
|
||||
default => null
|
||||
};
|
||||
|
||||
if ($idx == LootByItem::OBJECT_FISHED && !$this->map)
|
||||
{
|
||||
$nodeIds = array_map(fn($x) => $x['id'], $tabData['data']);
|
||||
$fishedIn = new GameObjectList(array(['id', $nodeIds]));
|
||||
if (!$fishedIn->error)
|
||||
{
|
||||
// show mapper for fishing locations
|
||||
if ($nodeSpawns = $fishedIn->getSpawns(SPAWNINFO_FULL, true, true, true, true))
|
||||
{
|
||||
$this->map = array(
|
||||
['parent' => 'mapper-generic'], // Mapper
|
||||
$nodeSpawns, // mapperData
|
||||
null, // ShowOnMap
|
||||
[Lang::item('fishedIn')], // foundIn
|
||||
Lang::item('fishingLoc') // title
|
||||
);
|
||||
foreach ($nodeSpawns as $areaId => $_)
|
||||
$this->map[3][$areaId] = ZoneList::getName($areaId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,24 +504,25 @@ 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_DISENCHANT, $this->subject->getField('disenchantId'), '$LANG.tab_disenchanting', 'disenchanting', ['$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']]
|
||||
);
|
||||
|
||||
foreach ($sourceFor as [$lootTemplate, $lootId, $tabName, $tabId, $extraCols, $hiddenCols])
|
||||
{
|
||||
$lootTab = new Loot();
|
||||
if ($lootTab->getByContainer($lootTemplate, $lootId))
|
||||
$lootTab = new LootByContainer();
|
||||
if ($lootTab->getByContainer($lootTemplate, [$lootId]))
|
||||
{
|
||||
$this->extendGlobalData($lootTab->jsGlobals);
|
||||
$extraCols = array_merge($extraCols, $lootTab->extraCols);
|
||||
|
||||
$tabData = array(
|
||||
'data' => $lootTab->getResult(),
|
||||
'name' => $tabName,
|
||||
'id' => $tabId,
|
||||
'data' => $lootTab->getResult(),
|
||||
'name' => $tabName,
|
||||
'id' => $tabId,
|
||||
'computeDataFunc' => '$Listview.funcBox.initLootTable'
|
||||
);
|
||||
|
||||
if ($extraCols)
|
||||
@@ -585,12 +617,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)
|
||||
@@ -621,40 +655,6 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
// tab: see also
|
||||
$conditions = array(
|
||||
['id', $this->typeId, '!'],
|
||||
[
|
||||
'OR',
|
||||
['name_loc'.Lang::getLocale()->value, $this->subject->getField('name', true)],
|
||||
[
|
||||
'AND',
|
||||
['class', $_class],
|
||||
['subClass', $_subClass],
|
||||
['slot', $_slot],
|
||||
['itemLevel', $_ilvl - 15, '>'],
|
||||
['itemLevel', $_ilvl + 15, '<'],
|
||||
['quality', $this->subject->getField('quality')],
|
||||
['requiredClass', $this->subject->getField('requiredClass') ?: -1] // todo: fix db data in setup and not on fetch
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
if ($_ = $this->subject->getField('itemset'))
|
||||
$conditions[1][] = ['AND', ['slot', $_slot], ['itemset', $_]];
|
||||
|
||||
$saItems = new ItemList($conditions);
|
||||
if (!$saItems->error)
|
||||
{
|
||||
$this->extendGlobalData($saItems->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $saItems->getListviewData(),
|
||||
'name' => '$LANG.tab_seealso',
|
||||
'id' => 'see-also'
|
||||
), ItemList::$brickFile));
|
||||
}
|
||||
|
||||
// tab: starts (quest)
|
||||
if ($qId = $this->subject->getField('startQuest'))
|
||||
{
|
||||
@@ -707,28 +707,10 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
), QuestList::$brickFile));
|
||||
}
|
||||
|
||||
// tab: same model as
|
||||
// todo (low): should also work for creatures summoned by item
|
||||
if (($model = $this->subject->getField('model')) && $_slot)
|
||||
{
|
||||
$sameModel = new ItemList(array(['model', $model], ['id', $this->typeId, '!'], ['slot', $_slot]));
|
||||
if (!$sameModel->error)
|
||||
{
|
||||
$this->extendGlobalData($sameModel->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $sameModel->getListviewData(ITEMINFO_MODEL),
|
||||
'name' => '$LANG.tab_samemodelas',
|
||||
'id' => 'same-model-as',
|
||||
'genericlinktype' => 'item'
|
||||
), 'genericmodel'));
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
@@ -736,13 +718,14 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
if ($vendorSpawns = $soldBy->getSpawns(SPAWNINFO_FULL, true, true, true, true))
|
||||
{
|
||||
$this->map = array(
|
||||
['parent' => 'mapper-generic'], // Mapper
|
||||
$vendorSpawns, // mapperData
|
||||
null, // ShowOnMap
|
||||
[Lang::item('purchasedIn')] // foundIn
|
||||
['parent' => 'mapper-generic'], // Mapper
|
||||
$vendorSpawns, // mapperData
|
||||
null, // ShowOnMap
|
||||
[Lang::item('purchasedIn')], // foundIn
|
||||
Lang::item('vendorLoc') // title
|
||||
);
|
||||
foreach ($vendorSpawns as $areaId => $_)
|
||||
$this->map['extra'][$areaId] = ZoneList::getName($areaId);
|
||||
$this->map[3][$areaId] = ZoneList::getName($areaId);
|
||||
}
|
||||
|
||||
$sbData = $soldBy->getListviewData();
|
||||
@@ -751,7 +734,7 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
$extraCols = ['$Listview.extraCols.stock', "\$Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')", '$Listview.extraCols.cost'];
|
||||
|
||||
$cnd = new Conditions();
|
||||
$cnd->getBySourceEntry($this->typeId, Conditions::SRC_NPC_VENDOR)->prepare();
|
||||
$cnd->getBySource(Conditions::SRC_NPC_VENDOR, entry: $this->typeId)->prepare();
|
||||
foreach ($sbData as $k => &$row)
|
||||
{
|
||||
$currency = [];
|
||||
@@ -892,6 +875,58 @@ class ItemBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
// tab: see also
|
||||
$conditions = array(
|
||||
['id', $this->typeId, '!'],
|
||||
[
|
||||
'OR',
|
||||
['name_loc'.Lang::getLocale()->value, $this->subject->getField('name', true)],
|
||||
[
|
||||
'AND',
|
||||
['class', $_class],
|
||||
['subClass', $_subClass],
|
||||
['slot', $_slot],
|
||||
['itemLevel', $_ilvl - 15, '>'],
|
||||
['itemLevel', $_ilvl + 15, '<'],
|
||||
['quality', $this->subject->getField('quality')],
|
||||
['requiredClass', $this->subject->getField('requiredClass') ?: -1] // todo: fix db data in setup and not on fetch
|
||||
]
|
||||
]
|
||||
);
|
||||
|
||||
if ($_ = $this->subject->getField('itemset'))
|
||||
$conditions[1][] = ['AND', ['slot', $_slot], ['itemset', $_]];
|
||||
|
||||
$saItems = new ItemList($conditions);
|
||||
if (!$saItems->error)
|
||||
{
|
||||
$this->extendGlobalData($saItems->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $saItems->getListviewData(),
|
||||
'name' => '$LANG.tab_seealso',
|
||||
'id' => 'see-also'
|
||||
), ItemList::$brickFile));
|
||||
}
|
||||
|
||||
// tab: same model as
|
||||
// todo (low): should also work for creatures summoned by item
|
||||
if (($model = $this->subject->getField('model')) && $_slot)
|
||||
{
|
||||
$sameModel = new ItemList(array(['model', $model], ['id', $this->typeId, '!'], ['slot', $_slot]));
|
||||
if (!$sameModel->error)
|
||||
{
|
||||
$this->extendGlobalData($sameModel->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $sameModel->getListviewData(ITEMINFO_MODEL),
|
||||
'name' => '$LANG.tab_samemodelas',
|
||||
'id' => 'same-model-as',
|
||||
'genericlinktype' => 'item'
|
||||
), 'genericmodel'));
|
||||
}
|
||||
}
|
||||
|
||||
// tab: Shared cooldown
|
||||
$cdCats = [];
|
||||
$useSpells = [];
|
||||
|
||||
@@ -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,22 @@ class LatestcommentsRssResponse extends TextResponse
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
foreach (CommunityContent::getCommentPreviews(dateFmt: false) as $comment)
|
||||
$now = new DateTime();
|
||||
|
||||
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']],
|
||||
'description' => [true, [], htmlentities($comment['preview'])."<br /><br />".Lang::main('byUser', [$comment['user'], '']) . Util::formatTimeDiff($comment['date'])],
|
||||
'link' => [false, [], $url],
|
||||
'description' => [true, [], htmlentities($comment['preview'])."<br /><br />".Lang::main('byUser', [$comment['user'], '']) . $now->formatDate($comment['date'], true)],
|
||||
'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]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,12 +14,14 @@ class LatestscreenshotsRssResponse extends TextResponse
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$now = new DateTime();
|
||||
|
||||
foreach (CommunityContent::getScreenshots(dateFmt: false) as $screenshot)
|
||||
{
|
||||
$desc = '<a href="'.Cfg::get('HOST_URL').'/?'.Type::getFileString($screenshot['type']).'='.$screenshot['typeId'].'#screenshots:id='.$screenshot['id'].'"><img src="'.Cfg::get('STATIC_URL').'/uploads/screenshots/thumb/'.$screenshot['id'].'.jpg" alt="" /></a>';
|
||||
if ($screenshot['caption'])
|
||||
$desc .= '<br />'.$screenshot['caption'];
|
||||
$desc .= "<br /><br />".Lang::main('byUser', [$screenshot['user'], '']) . Util::formatTimeDiff($screenshot['date'], true);
|
||||
$desc .= "<br /><br />".Lang::main('byUser', [$screenshot['user'], '']) . $now->formatDate($screenshot['date'], true);
|
||||
|
||||
// enclosure/length => filesize('static/uploads/screenshots/thumb/'.$screenshot['id'].'.jpg') .. always set to this placeholder value though
|
||||
$this->feedData[] = array(
|
||||
|
||||
@@ -14,12 +14,14 @@ class LatestvideosRssResponse extends TextResponse
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$now = new DateTime();
|
||||
|
||||
foreach (CommunityContent::getvideos(dateFmt: false) as $video)
|
||||
{
|
||||
$desc = '<a href="'.Cfg::get('HOST_URL').'/?'.Type::getFileString($video['type']).'='.$video['typeId'].'#videos:id='.$video['id'].'"><img src="//i3.ytimg.com/vi/'.$video['videoId'].'/default.jpg" alt="" /></a>';
|
||||
if ($video['caption'])
|
||||
$desc .= '<br />'.$video['caption'];
|
||||
$desc .= "<br /><br />".Lang::main('byUser', [$video['user'], '']) . Util::formatTimeDiff($video['date'], true);
|
||||
$desc .= "<br /><br />".Lang::main('byUser', [$video['user'], '']) . $now->formatDate($video['date'], true);
|
||||
|
||||
// is enclosure/length .. is this even relevant..?
|
||||
$this->feedData[] = array(
|
||||
|
||||
@@ -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';
|
||||
@@ -99,7 +99,7 @@ class MailBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
if ($q['rewardMailDelay'] > 0)
|
||||
$infobox[] = Lang::mail('delay', [Util::formatTime($q['rewardMailDelay'] * 1000)]);
|
||||
$infobox[] = Lang::mail('delay', [DateTime::formatTimeElapsed($q['rewardMailDelay'] * 1000)]);
|
||||
}
|
||||
else if ($npcId = DB::World()->selectCell('SELECT `Sender` FROM achievement_reward WHERE `MailTemplateId` = ?d', $this->typeId))
|
||||
{
|
||||
@@ -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';
|
||||
@@ -103,18 +103,17 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
/**********************/
|
||||
|
||||
$mapType = 0;
|
||||
if ($maps = DB::Aowow()->selectCol('SELECT DISTINCT `areaId` FROM ?_spawns WHERE `type` = ?d AND `typeId` = ?d', Type::NPC, $this->typeId))
|
||||
if ($maps = DB::Aowow()->selectCell('SELECT IF(COUNT(DISTINCT `areaId`) > 1, 0, `areaId`) FROM ?_spawns WHERE `type` = ?d AND `typeId` = ?d', Type::NPC, $this->typeId))
|
||||
{
|
||||
if (count($maps) == 1) // should only exist in one instance
|
||||
$mapType = match (DB::Aowow()->selectCell('SELECT `type` FROM ?_zones WHERE `id` = ?d', $maps[0]))
|
||||
{
|
||||
// MAP_TYPE_DUNGEON,
|
||||
MAP_TYPE_DUNGEON_HC => 1,
|
||||
// MAP_TYPE_RAID,
|
||||
MAP_TYPE_MMODE_RAID,
|
||||
MAP_TYPE_MMODE_RAID_HC => 2,
|
||||
default => 0
|
||||
};
|
||||
$mapType = match ((int)DB::Aowow()->selectCell('SELECT `type` FROM ?_zones WHERE `id` = ?d', $maps[0]))
|
||||
{
|
||||
// MAP_TYPE_DUNGEON,
|
||||
MAP_TYPE_DUNGEON_HC => 1,
|
||||
// MAP_TYPE_RAID,
|
||||
MAP_TYPE_MMODE_RAID,
|
||||
MAP_TYPE_MMODE_RAID_HC => 2,
|
||||
default => 0
|
||||
};
|
||||
}
|
||||
// npc is difficulty dummy: get max difficulty from parent npc
|
||||
if ($this->placeholder && ($mt = DB::Aowow()->selectCell('SELECT IF(`difficultyEntry1` = ?d, 1, 2) FROM ?_creature WHERE `difficultyEntry1` = ?d OR `difficultyEntry2` = ?d OR `difficultyEntry3` = ?d', $this->typeId, $this->typeId, $this->typeId, $this->typeId)))
|
||||
@@ -194,6 +193,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
|
||||
@@ -237,7 +243,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
if ($stats = $this->getCreatureStats($mapType, $_altIds))
|
||||
$infobox[] = Lang::npc('stats').($_altIds ? ' ('.Lang::npc('modes', $mapType, 0).')' : '').Lang::main('colon').'[ul][li]'.implode('[/li][li]', $stats).'[/li][/ul]';
|
||||
$infobox[] = Lang::npc('stats').($_altIds ? ' ('.Lang::game('modes', $mapType, 0).')' : '').Lang::main('colon').'[ul][li]'.implode('[/li][li]', $stats).'[/li][/ul]';
|
||||
|
||||
if ($infobox)
|
||||
{
|
||||
@@ -312,6 +318,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: abilities / tab_controlledabilities (dep: VehicleId)
|
||||
$tplSpells = [];
|
||||
$genSpells = [];
|
||||
$spellClick = [];
|
||||
$conditions = ['OR'];
|
||||
|
||||
for ($i = 1; $i < 9; $i++)
|
||||
@@ -333,6 +340,12 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
if ($genSpells)
|
||||
$conditions[] = ['id', $genSpells];
|
||||
|
||||
if ($spellClick = DB::World()->select('SELECT `spell_id` AS ARRAY_KEY, `cast_flags` AS "0", `user_type` AS "1" FROM npc_spellclick_spells WHERE `npc_entry` = ?d', $this->typeId))
|
||||
{
|
||||
$genSpells = array_merge($genSpells, array_keys($spellClick));
|
||||
$conditions[] = ['id', array_keys($spellClick)];
|
||||
}
|
||||
|
||||
// Pet-Abilities
|
||||
if (($_typeFlags & NPC_TYPEFLAG_TAMEABLE) && ($_ = $this->subject->getField('family')))
|
||||
{
|
||||
@@ -370,6 +383,9 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
foreach ($controled as $id => $values)
|
||||
{
|
||||
if (isset($spellClick[$id]))
|
||||
$values['spellclick'] = $spellClick[$id];
|
||||
|
||||
if (in_array($id, $genSpells))
|
||||
{
|
||||
$normal[$id] = $values;
|
||||
@@ -379,7 +395,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
$cnd = new Conditions();
|
||||
$cnd->getBySourceGroup($this->typeId, Conditions::SRC_VEHICLE_SPELL)->prepare();
|
||||
$cnd->getBySource(Conditions::SRC_VEHICLE_SPELL, group: $this->typeId)->prepare();
|
||||
if ($cnd->toListviewColumn($controled, $extraCols, $this->typeId, 'id'))
|
||||
$this->extendGlobalData($cnd->getJsGlobals());
|
||||
|
||||
@@ -526,7 +542,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]]);
|
||||
@@ -541,7 +557,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
$cnd = new Conditions();
|
||||
if ($cnd->getBySourceGroup($this->typeId, Conditions::SRC_NPC_VENDOR)->prepare())
|
||||
if ($cnd->getBySource(Conditions::SRC_NPC_VENDOR, group: $this->typeId)->prepare())
|
||||
{
|
||||
$this->extendGlobalData($cnd->getJsGlobals());
|
||||
$cnd->toListviewColumn($lvData, $extraCols, $this->typeId, 'id');
|
||||
@@ -559,79 +575,108 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
// tabs: this creature contains..
|
||||
$skinTab = ['tab_skinning', 'skinning', SKILL_SKINNING];
|
||||
if ($_typeFlags & NPC_TYPEFLAG_SKIN_WITH_HERBALISM)
|
||||
$skinTab = ['tab_herbalism', 'herbalism', SKILL_HERBALISM];
|
||||
else if ($_typeFlags & NPC_TYPEFLAG_SKIN_WITH_MINING)
|
||||
$skinTab = ['tab_mining', 'mining', SKILL_MINING];
|
||||
else if ($_typeFlags & NPC_TYPEFLAG_SKIN_WITH_ENGINEERING)
|
||||
$skinTab = ['tab_engineering', 'engineering', SKILL_ENGINEERING];
|
||||
|
||||
/*
|
||||
extraCols: [Listview.extraCols.count, Listview.extraCols.percent, Listview.extraCols.mode],
|
||||
_totalCount: 22531,
|
||||
computeDataFunc: Listview.funcBox.initLootTable,
|
||||
onAfterCreate: Listview.funcBox.addModeIndicator,
|
||||
|
||||
modes:{"mode":1,"1":{"count":4408,"outof":16013},"4":{"count":4408,"outof":22531}}
|
||||
*/
|
||||
if ($this->subject->isGatherable())
|
||||
$skinTab = ['$LANG.tab_herbalism', 'herbalism', SKILL_HERBALISM];
|
||||
else if ($this->subject->isMineable())
|
||||
$skinTab = ['$LANG.tab_mining', 'mining', SKILL_MINING];
|
||||
else if ($this->subject->isSalvageable())
|
||||
$skinTab = ['$LANG.tab_engineering', 'engineering', SKILL_ENGINEERING];
|
||||
else
|
||||
$skinTab = ['$LANG.tab_skinning', 'skinning', SKILL_SKINNING];
|
||||
|
||||
$sourceFor = array(
|
||||
0 => [LOOT_CREATURE, $this->subject->getField('lootId'), '$LANG.tab_drops', 'drops', [ ], ''],
|
||||
8 => [LOOT_PICKPOCKET, $this->subject->getField('pickpocketLootId'), '$LANG.tab_pickpocketing', 'pickpocketing', ['side', 'slot', 'reqlevel'], ''],
|
||||
9 => [LOOT_SKINNING, $this->subject->getField('skinLootId'), '$LANG.'.$skinTab[0], $skinTab[1], ['side', 'slot', 'reqlevel'], '']
|
||||
0 => [Loot::CREATURE, [4 => $this->subject->getField('lootId')], '$LANG.tab_drops', 'drops', [ ], ''],
|
||||
1 => [Loot::GAMEOBJECT, [], '$LANG.tab_drops', 'drops-object', [ ], ''],
|
||||
2 => [Loot::PICKPOCKET, [4 => $this->subject->getField('pickpocketLootId')], '$LANG.tab_pickpocketing', 'pickpocketing', ['side', 'slot', 'reqlevel'], ''],
|
||||
3 => [Loot::SKINNING, [4 => $this->subject->getField('skinLootId')], $skinTab[0], $skinTab[1], ['side', 'slot', 'reqlevel'], '']
|
||||
);
|
||||
|
||||
// temp: manually add loot for difficulty-versions
|
||||
$langref = array(
|
||||
"-2" => '$LANG.tab_heroic',
|
||||
"-1" => '$LANG.tab_normal',
|
||||
1 => '$$WH.sprintf(LANG.tab_normalX, 10)',
|
||||
2 => '$$WH.sprintf(LANG.tab_normalX, 25)',
|
||||
3 => '$$WH.sprintf(LANG.tab_heroicX, 10)',
|
||||
4 => '$$WH.sprintf(LANG.tab_heroicX, 25)'
|
||||
);
|
||||
/* loot tabs to sub tabs
|
||||
* (1 << 0) => '$LANG.tab_heroic',
|
||||
* (1 << 1) => '$LANG.tab_normal',
|
||||
* (1 << 2) => '$LANG.tab_drops',
|
||||
* (1 << 3) => '$$WH.sprintf(LANG.tab_normalX, 10)',
|
||||
* (1 << 4) => '$$WH.sprintf(LANG.tab_normalX, 25)',
|
||||
* (1 << 5) => '$$WH.sprintf(LANG.tab_heroicX, 10)',
|
||||
* (1 << 6) => '$$WH.sprintf(LANG.tab_heroicX, 25)'
|
||||
*/
|
||||
|
||||
$getBit = function(int $type, int $difficulty) : int
|
||||
{
|
||||
if ($type == 1) // dungeon
|
||||
return 1 << (2 - $difficulty);
|
||||
if ($type == 2) // raid
|
||||
return 1 << (2 + $difficulty);
|
||||
return 4; // generic case
|
||||
};
|
||||
|
||||
foreach (DB::Aowow()->select('SELECT l.`difficulty` AS ARRAY_KEY, o.`id`, o.`lootId`, o.`name_loc0`, o.`name_loc2`, o.`name_loc3`, o.`name_loc4`, o.`name_loc6`, o.`name_loc8` FROM ?_loot_link l JOIN ?_objects o ON o.`id` = l.`objectId` WHERE l.`npcId` = ?d ORDER BY `difficulty` ASC', $this->typeId) as $difficulty => $lgo)
|
||||
{
|
||||
$sourceFor[1][1][$getBit($mapType, $difficulty)] = $lgo['lootId'];
|
||||
$sourceFor[1][5] = $sourceFor[1][5] ?: '$$WH.sprintf(LANG.lvnote_npcobjectsource, '.$lgo['id'].', "'.Util::localizedString($lgo, 'name').'")';
|
||||
}
|
||||
|
||||
if ($_altIds)
|
||||
{
|
||||
$sourceFor[0][2] = $mapType == 1 ? $langref[-1] : $langref[1];
|
||||
if ($mapType == 1) // map generic loot to dungeon NH
|
||||
{
|
||||
$sourceFor[0][1] = [2 => $sourceFor[0][1][4]];
|
||||
$sourceFor[2][1] = [2 => $sourceFor[2][1][4]];
|
||||
$sourceFor[3][1] = [2 => $sourceFor[3][1][4]];
|
||||
}
|
||||
if ($mapType == 2) // map generic loot to raid 10NH
|
||||
{
|
||||
$sourceFor[0][1] = [8 => $sourceFor[0][1][4]];
|
||||
$sourceFor[2][1] = [8 => $sourceFor[2][1][4]];
|
||||
$sourceFor[3][1] = [8 => $sourceFor[3][1][4]];
|
||||
}
|
||||
|
||||
foreach ($this->altNPCs->iterate() as $id => $__)
|
||||
{
|
||||
$mode = ($_altIds[$id] + 1) * ($mapType == 1 ? -1 : 1);
|
||||
foreach (DB::Aowow()->select('SELECT o.`id`, o.`lootId`, o.`name_loc0`, o.`name_loc2`, o.`name_loc3`, o.`name_loc4`, o.`name_loc6`, o.`name_loc8`, l.`difficulty` FROM ?_loot_link l JOIN ?_objects o ON o.`id` = l.`objectId` WHERE l.`npcId` = ?d', $id) as $l)
|
||||
$sourceFor[(($l['difficulty'] - 1) * 2) + 1] = [LOOT_GAMEOBJECT, $l['lootId'], $langref[$l['difficulty'] * ($mapType == 1 ? -1 : 1)], 'drops-object-'.$l['difficulty'], [], '$$WH.sprintf(LANG.lvnote_npcobjectsource, '.$l['id'].', "'.Util::localizedString($l, 'name').'")'];
|
||||
foreach (DB::Aowow()->select('SELECT l.`difficulty` AS ARRAY_KEY, o.`id`, o.`lootId`, o.`name_loc0`, o.`name_loc2`, o.`name_loc3`, o.`name_loc4`, o.`name_loc6`, o.`name_loc8` FROM ?_loot_link l JOIN ?_objects o ON o.`id` = l.`objectId` WHERE l.`npcId` = ?d ORDER BY `difficulty` ASC', $id) as $difficulty => $lgo)
|
||||
{
|
||||
$sourceFor[1][1][$getBit($mapType, $difficulty)] = $lgo['lootId'];
|
||||
$sourceFor[1][5] = $sourceFor[1][5] ?: '$$WH.sprintf(LANG.lvnote_npcobjectsource, '.$lgo['id'].', "'.Util::localizedString($lgo, 'name').'")';
|
||||
}
|
||||
|
||||
if ($lootId = $this->altNPCs->getField('lootId'))
|
||||
$sourceFor[($mode - 1) * 2] = [LOOT_CREATURE, $lootId, $langref[$mode], 'drops-'.abs($mode), [], ''];
|
||||
$sourceFor[0][1][$getBit($mapType, $_altIds[$id] + 1)] = $lootId;
|
||||
if ($lootId = $this->altNPCs->getField('pickpocketLootId'))
|
||||
$sourceFor[2][1][$getBit($mapType, $_altIds[$id] + 1)] = $lootId;
|
||||
if ($lootId = $this->altNPCs->getField('skinLootId'))
|
||||
$sourceFor[3][1][$getBit($mapType, $_altIds[$id] + 1)] = $lootId;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (DB::Aowow()->select('SELECT l.`difficulty` AS ARRAY_KEY, o.`id`, o.`lootId`, o.`name_loc0`, o.`name_loc2`, o.`name_loc3`, o.`name_loc4`, o.`name_loc6`, o.`name_loc8` FROM ?_loot_link l JOIN ?_objects o ON o.`id` = l.`objectId` WHERE l.`npcId` = ?d', $this->typeId) as $difficulty => $lgo)
|
||||
$sourceFor[(($difficulty - 1) * 2) + 1] = [LOOT_GAMEOBJECT, $lgo['lootId'], $mapType ? $langref[$difficulty * ($mapType == 1 ? -1 : 1)] : '$LANG.tab_drops', 'drops-object-'.$difficulty, [], '$$WH.sprintf(LANG.lvnote_npcobjectsource, '.$lgo['id'].', "'.Util::localizedString($lgo, 'name').'")'];
|
||||
|
||||
ksort($sourceFor);
|
||||
|
||||
foreach ($sourceFor as [$lootTpl, $lootId, $tabName, $tabId, $hiddenCols, $note])
|
||||
foreach ($sourceFor as [$lootTpl, $lootEntries, $tabName, $tabId, $hiddenCols, $note])
|
||||
{
|
||||
$creatureLoot = new Loot();
|
||||
if ($creatureLoot->getByContainer($lootTpl, $lootId))
|
||||
$creatureLoot = new LootByContainer();
|
||||
if ($creatureLoot->getByContainer($lootTpl, $lootEntries))
|
||||
{
|
||||
$extraCols = $creatureLoot->extraCols;
|
||||
$extraCols[] = '$Listview.extraCols.percent';
|
||||
array_push($extraCols, '$Listview.extraCols.count', '$Listview.extraCols.percent');
|
||||
if (count($lootEntries) > 1)
|
||||
$extraCols[] = '$Listview.extraCols.mode';
|
||||
|
||||
$hiddenCols[] = 'count';
|
||||
|
||||
$this->extendGlobalData($creatureLoot->jsGlobals);
|
||||
|
||||
$tabData = array(
|
||||
'data' => $creatureLoot->getResult(),
|
||||
'name' => $tabName,
|
||||
'id' => $tabId,
|
||||
'extraCols' => array_unique($extraCols),
|
||||
'hiddenCols' => $hiddenCols ?: null,
|
||||
'sort' => ['-percent', 'name']
|
||||
'data' => $creatureLoot->getResult(),
|
||||
'id' => $tabId,
|
||||
'name' => $tabName,
|
||||
'extraCols' => array_unique($extraCols),
|
||||
'hiddenCols' => $hiddenCols ?: null,
|
||||
'sort' => ['-percent', 'name'],
|
||||
'_totalCount' => 10000,
|
||||
'computeDataFunc' => '$Listview.funcBox.initLootTable',
|
||||
'onAfterCreate' => '$Listview.funcBox.addModeIndicator',
|
||||
);
|
||||
|
||||
if ($note)
|
||||
$tabData['note'] = $note;
|
||||
else if ($lootTpl == LOOT_SKINNING)
|
||||
else if ($lootTpl == Loot::SKINNING)
|
||||
$tabData['note'] = '<b>'.Lang::formatSkillBreakpoints(Game::getBreakpointsForSkill($skinTab[2], $this->subject->getField('maxLevel') * 5), Lang::FMT_HTML).'</b>';
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, ItemList::$brickFile));
|
||||
@@ -770,8 +815,8 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
// tab: conditions
|
||||
$cnd = new Conditions();
|
||||
$cnd->getBySourceEntry($this->typeId, Conditions::SRC_CREATURE_TEMPLATE_VEHICLE)
|
||||
->getBySourceGroup($this->typeId, Conditions::SRC_SPELL_CLICK_EVENT)
|
||||
$cnd->getBySource(Conditions::SRC_CREATURE_TEMPLATE_VEHICLE, entry: $this->typeId)
|
||||
->getBySource(Conditions::SRC_SPELL_CLICK_EVENT, group: $this->typeId)
|
||||
->getByCondition(Type::NPC, $this->typeId)
|
||||
->prepare();
|
||||
if ($tab = $cnd->toListviewTab())
|
||||
@@ -825,7 +870,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;
|
||||
@@ -841,7 +886,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
// base NPC
|
||||
if ($base = $this->getRepForId([$this->typeId], $spilledParents))
|
||||
$reputation[] = [Lang::npc('modes', 1, 0), $base];
|
||||
$reputation[] = [Lang::game('modes', 1, 0), $base];
|
||||
|
||||
// difficulty dummys
|
||||
if ($dummyIds && ($mapType == 1 || $mapType == 2))
|
||||
@@ -855,7 +900,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
// apply by difficulty
|
||||
foreach ($alt as $mode => $dat)
|
||||
$reputation[] = [Lang::npc('modes', $mapType, $mode), $dat];
|
||||
$reputation[] = [Lang::game('modes', $mapType, $mode), $dat];
|
||||
}
|
||||
|
||||
// get spillover factions and apply
|
||||
@@ -865,7 +910,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;
|
||||
@@ -957,7 +1002,7 @@ class NpcBaseResponse extends TemplateResponse implements ICache
|
||||
if (!$this->altNPCs->getEntry($id))
|
||||
continue;
|
||||
|
||||
$m = Lang::npc('modes', $mapType, $mode);
|
||||
$m = Lang::game('modes', $mapType, $mode);
|
||||
|
||||
// Health
|
||||
$health = $this->altNPCs->getBaseStats('health');
|
||||
@@ -999,10 +1044,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';
|
||||
@@ -22,6 +22,9 @@ class ObjectBaseResponse extends TemplateResponse implements ICache
|
||||
public ?Book $book = null;
|
||||
public ?array $relBoss = null;
|
||||
|
||||
private array $difficulties = [];
|
||||
private int $mapType = 0;
|
||||
|
||||
private GameObjectList $subject;
|
||||
|
||||
public function __construct(string $id)
|
||||
@@ -61,6 +64,37 @@ class ObjectBaseResponse extends TemplateResponse implements ICache
|
||||
array_unshift($this->title, Lang::unescapeUISequences($this->subject->getField('name', true), Lang::FMT_RAW), Util::ucFirst(Lang::game('object')));
|
||||
|
||||
|
||||
/**********************/
|
||||
/* Determine Map Type */
|
||||
/**********************/
|
||||
|
||||
if ($objectdifficulty = DB::Aowow()->select( // has difficulty versions of itself
|
||||
'SELECT `normal10` AS "0", `normal25` AS "1",
|
||||
`heroic10` AS "2", `heroic25` AS "3",
|
||||
`mapType` AS ARRAY_KEY
|
||||
FROM ?_objectdifficulty
|
||||
WHERE `normal10` = ?d OR `normal25` = ?d OR
|
||||
`heroic10` = ?d OR `heroic25` = ?d',
|
||||
$this->typeId, $this->typeId, $this->typeId, $this->typeId
|
||||
))
|
||||
{
|
||||
$this->mapType = key($objectdifficulty);
|
||||
$this->difficulties = array_pop($objectdifficulty);
|
||||
}
|
||||
else if ($maps = DB::Aowow()->selectCell('SELECT IF(COUNT(DISTINCT `areaId`) > 1, 0, `areaId`) FROM ?_spawns WHERE `type` = ?d AND `typeId` = ?d', Type::OBJECT, $this->typeId))
|
||||
{
|
||||
$this->mapType = match ((int)DB::Aowow()->selectCell('SELECT `type` FROM ?_zones WHERE `id` = ?d', $maps))
|
||||
{
|
||||
// MAP_TYPE_DUNGEON,
|
||||
MAP_TYPE_DUNGEON_HC => 1,
|
||||
// MAP_TYPE_RAID,
|
||||
MAP_TYPE_MMODE_RAID,
|
||||
MAP_TYPE_MMODE_RAID_HC => 2,
|
||||
default => 0
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/***********/
|
||||
/* Infobox */
|
||||
/***********/
|
||||
@@ -148,12 +182,10 @@ 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;
|
||||
$infobox[] = $restock > 1 ? '[tooltip name=restock]'.Lang::gameObject('restock', [DateTime::formatTimeElapsed($restock * 1000)]).'[/tooltip][span class=tip tooltip=restock]'.$buff.'[/span]' : $buff;
|
||||
}
|
||||
|
||||
// meeting stone [minLevel, maxLevel, zone]
|
||||
@@ -163,10 +195,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 +210,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) => DateTime::formatTimeElapsed(-$x * 1000)).'[/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 +225,18 @@ 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]';
|
||||
|
||||
// used in mode
|
||||
foreach ($this->difficulties as $n => $id)
|
||||
if ($id == $this->typeId)
|
||||
$infobox[] = Lang::game('mode').Lang::game('modes', $this->mapType, $n);
|
||||
|
||||
// AI
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
if ($_ = $this->subject->getField('ScriptOrAI'))
|
||||
@@ -400,12 +441,37 @@ class ObjectBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: contains
|
||||
if ($_ = $this->subject->getField('lootId'))
|
||||
{
|
||||
$goLoot = new Loot();
|
||||
if ($goLoot->getByContainer(LOOT_GAMEOBJECT, $_))
|
||||
// check if loot_link entry exists (only difficulty: 1)
|
||||
if ($npcId = DB::Aowow()->selectCell('SELECT `npcId` FROM ?_loot_link WHERE `objectId` = ?d AND `difficulty` = 1', $this->typeId))
|
||||
{
|
||||
$extraCols = $goLoot->extraCols;
|
||||
$extraCols[] = '$Listview.extraCols.percent';
|
||||
$hiddenCols = ['source', 'side', 'slot', 'reqlevel'];
|
||||
// get id set of npc
|
||||
$lootEntries = DB::Aowow()->selectCol(
|
||||
'SELECT ll.`difficulty` AS ARRAY_KEY, o.`lootId`
|
||||
FROM ?_creature c
|
||||
LEFT JOIN ?_loot_link ll ON ll.`npcId` IN (c.`id`, c.`difficultyEntry1`, c.`difficultyEntry2`, c.`difficultyEntry3`)
|
||||
LEFT JOIN ?_objects o ON o.`id` = ll.`objectId`
|
||||
WHERE c.`id` = ?d
|
||||
ORDER BY ll.`difficulty` ASC',
|
||||
$npcId
|
||||
);
|
||||
|
||||
if ($this->mapType == 2 || count($lootEntries) > 2) // always raid
|
||||
$lootEntries = array_combine(array_map(fn($x) => 1 << (2 + $x), array_keys($lootEntries)), array_values($lootEntries));
|
||||
else if ($this->mapType == 1 || count($lootEntries) == 2) // dungeon or raid, assume dungeon
|
||||
$lootEntries = array_combine(array_map(fn($x) => 1 << (2 - $x), array_keys($lootEntries)), array_values($lootEntries));
|
||||
}
|
||||
else
|
||||
$lootEntries = [4 => $_];
|
||||
|
||||
$goLoot = new LootByContainer();
|
||||
if ($goLoot->getByContainer(Loot::GAMEOBJECT, $lootEntries))
|
||||
{
|
||||
$extraCols = $goLoot->extraCols;
|
||||
array_push($extraCols, '$Listview.extraCols.count', '$Listview.extraCols.percent');
|
||||
if (count($lootEntries) > 1)
|
||||
$extraCols[] = '$Listview.extraCols.mode';
|
||||
|
||||
$hiddenCols = ['source', 'side', 'slot', 'reqlevel', 'count'];
|
||||
|
||||
$this->extendGlobalData($goLoot->jsGlobals);
|
||||
$lootResult = $goLoot->getResult();
|
||||
@@ -419,12 +485,16 @@ class ObjectBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $lootResult,
|
||||
'id' => 'contains',
|
||||
'name' => '$LANG.tab_contains',
|
||||
'sort' => ['-percent', 'name'],
|
||||
'extraCols' => array_unique($extraCols),
|
||||
'hiddenCols' => $hiddenCols ?: null
|
||||
'data' => $lootResult,
|
||||
'id' => 'contains',
|
||||
'name' => '$LANG.tab_contains',
|
||||
'sort' => ['-percent', 'name'],
|
||||
'extraCols' => array_unique($extraCols),
|
||||
'hiddenCols' => $hiddenCols ?: null,
|
||||
'sort' => ['-percent', 'name'],
|
||||
'_totalCount' => 10000,
|
||||
'computeDataFunc' => '$Listview.funcBox.initLootTable',
|
||||
'onAfterCreate' => '$Listview.funcBox.addModeIndicator',
|
||||
), ItemList::$brickFile));
|
||||
}
|
||||
}
|
||||
@@ -469,6 +539,51 @@ class ObjectBaseResponse extends TemplateResponse implements ICache
|
||||
), GameObjectList::$brickFile));
|
||||
}
|
||||
|
||||
// tab: see also
|
||||
if ($this->difficulties)
|
||||
{
|
||||
$conditions = array(
|
||||
'AND',
|
||||
['id', $this->difficulties],
|
||||
['id', $this->typeId, '!']
|
||||
);
|
||||
|
||||
$saObjects = new GameObjectList($conditions);
|
||||
if (!$saObjects->error)
|
||||
{
|
||||
$data = $saObjects->getListviewData();
|
||||
if ($this->difficulties)
|
||||
{
|
||||
$saE = ['$Listview.extraCols.mode'];
|
||||
|
||||
foreach ($data as $id => &$d)
|
||||
{
|
||||
if (($modeBit = array_search($id, $this->difficulties)) !== false)
|
||||
{
|
||||
if ($this->mapType)
|
||||
$d['modes'] = ['mode' => 1 << ($modeBit + 3)];
|
||||
else
|
||||
$d['modes'] = ['mode' => 2 - $modeBit];
|
||||
}
|
||||
else
|
||||
$d['modes'] = ['mode' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
$tabData = array(
|
||||
'data' => $data,
|
||||
'id' => 'see-also',
|
||||
'name' => '$LANG.tab_seealso',
|
||||
'visibleCols' => ['level'],
|
||||
);
|
||||
|
||||
if (isset($saE))
|
||||
$tabData['extraCols'] = $saE;
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, GameObjectList::$brickFile));
|
||||
}
|
||||
}
|
||||
|
||||
// tab: Same model as
|
||||
$sameModel = new GameObjectList(array(['displayId', $this->subject->getField('displayId')], ['id', $this->typeId, '!']));
|
||||
if (!$sameModel->error)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
/*************/
|
||||
@@ -196,7 +197,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
// timer
|
||||
if ($_ = $this->subject->getField('timeLimit'))
|
||||
$infobox[] = Lang::quest('timer').Util::formatTime($_ * 1000);
|
||||
$infobox[] = Lang::quest('timer').DateTime::formatTimeElapsedFloat($_ * 1000);
|
||||
|
||||
$startEnd = DB::Aowow()->select('SELECT * FROM ?_quests_startend WHERE `questId` = ?d', $this->typeId);
|
||||
|
||||
@@ -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
|
||||
@@ -500,8 +518,8 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
// todo (med): this double list creation very much sucks ...
|
||||
$getItemSource = function ($itemId, $method = 0) use (&$mapNPCs, &$mapGOs)
|
||||
{
|
||||
$lootTabs = new Loot();
|
||||
if ($lootTabs->getByItem($itemId))
|
||||
$lootTabs = new LootByItem($itemId);
|
||||
if ($lootTabs->getByItem())
|
||||
{
|
||||
/*
|
||||
todo (med): sanity check:
|
||||
@@ -513,22 +531,22 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
for the moment:
|
||||
if an item has >10 sources, only display sources with >80% chance
|
||||
always filter sources with <1% chance
|
||||
always filter sources with <5% chance
|
||||
*/
|
||||
|
||||
$nSources = 0;
|
||||
foreach ($lootTabs->iterate() as [$type, $data])
|
||||
if ($type == 'creature' || $type == 'object')
|
||||
$nSources += count(array_filter($data['data'], function($val) { return $val['percent'] >= 1.0; }));
|
||||
$nSources += count(array_filter($data['data'], fn($x) => $x['percent'] >= 5.0));
|
||||
|
||||
foreach ($lootTabs->iterate() as $idx => [$file, $tabData])
|
||||
foreach ($lootTabs->iterate() as [$file, $tabData])
|
||||
{
|
||||
if (!$tabData['data'])
|
||||
continue;
|
||||
|
||||
foreach ($tabData['data'] as $data)
|
||||
{
|
||||
if ($data['percent'] < 1.0)
|
||||
if ($data['percent'] < 5.0)
|
||||
continue;
|
||||
|
||||
if ($nSources > 10 && $data['percent'] < 80.0)
|
||||
@@ -961,7 +979,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
// tab: conditions
|
||||
$cnd = new Conditions();
|
||||
$cnd->getBySourceEntry($this->typeId, Conditions::SRC_QUEST_AVAILABLE, Conditions::SRC_QUEST_SHOW_MARK)
|
||||
$cnd->getBySource([Conditions::SRC_QUEST_AVAILABLE, Conditions::SRC_QUEST_SHOW_MARK], entry: $this->typeId)
|
||||
->getByCondition(Type::QUEST, $this->typeId)
|
||||
->prepare();
|
||||
|
||||
@@ -1141,7 +1159,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
'header' => array(
|
||||
$rmtId,
|
||||
null,
|
||||
$delay ? Lang::mail('mailIn', [Util::formatTime($delay * 1000)]) : null,
|
||||
$delay ? Lang::mail('mailIn', [DateTime::formatTimeElapsed($delay * 1000)]) : null,
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1157,8 +1175,8 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
$this->mail['header'][1] = Lang::mail('mailBy', [$senderTypeId, $ti]);
|
||||
|
||||
// while mail attachemnts are handled as loot, it has no variance. Always 100% chance, always one item.
|
||||
$mailLoot = new Loot();
|
||||
if ($mailLoot->getByContainer(LOOT_MAIL, $rmtId))
|
||||
$mailLoot = new LootByContainer();
|
||||
if ($mailLoot->getByContainer(Loot::MAIL, [$rmtId]))
|
||||
{
|
||||
$this->extendGlobalData($mailLoot->jsGlobals);
|
||||
foreach ($mailLoot->getResult() as $loot)
|
||||
@@ -1286,7 +1304,7 @@ class QuestBaseResponse extends TemplateResponse implements ICache
|
||||
['reqQ', array('OR', ['AND', ['nextQuestId', $this->typeId], ['exclusiveGroup', 0, '<']], ['AND', ['id', $this->subject->getField('prevQuestId')], ['nextQuestIdChain', $this->typeId, '!']])],
|
||||
|
||||
// Requires one of these quests (Requires one of the quests to choose from)
|
||||
['reqOneQ', array('OR', ['AND', ['exclusiveGroup', 0, '>'], ['nextQuestId', $this->typeId]], ['breadCrumbForQuestId', $this->typeId])],
|
||||
['reqOneQ', array('OR', ['AND', ['exclusiveGroup', 0, '>='], ['nextQuestId', $this->typeId]], ['breadCrumbForQuestId', $this->typeId])],
|
||||
|
||||
// Opens Quests (Quests that become available only after complete this quest (optionally only one))
|
||||
['opensQ', array('OR', ['AND', ['prevQuestId', $this->typeId], ['id', $this->subject->getField('nextQuestIdChain'), '!']], ['id', $this->subject->getField('nextQuestId')], ['id', $this->subject->getField('breadcrumbForQuestId')])],
|
||||
|
||||
@@ -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
|
||||
|
||||
30
endpoints/signature/delete.php
Normal file
30
endpoints/signature/delete.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class SignatureDeleteResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
$this->generate404();
|
||||
|
||||
// DB::Aowow()->query(DELETE FROM ?_account_signatures WHERE `id` IN (?a) { AND `accountId` = ?d }', $this->_get['id], User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
60
endpoints/signature/generate.php
Normal file
60
endpoints/signature/generate.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
// introductory blog post
|
||||
// https://web.archive.org/web/20210419162936/https://www.wowhead.com/news/new-feature-preview-forum-signatures-175630
|
||||
// looks like it was .. at best .. live for half a year
|
||||
|
||||
// only example seen. looks like archive.org had a hickup when parsing the markup js
|
||||
// https://web.archive.org/web/20110924014309/http://www.wowhead.com/signature=generate&id='+b.unnamed+'.png
|
||||
|
||||
// no clue where generated images are stored.
|
||||
// static/uploads/signatures/ indicates users can upload their own backgrounds
|
||||
// unclear when updated. With every char sync?
|
||||
|
||||
// generating and also viewing
|
||||
class SignatureGenerateResponse extends TextResponse
|
||||
{
|
||||
protected string $contentType = MIME_TYPE_PNG;
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkProfileId']]
|
||||
);
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
parent::generate();
|
||||
|
||||
if (!$this->assertGET('id'))
|
||||
$this->generate404();
|
||||
|
||||
// find file in storage
|
||||
|
||||
// build image
|
||||
}
|
||||
|
||||
public function generate404(?string $out = null) : never
|
||||
{
|
||||
// "Signature Unavailable"
|
||||
$out = /*data:image/png;base64,*/'iVBORw0KGgoAAAANSUhEUgAAAdQAAAA8CAIAAABQJdxgAAALbElEQVR4nO3bXWxT5R8H8OectnvtDtB2fVnXN6Cr29zW0SCSjMgSh0YSifPtjgsu1EuvjXFojPfKDRLitYQYxEggEwzhQiJb1+GG4MrWjrbr1petW6FubXee/8UTT05aKBv85az4/VyY9uyc5y32y9PfOeXMZjMBAIBni1d6AAAA/0UIXwAABSB8AQAUgPAFAFAAwhcAQAEIXwAABSB8AQAUgPAFAFAAwhcAQAEIXwAABSB8AQAUgPAFAFAAwhcAQAEIXwAABSB8AQAUgPAFAFAAwhcAQAEIXwAABSB8AQAUgPAFAFAAwhcAQAEIXwAABaiVHgDA8+bzzz+XXouiKH+72TM33hRUHYRv1di7d++BAwcEQZCOcBzHXgwNDR07dsxkMhFCFhYWvvvuO2WG+K8pD52hoaHy4+zgs1e++D6fjxBCKR0bG6t87WPP3HhTUF0QvtVhYGCgr6/P5XJt376dZS6ldH19XaPR+P1+QojJZNq3bx8h5Pfff/+3B/Ppp5+q1WpCiCiKX3zxxb/dHcMyiGFTLjkuP/iMlS/+7Oysw+GQ/nWsIBQKuVyuCmduvCmoLqj5VoeXX37Z4/HodLpCoXDz5s2JiYlMJsMSUMJx3LP5iKrVap/P5/P5eP7Z/f8TCoXYi2AwKD+eSqUIIfPz889sJA8lX/zTp0+zUT3WqVOnFhcXK5yw8aag6mDnWx1UKlVjYyMhZGpqamlpaXx8vK+vz263s2+77Nv3+Pg4IaS2tpb999ChQ93d3RqNpkIiU0ql1ysrK2fPno1EIoSQvr6+ffv2NTU1SX9NpVLnzp2LxWLyb/ocx1WuQrIypfwcSimllOM4Sumff/45MjJy+PBhg8HABlksFkdHR4eHh0VRlLfz7bfffvjhhy6Xi43zxIkT7PhPP/301ltvGQyGeDx+5syZko42NbUPPvigwkQIIb/88kuFC+WLzzoq8ah+5eccP36cvchms8PDwxMTEw9tyul0bmTRYItD+FYZt9vN8/yBAwey2Ww0Go1Go+x4SWXw/fff93g8bre7vr6eyKrDhBC/3y+dHAwGd+7cqVKpKKWRSGRwcPDrr78mhOzfv7+np6epqYntbUVRvHfv3ttvv/3NN98Q2Td99kJqkPzz3b+8TCkdmZ6edrlcPM/n8/l8Pt/e3m42m61WK+sol8tpNJpCoXDlyhX5rOfm5uRvpc3gH3/88eabb7IR/vXXX/KONjs1UlbZsFqtZrNZevvYCyuXZStczlgsFrPZzP5ZSqVSgiAUCoU7d+6UtGO3248ePbqRRYMtDmWH6rC2tra0tEQIqaur6+jo8Hq9XV1dPM9ns1m2DZydnSWykHW5XB0dHQ0NDYlEYnx8nH23LRQKLBzZV3iO4/R6/cTERCKR4HneZrPt2LFD6lEQhJs3b/r9/mg0qlKpHA6HTqdjf5Kqq36/X96ghFUG5Ikv9dja2nr37l1KqVqt1mg0ZrPZZrMVCoVAIJBOpxsbG9va2l566aUNLkuhUJBer6+vP+XUQqEQ2y+zIkYsFkun05RSaXaPurBk8R+lwpISQkRRHBsbm5qaopQajUar1frqq6+WN/L6668/5aLBFoHwrQ6XL18OhUKRSCSfzxNC1Gq1wWDwer1Wq3VwcLC8MshxHKsIz83NpdNplg5qtZpSKq8zhsNhlgVEVrXkeZ7juNHRUVEUa2trGxoa5H8teaJgaGjo5MmT8sLliRMnVlZW5OfIe7x161Y6nb5x48bIyAjP8y0tLRzHsdSLxWKEEK1Wy768P4GnmdrJkyeTyWQulyOEbN++XRTFtbU1jUaTy+VSqdTp06cfdeFGyrKVl5RZWFg4f/78vXv3WKmhublZr9eXN2WxWP6/iwZKQdmhOoyMjKRSqf7+fpvNVlNTY7Va9Xo9x3Eul2t5ebm8MkgpLRaLGo3G4XAQQux2OyFkfX1d+rhKzp8/39vbS2QbtzfeeINtpurr61Uq1YMHD0jFbV08Hpe/LU+ikh6/+uor9uL48eMqlYoQ0t7evsF1YFQqFdvnajSaCh1tamrxeDwQCAiC4PF4amtrWblGq9Xevn07EAj09PQ86sKHlmVLbHBJA4FAJpM5duyY0+lkeV3eFMdxT7ZosNUgfKuDdCvp3LlzGo1mYGDAaDTu3r2bfQ7LhcPhuro6t9ut0+l0Oh2ldHV1NRgMsi2wnPzGFLNnz56Ojo76+vr79+/fuXOH4zh5MfSxnuARiEAgIL9ZVD4k6TjHcTzP2+12Vgpoa2tjVd1HnV9ypPLUrl275vP58vl8bW2tw+G4f/9+oVDIZrNXr179+OOPn2ZNNr6klW+Qym1w0WDLQtmhavh8vtbW1iNHjgiCkEgkWP2B2bZtm/xMs9l85syZtbU1tVodDAb9fv/Y2Njk5OTq6qooijabTX4ye4RAYjAYeJ6vq6sjhNy9ezeTycjDVKvVloyK7ayJ7MP/0UcflTRYMjx5+ZXFhyAI8Xjc7/enUqlkMnnr1q3y6VNK2cl6vf7dd9/1eDzd3d1HjhwxmUyiKLLeSzra7NSWl5dnZmbYzT2tVms0GqPR6Ozs7MrKSoULLRaLvBez2VwyDKPRWOFyuffee+/w4cOs2sC29uVNbWrRYCtTlX+cYAvq7+9vaWlpbGzUarU6nW7btm0ej0elUi0uLs7Nzb3yyiuNjY0Gg4EQ8vfff3d1dV2+fPngwYOsOmGxWFihsLm5uaampqurSzo5l8u1t7c3NDQ0NzcTQh48eOD1egkhrKpICBFF0ePxqNVqjuOWlpYcDsfo6Gh/f7/FYuE4rlgsut1uu92+Y8cOdkSlUjU3NzudTlZxZg3u379f6jGbze7Zs+fq1auEkM7OzsbGxqamJkEQisWixWLp7e3duXPn7du3y6PkxRdfrKurEwRBEASVSrVr167Ozk6bzWY2m1lE3rhx45NPPnnKqaVSqY6ODpPJxPO8KIrT09M//PBDNps9ePDgoy70er0liy+fby6X6+7urtBvsVhsaWmhlOp0Oo7jDAaD0+kkhMzNzc3MzAwMDJQ0lUwmN75osJVh51tlBEHo6urq6elRq9WJRCIcDrMHjF544QV2wq5duwghR48eZeFI/rmxw3FcTU2N2+2Wn7x7924iqx6yv+ZyuWg0Sik1mUzd3d2ZTGZ1dZVSKl21urrKHgOw2Wws0TKZDLvEaDRaLJZYLMa2oqxBeY8ej0eay/DwcDwen5+f53m+s7Ozp6eH5/nJycmHTvznn3+en5+fmZkpFAqtra29vb1er9dgMLD7kBcuXCjp6Mmmxp5wYGXrpaWlTCbDNsKVLyxZ/PJhVL6cUppOp/P5fG9vb1tbGyEkHo8vLCxcunSpvKlNLRpsZaj5Vg32UJe8tLe8vHzlyhX2rGvJj2udTicL6Onp6UwmQwjR6XTsAVtS9kvckrdnz54dHBxcWFhgb/P5fCwWk3ZthJCLFy/yPB8Oh6Xx/Pjjj++8804ikZAaKXni9aG//Q0Gg99///1rr70m3SgTRXFycvLixYvlJ4fD4VOnTg0MDCSTSemnfZTSaDR66dIlqYWnnBoh5Ndff9Xr9ewxiWvXrj32Qo7jyme3qX6vX7/OKtfSvFZWVi5cuMDq2iVNbWrRYCvjpMfI4Xny2Wef7d27l+O4ZDIZiUQ4jrPZbAaDYXFxcWpq6ssvv1R6gAD/ddj5Pp8KhUIkEmlpaTEYDKxiSCnNZDKhUGh4eFjp0QEAdr7PKbvdzn4KJb+xns1mf/vtt+vXrys4MABgEL4AAArA0w4AAApA+AIAKADhCwCgAIQvAIACEL4AAApA+AIAKADhCwCgAIQvAIACEL4AAApA+AIAKADhCwCgAIQvAIACEL4AAApA+AIAKADhCwCgAIQvAIACEL4AAApA+AIAKADhCwCggP8BQFB72fG1SEAAAAAASUVORK5CYII=';
|
||||
parent::generate404(base64_decode($out));
|
||||
}
|
||||
|
||||
protected static function checkProfileId(string $sigId) : ?int
|
||||
{
|
||||
if (preg_match('/^(\d+)\.png$/i', $sigId, $m))
|
||||
return $m[0];
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
55
endpoints/signature/signature.php
Normal file
55
endpoints/signature/signature.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class SignatureBaseResponse extends TemplateResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'signature';
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'profile' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkProfile']] // optional - full profile string to build sig from
|
||||
);
|
||||
|
||||
private int $id = 0;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
if ($pageParam)
|
||||
$this->id = intVal($pageParam);
|
||||
else if ($this->assertGET('profile'))
|
||||
$this->id = $this->_get['profile'];
|
||||
else
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
// show editor
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
|
||||
protected static function checkProfile(string $profile) : ?int
|
||||
{
|
||||
if (!preg_match('/^([a-z]+)\.([a-z_]+)\.(.+)$/i', $profile, $m))
|
||||
return null;
|
||||
|
||||
[, $region, $realm, $char] = $m;
|
||||
|
||||
$realms = Profiler::getRealms();
|
||||
if ($rId = array_find_key($realms, fn($x) => $x['region'] == $region && $x['name'] == $realm))
|
||||
return DB::Aowow()->selectCell('SELECT `id` FROM ?_profiler_profiles WHERE `realm` = ?d AND `custom` = 0 AND `name` = ?', $rId, urldecode($char)) ?: null;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -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 = [];
|
||||
@@ -50,6 +49,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
private int $firstRank = 0;
|
||||
private array $modelInfo = [];
|
||||
private array $difficulties = [];
|
||||
private int $mapType = 0;
|
||||
|
||||
public function __construct(string $id)
|
||||
{
|
||||
@@ -68,15 +68,20 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
if ($jsg = $this->subject->getJSGlobals(GLOBALINFO_ANY, $extra))
|
||||
$this->extendGlobalData($jsg, $extra);
|
||||
|
||||
$this->modelInfo = $this->subject->getModelInfo($this->typeId);
|
||||
$this->difficulties = DB::Aowow()->selectRow( // has difficulty versions of itself
|
||||
$this->modelInfo = $this->subject->getModelInfo($this->typeId);
|
||||
if ($spelldifficulty = DB::Aowow()->select( // has difficulty versions of itself
|
||||
'SELECT `normal10` AS "0", `normal25` AS "1",
|
||||
`heroic10` AS "2", `heroic25` AS "3"
|
||||
`heroic10` AS "2", `heroic25` AS "3",
|
||||
`mapType` AS ARRAY_KEY
|
||||
FROM ?_spelldifficulty
|
||||
WHERE `normal10` = ?d OR `normal25` = ?d OR
|
||||
`heroic10` = ?d OR `heroic25` = ?d',
|
||||
$this->typeId, $this->typeId, $this->typeId, $this->typeId
|
||||
);
|
||||
))
|
||||
{
|
||||
$this->mapType = key($spelldifficulty);
|
||||
$this->difficulties = array_pop($spelldifficulty);
|
||||
}
|
||||
|
||||
// returns self or firstRank
|
||||
if ($fr = DB::World()->selectCell('SELECT `first_spell_id` FROM spell_ranks WHERE `spell_id` = ?d', $this->typeId))
|
||||
@@ -161,13 +166,6 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$this->createReagentList();
|
||||
|
||||
|
||||
/**********************/
|
||||
/* Spell Scaling Info */
|
||||
/**********************/
|
||||
|
||||
$this->createScalingData();
|
||||
|
||||
|
||||
/******************/
|
||||
/* Required Items */
|
||||
/******************/
|
||||
@@ -236,7 +234,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$this->castTime = $this->subject->createCastTimeForCurrent(false, false);
|
||||
$this->level = $this->subject->getField('spellLevel');
|
||||
$this->rangeName = $this->subject->getField('rangeText', true);
|
||||
$this->gcd = Util::formatTime($this->subject->getField('startRecoveryTime'));
|
||||
$this->gcd = DateTime::formatTimeElapsedFloat($this->subject->getField('startRecoveryTime'));
|
||||
$this->school = $this->fmtStaffTip(Lang::getMagicSchools($this->subject->getField('schoolMask')), Util::asHex($this->subject->getField('schoolMask')));
|
||||
$this->dispel = $this->subject->getField('dispelType') ? Lang::game('dt', $this->subject->getField('dispelType')) : null;
|
||||
$this->mechanic = $this->subject->getField('mechanic') ? Lang::game('me', $this->subject->getField('mechanic')) : null;
|
||||
@@ -266,12 +264,12 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$this->stances = Lang::getStances($this->subject->getField('stanceMask'));
|
||||
|
||||
if (($_ = $this->subject->getField('recoveryTime')) && $_ > 0)
|
||||
$this->cooldown = Util::formatTime($_);
|
||||
$this->cooldown = DateTime::formatTimeElapsedFloat($_);
|
||||
else if (($_ = $this->subject->getField('recoveryCategory')) && $_ > 0)
|
||||
$this->cooldown = Util::formatTime($_);
|
||||
$this->cooldown = DateTime::formatTimeElapsedFloat($_);
|
||||
|
||||
if (($_ = $this->subject->getField('duration')) && $_ > 0)
|
||||
$this->duration = Util::formatTime($_);
|
||||
$this->duration = DateTime::formatTimeElapsedFloat($_);
|
||||
|
||||
|
||||
/**************/
|
||||
@@ -449,43 +447,32 @@ 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)]
|
||||
);
|
||||
|
||||
if ($this->difficulties)
|
||||
$conditions = ['OR', ['AND', ...$conditions], ['AND', ['s.id', $this->difficulties], ['s.id', $this->typeId, '!']]];
|
||||
|
||||
$saSpells = new SpellList($conditions);
|
||||
if (!$saSpells->error)
|
||||
{
|
||||
$data = $saSpells->getListviewData();
|
||||
if ($this->difficulties) // needs a way to distinguish between dungeon and raid :x; creature using this -> map -> areaType?
|
||||
if ($this->difficulties)
|
||||
{
|
||||
$saE = ['$Listview.extraCols.mode'];
|
||||
|
||||
foreach ($data as $id => &$d)
|
||||
{
|
||||
$d['modes'] = ['mode' => 0];
|
||||
|
||||
if ($this->difficulties[0] == $id) // b0001000
|
||||
if (($modeBit = array_search($id, $this->difficulties)) !== false)
|
||||
{
|
||||
if (!$this->difficulties[2] && !$this->difficulties[3])
|
||||
$d['modes']['mode'] |= 0x2;
|
||||
if ($this->mapType)
|
||||
$d['modes'] = ['mode' => 1 << ($modeBit + 3)];
|
||||
else
|
||||
$d['modes']['mode'] |= 0x8;
|
||||
$d['modes'] = ['mode' => 2 - $modeBit];
|
||||
}
|
||||
|
||||
if ($this->difficulties[1] == $id) // b0010000
|
||||
{
|
||||
if (!$this->difficulties[2] && !$this->difficulties[3])
|
||||
$d['modes']['mode'] |= 0x1;
|
||||
else
|
||||
$d['modes']['mode'] |= 0x10;
|
||||
}
|
||||
|
||||
if ($this->difficulties[2] == $id) // b0100000
|
||||
$d['modes']['mode'] |= 0x20;
|
||||
|
||||
if ($this->difficulties[3] == $id) // b1000000
|
||||
$d['modes']['mode'] |= 0x40;
|
||||
else
|
||||
$d['modes'] = ['mode' => 0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,7 +521,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 +546,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 +565,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 +587,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 +643,54 @@ 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);
|
||||
$spellLoot = new Loot();
|
||||
|
||||
if ($spellLoot->getByContainer(LOOT_SPELL, $this->subject->id) || $extraItem)
|
||||
// spell_loot_template
|
||||
$spellLoot = new LootByContainer();
|
||||
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,
|
||||
'id' => 'contains',
|
||||
'hiddenCols' => ['side', 'slot', 'source', 'reqlevel'],
|
||||
'extraCols' => array_unique($extraCols)
|
||||
'data' => $spellLoot->getResult(),
|
||||
'name' => '$LANG.tab_contains',
|
||||
'id' => 'contains',
|
||||
'hiddenCols' => ['side', 'slot', 'source', 'reqlevel'],
|
||||
'extraCols' => array_unique($extraCols),
|
||||
'computeDataFunc' => '$Listview.funcBox.initLootTable'
|
||||
), 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 +806,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);
|
||||
@@ -848,6 +835,9 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
if ($auras = DB::World()->selectCol('SELECT `entry` FROM creature_template_addon WHERE `auras` REGEXP ?', '\\b'.$this->typeId.'\\b'))
|
||||
$conditions[] = ['id', $auras];
|
||||
|
||||
if ($spellClick = DB::World()->selectCol('SELECT `npc_entry` FROM npc_spellclick_spells WHERE `spell_id` = ?d', $this->typeId))
|
||||
$conditions[] = ['id', $spellClick];
|
||||
|
||||
$ubCreature = new CreatureList($conditions);
|
||||
if (!$ubCreature->error)
|
||||
{
|
||||
@@ -1000,7 +990,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
// tab: taught by npc
|
||||
if ($this->subject->getSources($s) && in_array(SRC_TRAINER, $s))
|
||||
if ($this->subject->getRawSource(SRC_TRAINER))
|
||||
{
|
||||
$trainers = DB::World()->select(
|
||||
'SELECT cdt.`CreatureId` AS ARRAY_KEY, ts.`ReqSkillLine` AS "reqSkillId", ts.`ReqSkillRank` AS "reqSkillValue", ts.`ReqLevel` AS "reqLevel", ts.`ReqAbility1` AS "reqSpellId1", ts.`reqAbility2` AS "reqSpellId2"
|
||||
@@ -1057,15 +1047,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 +1067,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 +1091,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 +1156,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)
|
||||
@@ -1174,7 +1213,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
// tab: conditions
|
||||
$cnd = new Conditions();
|
||||
$cnd->getBySourceEntry($this->typeId, Conditions::SRC_SPELL_IMPLICIT_TARGET, Conditions::SRC_SPELL, Conditions::SRC_SPELL_CLICK_EVENT, Conditions::SRC_VEHICLE_SPELL, Conditions::SRC_SPELL_PROC)
|
||||
$cnd->getBySource([Conditions::SRC_SPELL_IMPLICIT_TARGET, Conditions::SRC_SPELL, Conditions::SRC_SPELL_CLICK_EVENT, Conditions::SRC_VEHICLE_SPELL, Conditions::SRC_SPELL_PROC], entry: $this->typeId)
|
||||
->getByCondition(Type::SPELL, $this->typeId)
|
||||
->prepare();
|
||||
if ($tab = $cnd->toListviewTab())
|
||||
@@ -1191,7 +1230,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 +1251,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 +1375,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 +1386,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 +1414,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 +1433,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 +1455,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 +1501,7 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->subject->isHealingSpell())
|
||||
if ($this->subject->isScalableHealingSpell())
|
||||
$castingTime *= 1.88;
|
||||
|
||||
// SPELL_SCHOOL_MASK_NORMAL
|
||||
@@ -1468,7 +1511,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 +1573,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 +1605,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 +1622,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 +1635,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 +1648,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)
|
||||
@@ -1638,16 +1702,16 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
$_footer['radius'] = Lang::spell('_radius').$this->subject->getField('effect'.$i.'RadiusMax').' '.Lang::spell('_distUnit');
|
||||
|
||||
if ($this->subject->getField('effect'.$i.'Periode') > 0)
|
||||
$_footer['interval'] = Lang::spell('_interval').Util::formatTime($this->subject->getField('effect'.$i.'Periode'));
|
||||
$_footer['interval'] = Lang::spell('_interval').DateTime::formatTimeElapsedFloat($this->subject->getField('effect'.$i.'Periode'));
|
||||
|
||||
if ($_ = $this->subject->getField('effect'.$i.'Mechanic'))
|
||||
$_footer['mechanic'] = Lang::game('mechanic').Lang::main('colon').Lang::game('me', $_);
|
||||
|
||||
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)]);
|
||||
$_footer['procCD'] = Lang::game('cooldown', [DateTime::formatTimeElapsed($procData['cooldown'] * 1000)]);
|
||||
}
|
||||
|
||||
// Effect Name
|
||||
@@ -1892,6 +1956,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 +2032,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 +2203,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 +2278,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 +2309,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 +2326,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 +2351,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 +2398,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 .= ' ('.$_.')';
|
||||
|
||||
@@ -2333,29 +2422,43 @@ class SpellBaseResponse extends TemplateResponse implements ICache
|
||||
}
|
||||
|
||||
// accquisition.. 10: starter spell; 7: discovery
|
||||
if ($this->subject->getSources($s))
|
||||
{
|
||||
if (in_array(SRC_STARTER, $s))
|
||||
$infobox[] = Lang::spell('starter');
|
||||
else if (in_array(SRC_DISCOVERY, $s))
|
||||
$infobox[] = Lang::spell('discovered');
|
||||
}
|
||||
if ($this->subject->getRawSource(SRC_STARTER))
|
||||
$infobox[] = Lang::spell('starter');
|
||||
else if ($this->subject->getRawSource(SRC_DISCOVERY))
|
||||
$infobox[] = Lang::spell('discovered');
|
||||
|
||||
// training cost
|
||||
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)
|
||||
$infobox[] = Lang::game('mode').Lang::game('modes', $n);
|
||||
$infobox[] = Lang::game('mode').Lang::game('modes', $this->mapType, $n);
|
||||
|
||||
// Creature Type from Aura: Shapeshift
|
||||
foreach ($this->modelInfo as $mI)
|
||||
@@ -2375,7 +2478,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,7 +42,11 @@ 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
|
||||
{
|
||||
@@ -70,14 +74,16 @@ class UserBaseResponse extends TemplateResponse
|
||||
}
|
||||
|
||||
if ($this->user['joinDate'])
|
||||
$infobox[] = Lang::user('joinDate') . '[tooltip name=joinDate]'. date('l, G:i:s', $this->user['joinDate']). '[/tooltip][span class=tip tooltip=joinDate]'. date(Lang::main('dateFmtShort'), $this->user['joinDate']). '[/span]';
|
||||
$infobox[] = Lang::user('joinDate') . '[tooltip name=joinDate]'. date('l, G:i:s', $this->user['joinDate']). '[/tooltip][span class=tip tooltip=joinDate]'.(new DateTime())->formatDate($this->user['joinDate']). '[/span]';
|
||||
if ($this->user['prevLogin'])
|
||||
$infobox[] = Lang::user('lastLogin') . '[tooltip name=lastLogin]'.date('l, G:i:s', $this->user['prevLogin']).'[/tooltip][span class=tip tooltip=lastLogin]'.date(Lang::main('dateFmtShort'), $this->user['prevLogin']).'[/span]';
|
||||
$infobox[] = Lang::user('lastLogin') . '[tooltip name=lastLogin]'.date('l, G:i:s', $this->user['prevLogin']).'[/tooltip][span class=tip tooltip=lastLogin]'.(new DateTime())->formatDate($this->user['prevLogin']).'[/span]';
|
||||
if ($groups)
|
||||
$infobox[] = Lang::user('userGroups') . implode(', ', $groups);
|
||||
|
||||
$infobox[] = Lang::user('consecVisits'). $this->user['consecutiveVisits'];
|
||||
$infobox[] = Lang::main('siteRep') . Lang::nf($this->user['sumRep']);
|
||||
|
||||
if ($this->user['sumRep'])
|
||||
$infobox[] = Lang::main('siteRep') . Lang::nf($this->user['sumRep']);
|
||||
|
||||
if ($infobox)
|
||||
$this->infobox = new InfoboxMarkup($infobox, ['allow' => Markup::CLASS_STAFF], 'infobox-contents0');
|
||||
@@ -229,30 +235,44 @@ 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);
|
||||
}
|
||||
|
||||
// signatures
|
||||
/* $this->lvTabs->addListviewTab(new Listview(array(
|
||||
* 'id' => 'signatures',
|
||||
* 'name' => '$LANG.tab_signatures',
|
||||
* 'hiddenCols' => ['name','faction','location','guild'],
|
||||
* 'extraCols' => ['$Listview.extraCols.signature'],
|
||||
* 'onBeforeCreate' => '$Listview.funcBox.beforeUserSignatures',
|
||||
* 'data' => [ ProfileList->getListviewData() ] // no extra signature related data observed
|
||||
* ), 'profile'));
|
||||
*/
|
||||
}
|
||||
|
||||
// My Guides
|
||||
@@ -280,6 +300,9 @@ class UserBaseResponse extends TemplateResponse
|
||||
|
||||
[$sum, $nRatings] = $co;
|
||||
|
||||
if (!$sum)
|
||||
return null;
|
||||
|
||||
return Lang::user('comments').$sum.($nRatings ? ' [small]([tooltip=tooltip_totalratings]'.$nRatings.'[/tooltip])[/small]' : '');
|
||||
}
|
||||
|
||||
@@ -295,6 +318,9 @@ class UserBaseResponse extends TemplateResponse
|
||||
|
||||
[$sum, $nSticky, $nPending] = $ss;
|
||||
|
||||
if (!$sum)
|
||||
return null;
|
||||
|
||||
$buff = [];
|
||||
if ($nSticky || $nPending)
|
||||
{
|
||||
@@ -323,6 +349,9 @@ class UserBaseResponse extends TemplateResponse
|
||||
|
||||
[$sum, $nSticky, $nPending] = $vi;
|
||||
|
||||
if (!$sum)
|
||||
return null;
|
||||
|
||||
$buff = [];
|
||||
if ($nSticky || $nPending)
|
||||
{
|
||||
@@ -355,6 +384,9 @@ class UserBaseResponse extends TemplateResponse
|
||||
if ($nReplies)
|
||||
$buff[] = '[tooltip=replies]'.$nReplies.'[/tooltip]';
|
||||
|
||||
if (!$buff)
|
||||
return null;
|
||||
|
||||
return Lang::user('posts').($nTopics + $nReplies).($buff ? ' [small]('.implode(' + ', $buff).')[/small]' : '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -558,13 +565,55 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
|
||||
|
||||
$this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"], 'tabsRelated', true);
|
||||
|
||||
// tab: Drops
|
||||
if (in_array($this->subject->getField('category'), [MAP_TYPE_DUNGEON, MAP_TYPE_RAID]))
|
||||
{
|
||||
// Issue 1 - if the bosses drop items that are also sold by vendors moreZoneId will be 0 as vendor location and boss location are likely in conflict with each other
|
||||
// Issue 2 - if the boss/chest isn't spawned the loot will not show up
|
||||
$items = new ItemList(array(Cfg::get('SQL_LIMIT_NONE'), ['src.moreZoneId', $this->typeId], ['src.src2', 0, '>'], ['quality', ITEM_QUALITY_UNCOMMON, '>=']), ['calcTotal' => true]);
|
||||
$data = $items->getListviewData();
|
||||
$subTabs = false;
|
||||
foreach ($items->iterate() as $id => $__)
|
||||
{
|
||||
$src = $items->getRawSource(SRC_DROP);
|
||||
$map = ($items->getField('moreMask') ?: 0) & (SRC_FLAG_DUNGEON_DROP | SRC_FLAG_RAID_DROP);
|
||||
if (!$src || !$map)
|
||||
continue;
|
||||
|
||||
$subTabs = true;
|
||||
|
||||
if ($map & SRC_FLAG_RAID_DROP)
|
||||
$mode = ($src[0] << 3);
|
||||
else
|
||||
$mode = ($src[0] & 0x1 ? 0x2 : 0) | ($src[0] & 0x2 ? 0x1 : 0);
|
||||
|
||||
$data[$id] += ['modes' => ['mode' => $mode]];
|
||||
}
|
||||
|
||||
$tabData = array(
|
||||
'data' => $data,
|
||||
'id' => 'drops',
|
||||
'name' => '$LANG.tab_drops',
|
||||
'extraCols' => $subTabs ? ['$Listview.extraCols.mode'] : null,
|
||||
'computeDataFunc' => '$Listview.funcBox.initLootTable',
|
||||
'onAfterCreate' => $subTabs ? '$Listview.funcBox.addModeIndicator' : null
|
||||
);
|
||||
|
||||
if (!is_null(ItemListFilter::getCriteriaIndex(16, $this->typeId)))
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?items&filter=cr=16;crs='.$this->typeId.';crv=0');
|
||||
|
||||
$this->extendGlobalData($items->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview($tabData, ItemList::$brickFile));
|
||||
}
|
||||
|
||||
// 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 +626,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 +665,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 +707,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));
|
||||
@@ -669,8 +725,8 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
|
||||
// tab: achievements
|
||||
|
||||
// tab: fished in zone
|
||||
$fish = new Loot();
|
||||
if ($fish->getByContainer(LOOT_FISHING, $this->typeId))
|
||||
$fish = new LootByContainer();
|
||||
if ($fish->getByContainer(Loot::FISHING, [$this->typeId]))
|
||||
{
|
||||
$this->extendGlobalData($fish->jsGlobals);
|
||||
$xCols = array_merge(['$Listview.extraCols.percent'], $fish->extraCols);
|
||||
@@ -682,12 +738,13 @@ class ZoneBaseResponse extends TemplateResponse implements ICache
|
||||
$note = sprintf(Util::$lvTabNoteString, Lang::zone('fishingSkill'), Lang::formatSkillBreakpoints(Game::getBreakpointsForSkill(SKILL_FISHING, $skill), Lang::FMT_HTML));
|
||||
|
||||
$this->lvTabs->addListviewTab(new Listview(array(
|
||||
'data' => $fish->getResult(),
|
||||
'name' => '$LANG.tab_fishing',
|
||||
'id' => 'fishing',
|
||||
'extraCols' => array_unique($xCols),
|
||||
'hiddenCols' => ['side'],
|
||||
'note' => $note
|
||||
'data' => $fish->getResult(),
|
||||
'name' => '$LANG.tab_fishing',
|
||||
'id' => 'fishing',
|
||||
'extraCols' => array_unique($xCols),
|
||||
'hiddenCols' => ['side'],
|
||||
'note' => $note,
|
||||
'computeDataFunc' => '$Listview.funcBox.initLootTable'
|
||||
), ItemList::$brickFile));
|
||||
}
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -221,29 +221,26 @@ class Conditions
|
||||
/* IN */
|
||||
/******/
|
||||
|
||||
public function getBySourceEntry(int $entry, int ...$srcType) : self
|
||||
public function getBySource(int|array $type, int|array $group = 0, int|array $entry = 0, int|array $id = 0) : self
|
||||
{
|
||||
if ($group)
|
||||
$group = is_int($group) ? [$group] : array_map('intVal', $group);
|
||||
if ($entry)
|
||||
$entry = is_int($entry) ? [$entry] : array_map('intVal', $entry);
|
||||
if ($id)
|
||||
$id = is_int($id) ? [$id] : array_map('intVal', $id);
|
||||
if ($type)
|
||||
$type = is_int($type) ? [$type] : array_map('intVal', $type);
|
||||
else
|
||||
return $this;
|
||||
|
||||
$this->rows = array_merge($this->rows, DB::World()->select(
|
||||
'SELECT `SourceTypeOrReferenceId`, `SourceEntry`, `SourceGroup`, `SourceId`, `ElseGroup`,
|
||||
`ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`
|
||||
FROM conditions
|
||||
WHERE `SourceTypeOrReferenceId` IN (?a) AND `SourceEntry` = ?d
|
||||
WHERE `SourceTypeOrReferenceId` IN (?a){ AND `SourceGroup` IN (?a)}{ AND `SourceEntry` IN (?a)}{ AND `SourceId` IN (?a)}
|
||||
ORDER BY `SourceTypeOrReferenceId`, `SourceEntry`, `SourceGroup`, `ElseGroup` ASC',
|
||||
$srcType, $entry
|
||||
));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBySourceGroup(int $group, int ...$srcType) : self
|
||||
{
|
||||
$this->rows = array_merge($this->rows, DB::World()->select(
|
||||
'SELECT `SourceTypeOrReferenceId`, `SourceEntry`, `SourceGroup`, `SourceId`, `ElseGroup`,
|
||||
`ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`
|
||||
FROM conditions
|
||||
WHERE `SourceTypeOrReferenceId` IN (?a) AND `SourceGroup` = ?d
|
||||
ORDER BY `SourceTypeOrReferenceId`, `SourceEntry`, `SourceGroup`, `ElseGroup` ASC',
|
||||
$srcType, $group
|
||||
$type, $group ?: DBSIMPLE_SKIP, $entry ?: DBSIMPLE_SKIP, $id ?: DBSIMPLE_SKIP
|
||||
));
|
||||
|
||||
return $this;
|
||||
@@ -386,6 +383,14 @@ class Conditions
|
||||
return $success;
|
||||
}
|
||||
|
||||
public function toMarkupTag() : string
|
||||
{
|
||||
if (!$this->result)
|
||||
return '';
|
||||
|
||||
return '[condition]' . json_encode($this->result, JSON_NUMERIC_CHECK) . '[/condition]';
|
||||
}
|
||||
|
||||
public function getJsGlobals() : array
|
||||
{
|
||||
return $this->jsGlobals;
|
||||
@@ -398,22 +403,22 @@ class Conditions
|
||||
|
||||
public static function lootTableToConditionSource(string $lootTable) : int
|
||||
{
|
||||
switch ($lootTable)
|
||||
return match ($lootTable)
|
||||
{
|
||||
case LOOT_FISHING: return self::SRC_FISHING_LOOT_TEMPLATE;
|
||||
case LOOT_CREATURE: return self::SRC_CREATURE_LOOT_TEMPLATE;
|
||||
case LOOT_GAMEOBJECT: return self::SRC_GAMEOBJECT_LOOT_TEMPLATE;
|
||||
case LOOT_ITEM: return self::SRC_ITEM_LOOT_TEMPLATE;
|
||||
case LOOT_DISENCHANT: return self::SRC_DISENCHANT_LOOT_TEMPLATE;
|
||||
case LOOT_PROSPECTING: return self::SRC_PROSPECTING_LOOT_TEMPLATE;
|
||||
case LOOT_MILLING: return self::SRC_MILLING_LOOT_TEMPLATE;
|
||||
case LOOT_PICKPOCKET: return self::SRC_PICKPOCKETING_LOOT_TEMPLATE;
|
||||
case LOOT_SKINNING: return self::SRC_SKINNING_LOOT_TEMPLATE;
|
||||
case LOOT_MAIL: return self::SRC_MAIL_LOOT_TEMPLATE;
|
||||
case LOOT_SPELL: return self::SRC_SPELL_LOOT_TEMPLATE;
|
||||
case LOOT_REFERENCE: return self::SRC_REFERENCE_LOOT_TEMPLATE;
|
||||
default: return self::SRC_NONE;
|
||||
}
|
||||
Loot::FISHING => self::SRC_FISHING_LOOT_TEMPLATE,
|
||||
Loot::CREATURE => self::SRC_CREATURE_LOOT_TEMPLATE,
|
||||
Loot::GAMEOBJECT => self::SRC_GAMEOBJECT_LOOT_TEMPLATE,
|
||||
Loot::ITEM => self::SRC_ITEM_LOOT_TEMPLATE,
|
||||
Loot::DISENCHANT => self::SRC_DISENCHANT_LOOT_TEMPLATE,
|
||||
Loot::PROSPECTING => self::SRC_PROSPECTING_LOOT_TEMPLATE,
|
||||
Loot::MILLING => self::SRC_MILLING_LOOT_TEMPLATE,
|
||||
Loot::PICKPOCKET => self::SRC_PICKPOCKETING_LOOT_TEMPLATE,
|
||||
Loot::SKINNING => self::SRC_SKINNING_LOOT_TEMPLATE,
|
||||
Loot::MAIL => self::SRC_MAIL_LOOT_TEMPLATE,
|
||||
Loot::SPELL => self::SRC_SPELL_LOOT_TEMPLATE,
|
||||
Loot::REFERENCE => self::SRC_REFERENCE_LOOT_TEMPLATE,
|
||||
default => self::SRC_NONE
|
||||
};
|
||||
}
|
||||
|
||||
public static function extendListviewRow(array &$lvRow, int $srcType, int $groupKey, array $condition) : bool
|
||||
@@ -486,9 +491,9 @@ class Conditions
|
||||
$this->jsGlobals[$grp][$sGroup] = $sGroup;
|
||||
if (is_int($entry))
|
||||
$this->jsGlobals[$entry][$sEntry] = $sEntry;
|
||||
// Note: sourceId currently has no typed content
|
||||
// if (is_int($id))
|
||||
// $this->jsGlobals[$id][$sId] = $sId;
|
||||
// Note: sourceId currently has no typed content
|
||||
// if (is_int($id))
|
||||
// $this->jsGlobals[$id][$sId] = $sId;
|
||||
|
||||
// more checks? not all sources can retarget
|
||||
$cTarget = min(1, max(0, $cTarget));
|
||||
|
||||
@@ -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) => DateTime::formatTimeElapsed($x));
|
||||
|
||||
$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
|
||||
@@ -36,11 +32,17 @@ trait SmartHelper
|
||||
if (!$time)
|
||||
return '';
|
||||
|
||||
return Util::formatTime($time * ($isMilliSec ? 1 : 1000), false);
|
||||
return DateTime::formatTimeElapsedFloat($time * ($isMilliSec ? 1 : 1000));
|
||||
}
|
||||
|
||||
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,14 +250,23 @@ 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 = [];
|
||||
private array $result = [];
|
||||
private array $tabs = [];
|
||||
private array $itr = [];
|
||||
private array $quotes = [];
|
||||
|
||||
private array $quotes = [];
|
||||
public string $css = <<<CSS
|
||||
#smartai-generic .grid { clear:left; display: grid; }
|
||||
#smartai-generic .tabbed-contents { padding:0px; clear:left; }
|
||||
#smartai-generic .grid thead,
|
||||
#smartai-generic .grid tbody,
|
||||
#smartai-generic .grid tr { display: contents; }
|
||||
#sai { display: grid; }
|
||||
CSS;
|
||||
|
||||
// misc data
|
||||
public readonly int $baseEntry; // I'm a timed action list belonging to this entry
|
||||
@@ -231,24 +279,28 @@ class SmartAI
|
||||
$this->title = $miscData['title'] ?? '';
|
||||
$this->teleportTargetArea = $miscData['teleportTargetArea'] ?? 0;
|
||||
|
||||
if ($this->baseEntry) // my parent handles base css
|
||||
$this->css = '';
|
||||
|
||||
$raw = DB::World()->select(
|
||||
'SELECT `id`, `link`,
|
||||
`event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`,
|
||||
`action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`,
|
||||
`target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`
|
||||
FROM smart_scripts
|
||||
WHERE `entryorguid` = ?d AND `source_type` = ?d
|
||||
ORDER BY `id` ASC',
|
||||
'SELECT `id`, `link`,
|
||||
`event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`,
|
||||
`action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`,
|
||||
`target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`
|
||||
FROM smart_scripts
|
||||
WHERE `entryorguid` = ?d AND `source_type` = ?d
|
||||
ORDER BY `id` ASC',
|
||||
$this->entry, $this->srcType);
|
||||
|
||||
foreach ($raw as $r)
|
||||
{
|
||||
$this->rawData[$r['id']] = array(
|
||||
'id' => $r['id'],
|
||||
'link' => $r['link'],
|
||||
'event' => new SmartEvent($r['id'], $r['event_type'], $r['event_phase_mask'], $r['event_chance'], $r['event_flags'], [$r['event_param1'], $r['event_param2'], $r['event_param3'], $r['event_param4'], $r['event_param5']], $this),
|
||||
'action' => new SmartAction($r['id'], $r['action_type'], [$r['action_param1'], $r['action_param2'], $r['action_param3'], $r['action_param4'], $r['action_param5'], $r['action_param6']], $this),
|
||||
'target' => new SmartTarget($r['id'], $r['target_type'], [$r['target_param1'], $r['target_param2'], $r['target_param3'], $r['target_param4']], [$r['target_x'], $r['target_y'], $r['target_z'], $r['target_o']], $this)
|
||||
'id' => $r['id'],
|
||||
'link' => $r['link'],
|
||||
'event' => new SmartEvent($r['id'], $r['event_type'], $r['event_phase_mask'], $r['event_chance'], $r['event_flags'], [$r['event_param1'], $r['event_param2'], $r['event_param3'], $r['event_param4'], $r['event_param5']], $this),
|
||||
'action' => new SmartAction($r['id'], $r['action_type'], [$r['action_param1'], $r['action_param2'], $r['action_param3'], $r['action_param4'], $r['action_param5'], $r['action_param6']], $this),
|
||||
'target' => new SmartTarget($r['id'], $r['target_type'], [$r['target_param1'], $r['target_param2'], $r['target_param3'], $r['target_param4']], [$r['target_x'], $r['target_y'], $r['target_z'], $r['target_o']], $this),
|
||||
'condition' => (new Conditions())->getBySource(Conditions::SRC_SMART_EVENT, $r['id'] + 1, $entry, $srcType)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -579,10 +631,9 @@ class SmartAI
|
||||
if ($this->result)
|
||||
return true;
|
||||
|
||||
$hidePhase =
|
||||
$hideChance = true;
|
||||
$visibleCols = (1 << 0) | (1 << 2) | (1 << 4);
|
||||
|
||||
foreach ($this->iterate() as $id => $__)
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$rowIdx = Util::createHash(8);
|
||||
|
||||
@@ -596,53 +647,60 @@ class SmartAI
|
||||
$evtBody = str_replace(['#target#', '#rowIdx#'], [$this->itr['target']->process(), $rowIdx], $evtBody);
|
||||
$actBody = str_replace(['#target#', '#rowIdx#'], [$this->itr['target']->process(), $rowIdx], $actBody);
|
||||
|
||||
if (!$this->itr['event']->hasPhases())
|
||||
$hidePhase = false;
|
||||
if ($this->itr['event']->hasPhases())
|
||||
$visibleCols |= (1 << 1);
|
||||
|
||||
if ($this->itr['event']->chance != 100)
|
||||
$hideChance = false;
|
||||
$visibleCols |= (1 << 3);
|
||||
|
||||
if ($this->itr['condition']->prepare())
|
||||
{
|
||||
$visibleCols |= (1 << 5);
|
||||
Util::mergeJsGlobals($this->jsGlobals, $this->itr['condition']->getJsGlobals());
|
||||
}
|
||||
|
||||
$this->result[] = array(
|
||||
$this->itr['id'],
|
||||
implode(', ', Util::mask2bits($this->itr['event']->phaseMask, 1)),
|
||||
$evtBody.($evtFooter ? '[div float=right margin=0px clear=both][i][small class=q0]'.$evtFooter.'[/small][/i][/div]' : null),
|
||||
$evtBody.($evtFooter ? '[div float=right margin=0px clear=both width=100% align=right][i][small class=q0]'.$evtFooter.'[/small][/i][/div]' : ''),
|
||||
$this->itr['event']->chance.'%',
|
||||
$actBody.($actFooter ? '[div float=right margin=0px clear=both][i][small class=q0]'.$actFooter.'[/small][/i][/div]' : null)
|
||||
$actBody.($actFooter ? '[div float=right margin=0px clear=both width=100% align=right][i][small class=q0]'.$actFooter.'[/small][/i][/div]' : ''),
|
||||
$this->itr['condition']->toMarkupTag()
|
||||
);
|
||||
}
|
||||
|
||||
$th = array(
|
||||
'#' => 16,
|
||||
'Phase' => 32,
|
||||
'Event' => 350,
|
||||
'Chance' => 24,
|
||||
'Action' => 0
|
||||
['#' , '24px'],
|
||||
['Phase', '48px'],
|
||||
['Event', '30%%'],
|
||||
['Chance', '60px'],
|
||||
['Action', 'auto'],
|
||||
['Condition', 'auto']
|
||||
);
|
||||
|
||||
if ($hidePhase)
|
||||
for ($i = 0, $j = count($th); $i < $j; $i++)
|
||||
{
|
||||
unset($th['Phase']);
|
||||
foreach ($this->result as &$r)
|
||||
unset($r[1]);
|
||||
}
|
||||
unset($r);
|
||||
if ($visibleCols & (1 << $i))
|
||||
continue;
|
||||
|
||||
if ($hideChance)
|
||||
{
|
||||
unset($th['Chance']);
|
||||
unset($th[$i]);
|
||||
foreach ($this->result as &$r)
|
||||
unset($r[3]);
|
||||
}
|
||||
unset($r);
|
||||
unset($r[$i]);
|
||||
|
||||
$tbl = '[tr]';
|
||||
foreach ($th as $n => $w)
|
||||
$tbl .= '[td header '.($w ? 'width='.$w.'px' : null).']'.$n.'[/td]';
|
||||
$tbl .= '[/tr]';
|
||||
unset($r);
|
||||
}
|
||||
|
||||
$tblId = Util::createHash(12);
|
||||
|
||||
$this->css .= "\n#tbl-".$tblId." { grid-template-columns: ".implode(' ', array_column($th, 1))."; }";
|
||||
|
||||
$tbl = '[tr]' . array_reduce(array_column($th, 0), fn($out, $n) => $out .= '[td header]'.$n.'[/td]', '') . '[/tr]';
|
||||
|
||||
foreach ($this->result as $r)
|
||||
$tbl .= '[tr][td]'.implode('[/td][td]', $r).'[/td][/tr]';
|
||||
|
||||
$tbl = '[table id=tbl-'.$tblId.' class=grid]'.$tbl.'[/table]';
|
||||
|
||||
if ($this->srcType == self::SRC_TYPE_ACTIONLIST)
|
||||
$this->tabs[$this->entry] = $tbl;
|
||||
else
|
||||
@@ -658,16 +716,16 @@ class SmartAI
|
||||
if (!$this->rawData)
|
||||
return null;
|
||||
|
||||
$wrapper = '[table class=grid width=940px]%s[/table]';
|
||||
$return = '[style]#smartai-generic .grid { clear:left; } #smartai-generic .tabbed-contents { padding:0px; clear:left; }[/style][pad][h3][toggler id=sai]SmartAI'.$this->title.'[/toggler][/h3][div id=sai clear=left]%s[/div]';
|
||||
$wrapper = '%s';
|
||||
$return = '[style]'.strtr($this->css, "\n", ' ').'[/style][pad][h3][toggler id=sai]SmartAI'.$this->title.'[/toggler][/h3][div id=sai clear=left]%s[/div]';
|
||||
$tabs = '';
|
||||
if (count($this->tabs) > 1)
|
||||
{
|
||||
$wrapper = '[tabs name=sai width=942px]%s[/tabs]';
|
||||
$wrapper = '[tabs name=sai]%s[/tabs]';
|
||||
$return = "[script]function TalTabClick(id) { $('#dsf67g4d-sai').find('[href=\'#sai-actionlist-' + id + '\']').click(); }[/script]" . $return;
|
||||
foreach ($this->tabs as $guid => $data)
|
||||
{
|
||||
$buff = '[tab name="'.($guid ? 'ActionList #'.$guid : 'Main').'"][table class=grid width=940px]'.$data.'[/table][/tab]';
|
||||
$buff = '[tab name="'.($guid ? 'ActionList #'.$guid : 'Main').'"]'.$data.'[/tab]';
|
||||
if ($guid)
|
||||
$tabs .= $buff;
|
||||
else
|
||||
|
||||
@@ -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])
|
||||
@@ -562,6 +562,8 @@ class SmartAction
|
||||
$tal = new SmartAI(SmartAI::SRC_TYPE_ACTIONLIST, $this->param[0], ['baseEntry' => $this->smartAI->getEntry()]);
|
||||
$tal->prepare();
|
||||
|
||||
$this->smartAI->css .= $tal->css;
|
||||
|
||||
Util::mergeJsGlobals($this->jsGlobals, $tal->getJSGlobals());
|
||||
|
||||
foreach ($tal->getTabs() as $guid => $tt)
|
||||
@@ -587,6 +589,8 @@ class SmartAction
|
||||
$tal = new SmartAI(SmartAI::SRC_TYPE_ACTIONLIST, $this->param[$i], ['baseEntry' => $this->smartAI->getEntry()]);
|
||||
$tal->prepare();
|
||||
|
||||
$this->smartAI->css .= $tal->css;
|
||||
|
||||
Util::mergeJsGlobals($this->jsGlobals, $tal->getJSGlobals());
|
||||
|
||||
foreach ($tal->getTabs() as $guid => $tt)
|
||||
@@ -603,6 +607,8 @@ class SmartAction
|
||||
$tal = new SmartAI(SmartAI::SRC_TYPE_ACTIONLIST, $i, ['baseEntry' => $this->smartAI->getEntry()]);
|
||||
$tal->prepare();
|
||||
|
||||
$this->smartAI->css .= $tal->css;
|
||||
|
||||
Util::mergeJsGlobals($this->jsGlobals, $tal->getJSGlobals());
|
||||
|
||||
foreach ($tal->getTabs() as $guid => $tt)
|
||||
|
||||
@@ -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;
|
||||
@@ -359,13 +368,19 @@ class SmartEvent
|
||||
|
||||
public function hasPhases() : bool
|
||||
{
|
||||
return $this->phaseMask == 0;
|
||||
return $this->phaseMask && ($this->phaseMask & 0xFFF) != 0xFFF;
|
||||
}
|
||||
|
||||
private function formatFlags() : string
|
||||
{
|
||||
$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;
|
||||
|
||||
|
||||
@@ -306,6 +306,11 @@ abstract class DBTypeList
|
||||
$this->error = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* iterate over fetched templates
|
||||
*
|
||||
* @return array the current template
|
||||
*/
|
||||
public function &iterate() : \Generator
|
||||
{
|
||||
if (!$this->templates)
|
||||
@@ -483,7 +488,7 @@ abstract class DBTypeList
|
||||
't': type [always set]
|
||||
'ti': typeId [always set]
|
||||
'bd': BossDrop [0; 1] [Creature / GO]
|
||||
'dd': DungeonDifficulty [-2: DungeonHC; -1: DungeonNM; 1: Raid10NM; 2:Raid25NM; 3:Raid10HM; 4: Raid25HM] [Creature / GO]
|
||||
'dd': DungeonDifficulty [-2: DungeonHC; -1: DungeonNM; 1: Raid10NM; 2:Raid25NM; 3:Raid10HM; 4: Raid25HM; 99: filler trash] [Creature / GO]
|
||||
'q': cssQuality [Items]
|
||||
'z': zone [set when all happens in here]
|
||||
'p': PvP [pvpSourceId]
|
||||
@@ -632,7 +637,18 @@ trait spawnHelper
|
||||
$wpSum = [];
|
||||
$wpIdx = 0;
|
||||
$worldPos = [];
|
||||
$spawns = DB::Aowow()->select("SELECT * FROM ?_spawns WHERE `type` = ?d AND `typeId` IN (?a) AND `posX` > 0 AND `posY` > 0", self::$type, $this->getFoundIDs()) ?: [];
|
||||
$spawns = DB::Aowow()->select(
|
||||
'SELECT CASE WHEN z.`type` = ?d THEN 1
|
||||
WHEN z.`type` = ?d THEN 2
|
||||
WHEN z.`type` = ?d THEN 2
|
||||
ELSE 0
|
||||
END AS "mapType", s.*
|
||||
FROM ?_spawns s
|
||||
JOIN ?_zones z ON s.areaId = z.id
|
||||
WHERE s.`type` = ?d AND s.`typeId` IN (?a) AND s.`posX` > 0 AND s.`posY` > 0',
|
||||
MAP_TYPE_DUNGEON_HC, MAP_TYPE_MMODE_RAID, MAP_TYPE_MMODE_RAID_HC,
|
||||
self::$type, $this->getFoundIDs()
|
||||
) ?: [];
|
||||
|
||||
if (!$skipAdmin && User::isInGroup(U_GROUP_MODERATOR))
|
||||
if ($guids = array_column(array_filter($spawns, fn($x) => $x['guid'] > 0 || $x['type'] != Type::NPC), 'guid'))
|
||||
@@ -653,7 +669,7 @@ trait spawnHelper
|
||||
$label = [Lang::npc('waypoint').Lang::main('colon').$p['point']];
|
||||
|
||||
if ($p['wait'])
|
||||
$label[] = Lang::npc('wait').Lang::main('colon').Util::formatTime($p['wait'], false);
|
||||
$label[] = Lang::npc('wait').Lang::main('colon').DateTime::formatTimeElapsedFloat($p['wait']);
|
||||
|
||||
$opts = array( // \0 doesn't get printed and tricks Util::toJSON() into handling this as a string .. i feel slightly dirty now
|
||||
'label' => "\0$<br /><span class=\"q0\">".implode('<br />', $label).'</span>',
|
||||
@@ -696,13 +712,13 @@ trait spawnHelper
|
||||
$info[2] = Lang::game('phases').Lang::main('colon').Util::asHex($s['phaseMask']);
|
||||
|
||||
if ($s['spawnMask'] == 15)
|
||||
$info[3] = Lang::game('mode').Lang::game('modes', -1);
|
||||
$info[3] = Lang::game('mode').Lang::game('modes', 0, -1);
|
||||
else if ($s['spawnMask'])
|
||||
{
|
||||
$_ = [];
|
||||
for ($i = 0; $i < 4; $i++)
|
||||
if ($s['spawnMask'] & 1 << $i)
|
||||
$_[] = Lang::game('modes', $i);
|
||||
$_[] = Lang::game('modes', $s['mapType'], $i);
|
||||
|
||||
$info[4] = Lang::game('mode').implode(', ', $_);
|
||||
}
|
||||
@@ -880,8 +896,13 @@ trait profilerHelper
|
||||
|
||||
trait sourceHelper
|
||||
{
|
||||
protected $sources = [];
|
||||
protected $sourceMore = null;
|
||||
protected array $sources = [];
|
||||
protected ?array $sourceMore = null;
|
||||
|
||||
public function getRawSource(int $src) : array
|
||||
{
|
||||
return $this->sources[$this->id][$src] ?? [];
|
||||
}
|
||||
|
||||
public function getSources(?array &$s = [], ?array &$sm = []) : bool
|
||||
{
|
||||
@@ -923,7 +944,9 @@ trait sourceHelper
|
||||
10H 0b0100 2 0b011
|
||||
25H 0b1000 3 0b100
|
||||
*/
|
||||
if ($this->curTpl['moreMask'] & SRC_FLAG_DUNGEON_DROP)
|
||||
if ($this->curTpl['moreMask'] & SRC_FLAG_COMMON)
|
||||
$sm['dd'] = 99;
|
||||
else if ($this->curTpl['moreMask'] & SRC_FLAG_DUNGEON_DROP)
|
||||
$sm['dd'] = $this->sources[$this->id][SRC_DROP][0] * -1;
|
||||
else if ($this->curTpl['moreMask'] & SRC_FLAG_RAID_DROP)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user