mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7d49befdf |
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -1,4 +0,0 @@
|
||||
*.php text eol=lf
|
||||
*.js text eol=lf
|
||||
*.css text eol=lf
|
||||
*.sql text eol=lf
|
||||
22
.github/ISSUE_TEMPLATE/bug_report.md
vendored
22
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,22 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: issue template
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug and how to reproduce it**
|
||||
additionally paste relevant lines from db table `aowow_errors`
|
||||
or your browsers console here.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**System:**
|
||||
- OS: [e.g. Win10]
|
||||
- PHP version:
|
||||
- revision used:
|
||||
- Browser (in case of JavaScript / display errors):
|
||||
- AzerothCore: yes/no
|
||||
18
.gitignore
vendored
18
.gitignore
vendored
@@ -1,44 +1,30 @@
|
||||
# Git
|
||||
*.orig
|
||||
|
||||
# cache
|
||||
/cache/template/*
|
||||
/setup/generated/alphaMaps/*.png
|
||||
/cache/firstrun
|
||||
|
||||
# extract from MPQ
|
||||
/setup/mpqdata/*
|
||||
|
||||
# generated files
|
||||
/static/js/profile_all.js
|
||||
/static/js/locale.js
|
||||
/static/js/Markup.js
|
||||
/static/widgets/power.js
|
||||
/static/widgets/power/demo.html
|
||||
/static/widgets/searchbox.js
|
||||
/static/widgets/searchbox/searchbox.html
|
||||
/static/download/searchplugins/aowow.xml
|
||||
/config/config.php
|
||||
/datasets/*
|
||||
!/datasets/zones
|
||||
# /datasets/item-scaling
|
||||
|
||||
# extracted sounds
|
||||
/static/wowsounds/*
|
||||
|
||||
# extracted images
|
||||
/static/images/wow/icons/large/*
|
||||
/static/images/wow/icons/medium/*
|
||||
/static/images/wow/icons/small/*
|
||||
/static/images/wow/icons/tiny/*
|
||||
!/static/images/wow/icons/tiny/quest_*
|
||||
/static/images/wow/hunterpettalents/*
|
||||
/static/images/wow/Interface/*
|
||||
/static/images/wow/hunterpettalents/icons*
|
||||
/static/images/wow/interface/*
|
||||
/static/images/wow/loadingscreens/*
|
||||
/static/images/wow/maps/*
|
||||
!/static/images/wow/maps/overlay*
|
||||
/static/images/wow/talents/icons/*
|
||||
/static/images/wow/talents/backgrounds/*
|
||||
|
||||
# modelviewer (~7GB data)
|
||||
/static/modelviewer/models/*
|
||||
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "includes/tools/MPQExtractor"]
|
||||
path = includes/tools/MPQExtractor
|
||||
url = https://github.com/iamcal/MPQExtractor.git
|
||||
[submodule "includes/tools/BLPConverter"]
|
||||
path = includes/tools/BLPConverter
|
||||
url = https://github.com/Kanma/BLPConverter.git
|
||||
16
.htaccess
16
.htaccess
@@ -1,19 +1,11 @@
|
||||
Order Deny,Allow
|
||||
<FilesMatch "\.(conf|php|in)$">
|
||||
<FilesMatch "\.(conf|php|in)|aowow$">
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
<FilesMatch "^(index)\.php$">
|
||||
Allow from all
|
||||
</FilesMatch>
|
||||
|
||||
<Files "aowow">
|
||||
ForceType application/x-httpd-php
|
||||
</Files>
|
||||
|
||||
<Files "prQueue">
|
||||
ForceType application/x-httpd-php
|
||||
</Files>
|
||||
|
||||
# Block view of some folders
|
||||
Options -Indexes
|
||||
DirectoryIndex index.php
|
||||
@@ -25,9 +17,9 @@ AddDefaultCharset utf8
|
||||
CharsetRecodeMultipartForms Off
|
||||
</IfModule>
|
||||
|
||||
# UHD screenshots can get pretty large (cannot be set in config)
|
||||
php_value upload_max_filesize 20M
|
||||
php_value post_max_size 25M
|
||||
# 5MB should be enough for the largest screenshots in the land
|
||||
php_value default_charset UTF-8
|
||||
php_value upload_max_filesize 5M
|
||||
|
||||
RewriteEngine on
|
||||
# RewriteBase /~user/localPath/ # enable if the rules do not work, when they should
|
||||
|
||||
140
README.md
140
README.md
@@ -1,140 +0,0 @@
|
||||

|
||||
|
||||
|
||||
## Build Status
|
||||

|
||||
|
||||
|
||||
## Introduction
|
||||
|
||||
AoWoW is a Database tool for World of Warcraft v3.3.5 (build 12340)
|
||||
It is based upon the other famous Database tool for WoW, featuring the red smiling rocket.
|
||||
While the first releases can be found as early as 2008, today it is impossible to say who created this project.
|
||||
This is a complete rewrite of the serverside php code and update to the clientside javascripts from 2008 to something 2013ish.
|
||||
|
||||
I myself take no credit for the clientside scripting, design and layout that these php-scripts cater to.
|
||||
Also, this project is not meant to be used for commercial puposes of any kind!
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
+ Webserver running PHP ≥ 7.4 — 8.0 including extensions:
|
||||
+ [SimpleXML](https://www.php.net/manual/en/book.simplexml.php)
|
||||
+ [GD](https://www.php.net/manual/en/book.image)
|
||||
+ [MySQL Improved](https://www.php.net/manual/en/book.mysqli.php)
|
||||
+ [Multibyte String](https://www.php.net/manual/en/book.mbstring.php)
|
||||
+ [File Information](https://www.php.net/manual/en/book.fileinfo.php)
|
||||
+ [GNU Multiple Precision](https://www.php.net/manual/en/book.gmp.php) (When using TrinityCore as auth source)
|
||||
+ MySQL ≥ 5.5.30
|
||||
+ [TDB 335.21101](https://github.com/TrinityCore/TrinityCore/releases/tag/TDB335.21101)
|
||||
+ WIN: php.exe needs to be added to the `PATH` system variable, if it isn't already.
|
||||
+ Tools require cmake: Please refer to the individual repositories for detailed information
|
||||
+ [MPQExtractor](https://github.com/Sarjuuk/MPQExtractor) / [FFmpeg](https://ffmpeg.org/download.html) / (optional: [BLPConverter](https://github.com/Sarjuuk/BLPConverter))
|
||||
+ WIN users may find it easier to use these alternatives
|
||||
+ [MPQEditor](http://www.zezula.net/en/mpq/download.html) / [FFmpeg](http://ffmpeg.zeranoe.com/builds/) / (optional: [BLPConverter](https://github.com/PatrickCyr/BLPConverter))
|
||||
|
||||
audio processing may require [lame](https://sourceforge.net/projects/lame/files/lame/3.99/) or [vorbis-tools](https://www.xiph.org/downloads/) (which may require libvorbis (which may require libogg))
|
||||
|
||||
|
||||
#### Highly Recommended
|
||||
+ setting the following configuration values on your TrinityCore server will greatly increase the accuracy of spawn points
|
||||
> Calculate.Creature.Zone.Area.Data = 1
|
||||
> Calculate.Gameoject.Zone.Area.Data = 1
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
#### 1. Acquire the required repositories
|
||||
`git clone git@github.com:Sarjuuk/aowow.git aowow`
|
||||
`git clone git@github.com:Sarjuuk/MPQExtractor.git MPQExtractor`
|
||||
|
||||
#### 2. Prepare the database
|
||||
Ensure that the account you are going to use has **full** access on the database AoWoW is going to occupy and ideally only **read** access on the world database you are going to reference.
|
||||
Import `setup/db_structure.sql` into the AoWoW database `mysql -p {your-db-here} < setup/db_structure.sql`
|
||||
|
||||
#### 3. Server created files
|
||||
See to it, that the web server is able to write the following directories and their children. If they are missing, the setup will create them with appropriate permissions
|
||||
* `cache/`
|
||||
* `config/`
|
||||
* `static/download/`
|
||||
* `static/widgets/`
|
||||
* `static/js/`
|
||||
* `static/uploads/`
|
||||
* `static/images/wow/`
|
||||
* `datasets/`
|
||||
|
||||
#### 4. Extract the client archives (MPQs)
|
||||
Extract the following directories from the client archives into `setup/mpqdata/`, while maintaining patch order (base mpq -> patch-mpq: 1 -> 9 -> A -> Z). The required paths are scattered across the archives. Overwrite older files if asked to.
|
||||
.. for every locale you are going to use:
|
||||
> \<localeCode>/DBFilesClient/
|
||||
> \<localeCode>/Interface/WorldMap/
|
||||
> \<localeCode>/Interface/FrameXML/GlobalStrings.lua
|
||||
|
||||
.. once is enough (still apply the localeCode though):
|
||||
> \<localeCode>/Interface/TalentFrame/
|
||||
> \<localeCode>/Interface/Glues/Credits/
|
||||
> \<localeCode>/Interface/Icons/
|
||||
> \<localeCode>/Interface/Spellbook/
|
||||
> \<localeCode>/Interface/PaperDoll/
|
||||
> \<localeCode>/Interface/GLUES/CHARACTERCREATE/
|
||||
> \<localeCode>/Interface/Pictures
|
||||
> \<localeCode>/Interface/PvPRankBadges
|
||||
> \<localeCode>/Interface/FlavorImages
|
||||
> \<localeCode>/Interface/Calendar/Holidays/
|
||||
> \<localeCode>/Sound/
|
||||
|
||||
.. optionaly (not used in AoWoW):
|
||||
> \<localeCode>/Interface/GLUES/LOADINGSCREENS/
|
||||
|
||||
#### 5. Reencode the audio files
|
||||
WAV-files need to be reencoded as `ogg/vorbis` and some MP3s may identify themselves as `application/octet-stream` instead of `audio/mpeg`.
|
||||
* [example for WIN](https://gist.github.com/Sarjuuk/d77b203f7b71d191509afddabad5fc9f)
|
||||
* [example for \*nix](https://gist.github.com/Sarjuuk/1f05ef2affe49a7e7ca0fad7b01c081d)
|
||||
|
||||
#### 6. Run the initial setup from the CLI
|
||||
`php aowow --setup`.
|
||||
This should guide you through with minimal input required from your end, but will take some time though, especially compiling the zone-images. Use it to familiarize yourself with the other functions this setup has. Yes, I'm dead serious: *Go read the code!* It will help you understand how to configure AoWoW and keep it in sync with your world database.
|
||||
When you've created your admin account you are done.
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Q: The Page appears white, without any styles.
|
||||
A: The static content is not being displayed. You are either using SSL and AoWoW is unable to detect it or STATIC_HOST is not defined poperly. Either way this can be fixed via config `php aowow --siteconfig`
|
||||
|
||||
Q: Fatal error: Can't inherit abstract function \<functionName> (previously declared abstract in \<className>) in \<path>
|
||||
A: You are using cache optimization modules for php, that are in confict with each other. (Zend OPcache, XCache, ..) Disable all but one.
|
||||
|
||||
Q: Some generated images appear distorted or have alpha-channel issues.
|
||||
A: Image compression is beyond my understanding, so i am unable to fix these issues within the blpReader.
|
||||
BUT you can convert the affected blp file into a png file in the same directory, using the provided BLPConverter.
|
||||
AoWoW will priorize png files over blp files.
|
||||
|
||||
Q: How can i get the modelviewer to work?
|
||||
A: You can't anymore. Wowhead switched from Flash to WebGL (as they should) and moved or deleted the old files in the process.
|
||||
|
||||
Q: I'm getting random javascript errors!
|
||||
A: Some server configurations or external services (like Cloudflare) come with modules, that automaticly minify js and css files. Sometimes they break in the process. Disable the module in this case.
|
||||
|
||||
Q: Some search results within the profiler act rather strange. How does it work?
|
||||
A: Whenever you try to view a new character, AoWoW needs to fetch it first. Since the data is structured for the needs of TrinityCore and not for easy viewing, AoWoW needs to save and restructure it locally. To this end, every char request is placed in a queue. While the queue is not empty, a single instance of `prQueue` is run in the background as not to overwhelm the characters database with requests. This also means, some more exotic search queries can't be run agains the characters database and have to use the incomplete/outdated cached profiles of AoWoW.
|
||||
|
||||
Q: Screenshot upload fails, because the file size is too large and/or the subdirectories are visible from the web!
|
||||
A: That's a web server configuration issue. If you are using Apache you may need to [enable the use of .htaccess](http://httpd.apache.org/docs/2.4/de/mod/core.html#allowoverride). Other servers require individual configuration.
|
||||
|
||||
Q: An Item, Quest or NPC i added or edited can't be searched. Why?
|
||||
A: A search is only conducted against the currently used locale. You may have only edited the name field in the base table instead of adding multiple strings into the appropriate \*_locale tables. In this case searches in a non-english locale are run against an empty name field.
|
||||
|
||||
## Thanks
|
||||
|
||||
@mix: for providing the php-script to parse .blp and .dbc into usable images and tables
|
||||
@LordJZ: the wrapper-class for DBSimple; the basic idea for the user-class
|
||||
@kliver: basic implementation of screenshot uploads
|
||||
@Sarjuuk: maintainer of the project
|
||||
|
||||
|
||||
## Special Thanks
|
||||
Said website with the red smiling rocket, for providing this beautifull website!
|
||||
Please do not reagard this project as blatant rip-off, rather as "We do really liked your presentation, but since time and content progresses, you are sadly no longer supplying the data we need".
|
||||
|
||||

|
||||
49
config/config.php.in
Normal file
49
config/config.php.in
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// use as example. File is generated from setup.
|
||||
|
||||
// -- Aowow Database --
|
||||
// contains world-data, user-data and logs
|
||||
$AoWoWconf['aowow'] = array(
|
||||
'host' => '127.0.0.1',
|
||||
'user' => '<user>',
|
||||
'pass' => '<pass>',
|
||||
'db' => 'world',
|
||||
'prefix' => 'aowow_'
|
||||
);
|
||||
|
||||
// -- World Database --
|
||||
// used to generate data-tables
|
||||
$AoWoWconf['world'] = array(
|
||||
'host' => '127.0.0.1',
|
||||
'user' => '<user>',
|
||||
'pass' => '<pass>',
|
||||
'db' => 'world',
|
||||
'prefix' => ''
|
||||
);
|
||||
|
||||
// -- Auth Database --
|
||||
// used to generate user-tables
|
||||
$AoWoWconf['auth'] = array(
|
||||
'host' => '127.0.0.1',
|
||||
'user' => '<user>',
|
||||
'pass' => '<pass>',
|
||||
'db' => 'auth',
|
||||
'prefix' => ''
|
||||
);
|
||||
|
||||
// -- Characters Database --
|
||||
// used to display profiles
|
||||
$AoWoWconf['characters'][<realmId>] = array(
|
||||
'host' => '127.0.0.1',
|
||||
'user' => '<user>',
|
||||
'pass' => '<pass>',
|
||||
'db' => 'characters',
|
||||
'prefix' => ''
|
||||
);
|
||||
|
||||
?>
|
||||
@@ -4,7 +4,7 @@ if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
function extAuth($user, $pass, &$userId = 0, &$userGroup = -1)
|
||||
function extAuth($user, $pass, &$userId = 0)
|
||||
{
|
||||
/*
|
||||
insert some auth mechanism here
|
||||
|
||||
74
datasets/weight-presets
Normal file
74
datasets/weight-presets
Normal file
@@ -0,0 +1,74 @@
|
||||
var wt_presets = {
|
||||
1: {
|
||||
pve: {
|
||||
arms: {__icon:'ability_rogue_eviscerate'},
|
||||
fury: {__icon:'ability_warrior_innerrage',exprtng:100,str:82,critstrkrtng:66,agi:53,armorpenrtng:52,hitrtng:48,hastertng:36,atkpwr:31,armor:5},
|
||||
prot: {__icon:'ability_warrior_defensivestance',sta:100,dodgertng:90,defrtng:86,block:81,agi:67,parryrtng:67,blockrtng:48,str:48,exprtng:19,hitrtng:10,armorpenrtng:10,critstrkrtng:7,armor:6,hastertng:1,atkpwr:1}
|
||||
}
|
||||
},
|
||||
2: {
|
||||
pve: {
|
||||
holy: {__icon:'spell_holy_holybolt',int:100,manargn:88,splpwr:58,critstrkrtng:46,hastertng:35},
|
||||
prot: {__icon:'ability_paladin_shieldofthetemplar',sta:100,dodgertng:94,block:86,defrtng:86,exprtng:79,agi:76,parryrtng:76,hitrtng:58,blockrtng:52,str:50,armor:6,atkpwr:6,splpwr:4,critstrkrtng:3},
|
||||
retrib: {__icon:'spell_holy_auraoflight',mledps:470,hitrtng:100,str:80,exprtng:66,critstrkrtng:40,atkpwr:34,agi:32,hastertng:30,armorpenrtng:22,splpwr:9}
|
||||
}
|
||||
},
|
||||
3: {
|
||||
pve: {
|
||||
beast: {__icon:'ability_hunter_beasttaming',rgddps:213,hitrtng:100,agi:58,critstrkrtng:40,int:37,atkpwr:30,armorpenrtng:28,hastertng:21},
|
||||
marks: {__icon:'ability_marksmanship',rgddps:379,hitrtng:100,agi:74,critstrkrtng:57,armorpenrtng:40,int:39,atkpwr:32,hastertng:24},
|
||||
surv: {__icon:'ability_hunter_swiftstrike',rgddps:181,hitrtng:100,agi:76,critstrkrtng:42,int:35,hastertng:31,atkpwr:29,armorpenrtng:26}
|
||||
}
|
||||
},
|
||||
4: {
|
||||
pve: {
|
||||
assas: {__icon:'ability_rogue_eviscerate',mledps:170,agi:100,exprtng:87,hitrtng:83,critstrkrtng:81,atkpwr:65,armorpenrtng:65,hastertng:64,str:55},
|
||||
combat: {__icon:'ability_backstab',mledps:220,armorpenrtng:100,agi:100,exprtng:82,hitrtng:80,critstrkrtng:75,hastertng:73,str:55,atkpwr:50},
|
||||
subtle: {__icon:'ability_stealth',mledps:228,exprtng:100,agi:100,hitrtng:80,armorpenrtng:75,critstrkrtng:75,hastertng:75,str:55,atkpwr:50}
|
||||
}
|
||||
},
|
||||
5: {
|
||||
pve: {
|
||||
disc: {__icon:'spell_holy_wordfortitude',splpwr:100,manargn:67,int:65,hastertng:59,critstrkrtng:48,spi:22},
|
||||
holy: {__icon:'spell_holy_guardianspirit',manargn:100,int:69,splpwr:60,spi:52,critstrkrtng:38,hastertng:31},
|
||||
shadow: {__icon:'spell_shadow_shadowwordpain',hitrtng:100,shasplpwr:76,splpwr:76,critstrkrtng:54,hastertng:50,spi:16,int:16}
|
||||
}
|
||||
},
|
||||
6: {
|
||||
pve: {
|
||||
blooddps: {__icon:'spell_deathknight_bloodpresence',mledps:360,armorpenrtng:100,str:99,hitrtng:91,exprtng:90,critstrkrtng:57,hastertng:55,atkpwr:36,armor:1},
|
||||
frostdps: {__icon:'spell_deathknight_frostpresence',mledps:337,hitrtng:100,str:97,exprtng:81,armorpenrtng:61,critstrkrtng:45,atkpwr:35,hastertng:28,armor:1},
|
||||
frosttank: {__icon:'spell_deathknight_frostpresence',mledps:419,parryrtng:100,hitrtng:97,str:96,defrtng:85,exprtng:69,dodgertng:61,agi:61,sta:61,critstrkrtng:49,atkpwr:41,armorpenrtng:31,armor:5},
|
||||
unholydps: {__icon:'spell_deathknight_unholypresence',mledps:209,str:100,hitrtng:66,exprtng:51,hastertng:48,critstrkrtng:45,atkpwr:34,armorpenrtng:32,armor:1}
|
||||
}
|
||||
},
|
||||
7: {
|
||||
pve: {
|
||||
elem: {__icon:'spell_nature_lightning',hitrtng:100,splpwr:60,hastertng:56,critstrkrtng:40,int:11},
|
||||
enhance: {__icon:'spell_nature_lightningshield',mledps:135,hitrtng:100,exprtng:84,agi:55,int:55,critstrkrtng:55,hastertng:42,str:35,atkpwr:32,splpwr:29,armorpenrtng:26},
|
||||
resto: {__icon:'spell_nature_magicimmunity',manargn:100,int:85,splpwr:77,critstrkrtng:62,hastertng:35}
|
||||
}
|
||||
},
|
||||
8: {
|
||||
pve: {
|
||||
arcane: {__icon:'spell_holy_magicalsentry',hitrtng:100,hastertng:54,arcsplpwr:49,splpwr:49,critstrkrtng:37,int:34,frosplpwr:24,firsplpwr:24,spi:14},
|
||||
fire: {__icon:'spell_fire_firebolt02',hitrtng:100,hastertng:53,firsplpwr:46,splpwr:46,critstrkrtng:43,frosplpwr:23,arcsplpwr:23,int:13},
|
||||
frost: {__icon:'spell_frost_frostbolt02',hitrtng:100,hastertng:42,frosplpwr:39,splpwr:39,arcsplpwr:19,firsplpwr:19,critstrkrtng:19,int:6}
|
||||
}
|
||||
},
|
||||
9: {
|
||||
pve: {
|
||||
afflic: {__icon:'spell_shadow_deathcoil',hitrtng:100,shasplpwr:72,splpwr:72,hastertng:61,critstrkrtng:38,firsplpwr:36,spi:34,int:15},
|
||||
demo: {__icon:'spell_shadow_metamorphosis',hitrtng:100,hastertng:50,firsplpwr:45,shasplpwr:45,splpwr:45,critstrkrtng:31,spi:29,int:13},
|
||||
destro: {__icon:'spell_shadow_rainoffire',hitrtng:100,firsplpwr:47,splpwr:47,hastertng:46,spi:26,shasplpwr:23,critstrkrtng:16,int:13}
|
||||
}
|
||||
},
|
||||
11: {
|
||||
pve: {
|
||||
balance: {__icon:'spell_nature_starfall',hitrtng:100,splpwr:66,hastertng:54,critstrkrtng:43,spi:22,int:22},
|
||||
feraltank: {__icon:'ability_racial_bearform',agi:100,sta:75,dodgertng:65,defrtng:60,exprtng:16,str:10,armor:10,hitrtng:8,hastertng:5,atkpwr:4,feratkpwr:4,critstrkrtng:3},
|
||||
resto: {__icon:'spell_nature_healingtouch',splpwr:100,manargn:73,hastertng:57,int:51,spi:32,critstrkrtng:11},
|
||||
feraldps: {__icon:'ability_druid_catform',agi:100,armorpenrtng:90,str:80,critstrkrtng:55,exprtng:50,hitrtng:50,feratkpwr:40,atkpwr:40,hastertng:35}
|
||||
}
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,178 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxAccount extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['exclude', 'weightscales', 'favorites'];
|
||||
protected $_post = array(
|
||||
'groups' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'save' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'delete' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkIdList'],
|
||||
'name' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxAccount::checkName' ],
|
||||
'scale' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxAccount::checkScale' ],
|
||||
'reset' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'mode' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'type' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'add' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'remove' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
// 'sessionKey' => ['filter' => FILTER_SANITIZE_NUMBER_INT]
|
||||
);
|
||||
protected $_get = array(
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkLocale']
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (is_numeric($this->_get['locale']))
|
||||
User::useLocale($this->_get['locale']);
|
||||
|
||||
if (!$this->params || !User::$id)
|
||||
return;
|
||||
|
||||
// select handler
|
||||
if ($this->params[0] == 'exclude')
|
||||
$this->handler = 'handleExclude';
|
||||
else if ($this->params[0] == 'weightscales')
|
||||
$this->handler = 'handleWeightscales';
|
||||
else if ($this->params[0] == 'favorites')
|
||||
$this->handler = 'handleFavorites';
|
||||
}
|
||||
|
||||
protected function handleExclude() : void
|
||||
{
|
||||
if ($this->_post['mode'] == 1) // directly set exludes
|
||||
{
|
||||
$type = $this->_post['type'];
|
||||
$ids = $this->_post['id'];
|
||||
|
||||
if (!Type::exists($type) || empty($ids))
|
||||
{
|
||||
trigger_error('AjaxAccount::handleExclude - invalid type #'.$type.(empty($ids) ? ' or id-list empty' : ''), E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// ready for some bullshit? here it comes!
|
||||
// we don't get signaled whether an id should be added to or removed from either includes or excludes
|
||||
// so we throw everything into one table and toggle the mode if its already in here
|
||||
|
||||
$includes = DB::Aowow()->selectCol('SELECT typeId FROM ?_profiler_excludes WHERE type = ?d AND typeId IN (?a)', $type, $ids);
|
||||
|
||||
foreach ($ids as $typeId)
|
||||
DB::Aowow()->query('INSERT INTO ?_account_excludes (`userId`, `type`, `typeId`, `mode`) VALUES (?a) ON DUPLICATE KEY UPDATE mode = (mode ^ 0x3)', array(
|
||||
User::$id, $type, $typeId, in_array($includes, $typeId) ? 2 : 1
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
else if ($this->_post['reset'] == 1) // defaults to unavailable
|
||||
{
|
||||
$mask = PR_EXCLUDE_GROUP_UNAVAILABLE;
|
||||
DB::Aowow()->query('DELETE FROM ?_account_excludes WHERE userId = ?d', User::$id);
|
||||
}
|
||||
else // clamp to real groups
|
||||
$mask = $this->_post['groups'] & PR_EXCLUDE_GROUP_ANY;
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_account SET excludeGroups = ?d WHERE id = ?d', $mask, User::$id);
|
||||
}
|
||||
|
||||
protected function handleWeightscales() : string
|
||||
{
|
||||
if ($this->_post['save'])
|
||||
{
|
||||
if (!$this->_post['scale'])
|
||||
{
|
||||
trigger_error('AjaxAccount::handleWeightscales - scaleId empty', E_USER_ERROR);
|
||||
return '0';
|
||||
}
|
||||
|
||||
$id = 0;
|
||||
|
||||
if ($this->_post['id'] && ($id = $this->_post['id'][0]))
|
||||
{
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_account_weightscales WHERE userId = ?d AND id = ?d', User::$id, $id))
|
||||
{
|
||||
trigger_error('AjaxAccount::handleWeightscales - scale #'.$id.' not in db or owned by user #'.User::$id, E_USER_ERROR);
|
||||
return '0';
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_account_weightscales SET `name` = ? WHERE id = ?d', $this->_post['name'], $id);
|
||||
}
|
||||
else
|
||||
{
|
||||
$nScales = DB::Aowow()->selectCell('SELECT COUNT(id) FROM ?_account_weightscales WHERE userId = ?d', User::$id);
|
||||
if ($nScales >= 5) // more or less hard-defined in LANG.message_weightscalesaveerror
|
||||
return '0';
|
||||
|
||||
$id = DB::Aowow()->query('INSERT INTO ?_account_weightscales (`userId`, `name`) VALUES (?d, ?)', User::$id, $this->_post['name']);
|
||||
}
|
||||
|
||||
DB::Aowow()->query('DELETE FROM ?_account_weightscale_data WHERE id = ?d', $id);
|
||||
|
||||
foreach (explode(',', $this->_post['scale']) as $s)
|
||||
{
|
||||
[$k, $v] = explode(':', $s);
|
||||
if (!in_array($k, Util::$weightScales) || $v < 1)
|
||||
continue;
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_account_weightscale_data VALUES (?d, ?, ?d)', $id, $k, $v);
|
||||
}
|
||||
|
||||
return (string)$id;
|
||||
}
|
||||
else if ($this->_post['delete'] && $this->_post['id'] && $this->_post['id'][0])
|
||||
DB::Aowow()->query('DELETE FROM ?_account_weightscales WHERE id = ?d AND userId = ?d', $this->_post['id'][0], User::$id);
|
||||
else
|
||||
{
|
||||
trigger_error('AjaxAccount::handleWeightscales - malformed request received', E_USER_ERROR);
|
||||
return '0';
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleFavorites() : void
|
||||
{
|
||||
// omit usage of sessionKey
|
||||
if (count($this->_post['id']) != 1 || empty($this->_post['id'][0]))
|
||||
{
|
||||
trigger_error('AjaxAccount::handleFavorites - malformed request received', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$typeId = $this->_post['id'][0];
|
||||
|
||||
if ($type = $this->_post['add'])
|
||||
{
|
||||
$tc = Type::newList($type, [['id', $typeId]]);
|
||||
if (!$tc || $tc->error)
|
||||
{
|
||||
trigger_error('AjaxAccount::handleFavorites - invalid typeId #'.$typeId.' for type #'.$type, E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_account_favorites (`userId`, `type`, `typeId`) VALUES (?d, ?d, ?d)', User::$id, $type, $typeId);
|
||||
}
|
||||
else if ($type = $this->_post['remove'])
|
||||
DB::Aowow()->query('DELETE FROM ?_account_favorites WHERE `userId` = ?d AND `type` = ?d AND `typeId` = ?d', User::$id, $type, $typeId);
|
||||
}
|
||||
|
||||
protected static function checkScale(string $val) : string
|
||||
{
|
||||
if (preg_match('/^((\w+:\d+)(,\w+:\d+)*)$/', $val))
|
||||
return $val;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected static function checkName(string $val) : string
|
||||
{
|
||||
$var = trim(urldecode($val));
|
||||
|
||||
return filter_var($var, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_AOWOW);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,629 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxAdmin extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['screenshots', 'siteconfig', 'weight-presets', 'spawn-override', 'guide'];
|
||||
protected $_get = array(
|
||||
'action' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkIdListUnsigned'],
|
||||
'key' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxAdmin::checkKey' ],
|
||||
'all' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkFulltext' ],
|
||||
'type' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt' ],
|
||||
'typeid' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt' ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxAdmin::checkUser' ],
|
||||
'val' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkFulltext' ],
|
||||
'guid' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt' ],
|
||||
'area' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt' ],
|
||||
'floor' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt' ]
|
||||
);
|
||||
protected $_post = array(
|
||||
'alt' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt'],
|
||||
'scale' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxAdmin::checkScale'],
|
||||
'__icon' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxAdmin::checkKey' ],
|
||||
'status' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt'],
|
||||
'msg' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$this->params)
|
||||
return;
|
||||
|
||||
if ($this->params[0] == 'screenshots' && $this->_get['action'])
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT))
|
||||
return;
|
||||
|
||||
if ($this->_get['action'] == 'list')
|
||||
$this->handler = 'ssList';
|
||||
else if ($this->_get['action'] == 'manage')
|
||||
$this->handler = 'ssManage';
|
||||
else if ($this->_get['action'] == 'editalt')
|
||||
$this->handler = 'ssEditAlt';
|
||||
else if ($this->_get['action'] == 'approve')
|
||||
$this->handler = 'ssApprove';
|
||||
else if ($this->_get['action'] == 'sticky')
|
||||
$this->handler = 'ssSticky';
|
||||
else if ($this->_get['action'] == 'delete')
|
||||
$this->handler = 'ssDelete';
|
||||
else if ($this->_get['action'] == 'relocate')
|
||||
$this->handler = 'ssRelocate';
|
||||
}
|
||||
else if ($this->params[0] == 'siteconfig' && $this->_get['action'])
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
|
||||
return;
|
||||
|
||||
if ($this->_get['action'] == 'add')
|
||||
$this->handler = 'confAdd';
|
||||
else if ($this->_get['action'] == 'remove')
|
||||
$this->handler = 'confRemove';
|
||||
else if ($this->_get['action'] == 'update')
|
||||
$this->handler = 'confUpdate';
|
||||
}
|
||||
else if ($this->params[0] == 'weight-presets' && $this->_get['action'])
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
return;
|
||||
|
||||
if ($this->_get['action'] == 'save')
|
||||
$this->handler = 'wtSave';
|
||||
}
|
||||
else if ($this->params[0] == 'spawn-override')
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_MODERATOR))
|
||||
return;
|
||||
|
||||
$this->handler = 'spawnPosFix';
|
||||
}
|
||||
else if ($this->params[0] == 'guide')
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_STAFF))
|
||||
return;
|
||||
|
||||
$this->handler = 'guideManage';
|
||||
}
|
||||
}
|
||||
|
||||
// get all => null (optional)
|
||||
// evaled response .. UNK
|
||||
protected function ssList() : string
|
||||
{
|
||||
// ssm_screenshotPages
|
||||
// ssm_numPagesFound
|
||||
|
||||
$pages = CommunityContent::getScreenshotPagesForManager($this->_get['all'], $nPages);
|
||||
$buff = 'ssm_screenshotPages = '.Util::toJSON($pages).";\n";
|
||||
$buff .= 'ssm_numPagesFound = '.$nPages.';';
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
// get: [type => type, typeId => typeId] || [user => username]
|
||||
// evaled response .. UNK
|
||||
protected function ssManage() : string
|
||||
{
|
||||
$res = [];
|
||||
|
||||
if ($this->_get['type'] && $this->_get['type'] && $this->_get['typeid'] && $this->_get['typeid'])
|
||||
$res = CommunityContent::getScreenshotsForManager($this->_get['type'], $this->_get['typeid']);
|
||||
else if ($this->_get['user'])
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE displayName = ?', $this->_get['user']))
|
||||
$res = CommunityContent::getScreenshotsForManager(0, 0, $uId);
|
||||
|
||||
return 'ssm_screenshotData = '.Util::toJSON($res);
|
||||
}
|
||||
|
||||
// get: id => SSid
|
||||
// resp: ''
|
||||
protected function ssEditAlt() : void
|
||||
{
|
||||
// doesn't need to be htmlEscaped, ths javascript does that
|
||||
if ($this->_get['id'] && $this->_post['alt'] !== null)
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET caption = ? WHERE id = ?d', trim($this->_post['alt']), $this->_get['id'][0]);
|
||||
}
|
||||
|
||||
// get: id => comma-separated SSids
|
||||
// resp: ''
|
||||
protected function ssApprove() : void
|
||||
{
|
||||
if (!$this->reqGET('id'))
|
||||
{
|
||||
trigger_error('AjaxAdmin::ssApprove - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// create resized and thumb version of screenshot
|
||||
$resized = [772, 618];
|
||||
$thumb = [150, 150];
|
||||
$path = 'static/uploads/screenshots/%s/%d.jpg';
|
||||
|
||||
foreach ($this->_get['id'] as $id)
|
||||
{
|
||||
// must not be already approved
|
||||
if ($ssEntry = DB::Aowow()->selectRow('SELECT userIdOwner, date, type, typeId FROM ?_screenshots WHERE (status & ?d) = 0 AND id = ?d', CC_FLAG_APPROVED, $id))
|
||||
{
|
||||
// should also error-log
|
||||
if (!file_exists(sprintf($path, 'pending', $id)))
|
||||
{
|
||||
trigger_error('AjaxAdmin::ssApprove - screenshot #'.$id.' exists in db but not as file', E_USER_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
$srcImg = imagecreatefromjpeg(sprintf($path, 'pending', $id));
|
||||
$srcW = imagesx($srcImg);
|
||||
$srcH = imagesy($srcImg);
|
||||
|
||||
// write thumb
|
||||
$scale = min(1.0, min($thumb[0] / $srcW, $thumb[1] / $srcH));
|
||||
$destW = $srcW * $scale;
|
||||
$destH = $srcH * $scale;
|
||||
$destImg = imagecreatetruecolor($destW, $destH);
|
||||
|
||||
imagefill($destImg, 0, 0, imagecolorallocate($destImg, 255, 255, 255));
|
||||
imagecopyresampled($destImg, $srcImg, 0, 0, 0, 0, $destW, $destH, $srcW, $srcH);
|
||||
|
||||
imagejpeg($destImg, sprintf($path, 'thumb', $id), 100);
|
||||
|
||||
// write resized (only if required)
|
||||
if ($srcW > $resized[0] || $srcH > $resized[1])
|
||||
{
|
||||
$scale = min(1.0, min($resized[0] / $srcW, $resized[1] / $srcH));
|
||||
$destW = $srcW * $scale;
|
||||
$destH = $srcH * $scale;
|
||||
$destImg = imagecreatetruecolor($destW, $destH);
|
||||
|
||||
imagefill($destImg, 0, 0, imagecolorallocate($destImg, 255, 255, 255));
|
||||
imagecopyresampled($destImg, $srcImg, 0, 0, 0, 0, $destW, $destH, $srcW, $srcH);
|
||||
|
||||
imagejpeg($destImg, sprintf($path, 'resized', $id), 100);
|
||||
}
|
||||
|
||||
imagedestroy($srcImg);
|
||||
|
||||
// move screenshot from pending to normal
|
||||
rename(sprintf($path, 'pending', $id), sprintf($path, 'normal', $id));
|
||||
|
||||
// set as approved in DB and gain rep (once!)
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET status = ?d, userIdApprove = ?d WHERE id = ?d', CC_FLAG_APPROVED, User::$id, $id);
|
||||
Util::gainSiteReputation($ssEntry['userIdOwner'], SITEREP_ACTION_UPLOAD, ['id' => $id, 'what' => 1, 'date' => $ssEntry['date']]);
|
||||
// flag DB entry as having screenshots
|
||||
if ($tbl = Type::getClassAttrib($ssEntry['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE '.$tbl.' SET cuFlags = cuFlags | ?d WHERE id = ?d', CUSTOM_HAS_SCREENSHOT, $ssEntry['typeId']);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxAdmin::ssApprove - screenshot #'.$id.' not in db or already approved', E_USER_ERROR);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// get: id => comma-separated SSids
|
||||
// resp: ''
|
||||
protected function ssSticky() : void
|
||||
{
|
||||
if (!$this->reqGET('id'))
|
||||
{
|
||||
trigger_error('AjaxAdmin::ssSticky - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// approve soon to be sticky screenshots
|
||||
$this->ssApprove();
|
||||
|
||||
// this one is a bit strange: as far as i've seen, the only thing a 'sticky' screenshot does is show up in the infobox
|
||||
// this also means, that only one screenshot per page should be sticky
|
||||
// so, handle it one by one and the last one affecting one particular type/typId-key gets the cake
|
||||
foreach ($this->_get['id'] as $id)
|
||||
{
|
||||
// reset all others
|
||||
DB::Aowow()->query('UPDATE ?_screenshots a, ?_screenshots b SET a.status = a.status & ~?d WHERE a.type = b.type AND a.typeId = b.typeId AND a.id <> b.id AND b.id = ?d', CC_FLAG_STICKY, $id);
|
||||
|
||||
// toggle sticky status
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = IF(`status` & ?d, `status` & ~?d, `status` | ?d) WHERE id = ?d AND `status` & ?d', CC_FLAG_STICKY, CC_FLAG_STICKY, CC_FLAG_STICKY, $id, CC_FLAG_APPROVED);
|
||||
}
|
||||
}
|
||||
|
||||
// get: id => comma-separated SSids
|
||||
// resp: ''
|
||||
// 2 steps: 1) remove from sight, 2) remove from disk
|
||||
protected function ssDelete() : void
|
||||
{
|
||||
if (!$this->reqGET('id'))
|
||||
{
|
||||
trigger_error('AjaxAdmin::ssDelete - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$path = 'static/uploads/screenshots/%s/%d.jpg';
|
||||
|
||||
foreach ($this->_get['id'] as $id)
|
||||
{
|
||||
// irrevocably remove already deleted files
|
||||
if (User::isInGroup(U_GROUP_ADMIN) && DB::Aowow()->selectCell('SELECT 1 FROM ?_screenshots WHERE status & ?d AND id = ?d', CC_FLAG_DELETED, $id))
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_screenshots WHERE id = ?d', $id);
|
||||
if (file_exists(sprintf($path, 'pending', $id)))
|
||||
unlink(sprintf($path, 'pending', $id));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// move pending or normal to pending
|
||||
if (file_exists(sprintf($path, 'normal', $id)))
|
||||
rename(sprintf($path, 'normal', $id), sprintf($path, 'pending', $id));
|
||||
|
||||
// remove resized and thumb
|
||||
if (file_exists(sprintf($path, 'thumb', $id)))
|
||||
unlink(sprintf($path, 'thumb', $id));
|
||||
|
||||
if (file_exists(sprintf($path, 'resized', $id)))
|
||||
unlink(sprintf($path, 'resized', $id));
|
||||
}
|
||||
|
||||
// flag as deleted if not aready
|
||||
$oldEntries = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, GROUP_CONCAT(typeId) FROM ?_screenshots WHERE id IN (?a) GROUP BY `type`', $this->_get['id']);
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET status = ?d, userIdDelete = ?d WHERE id IN (?a)', CC_FLAG_DELETED, User::$id, $this->_get['id']);
|
||||
// deflag db entry as having screenshots
|
||||
foreach ($oldEntries as $type => $typeIds)
|
||||
{
|
||||
$typeIds = explode(',', $typeIds);
|
||||
$toUnflag = DB::Aowow()->selectCol('SELECT typeId AS ARRAY_KEY, IF(BIT_OR(`status`) & ?d, 1, 0) AS hasMore FROM ?_screenshots WHERE `type` = ?d AND typeId IN (?a) GROUP BY typeId HAVING hasMore = 0', CC_FLAG_APPROVED, $type, $typeIds);
|
||||
if ($toUnflag && ($tbl = Type::getClassAttrib($type, 'dataTable')))
|
||||
DB::Aowow()->query('UPDATE '.$tbl.' SET cuFlags = cuFlags & ~?d WHERE id IN (?a)', CUSTOM_HAS_SCREENSHOT, array_keys($toUnflag));
|
||||
}
|
||||
}
|
||||
|
||||
// get: id => ssId, typeid => typeId (but not type..?)
|
||||
// resp: ''
|
||||
protected function ssRelocate() : void
|
||||
{
|
||||
if (!$this->reqGET('id', 'typeid'))
|
||||
{
|
||||
trigger_error('AjaxAdmin::ssRelocate - screenshotId or typeId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$id = $this->_get['id'][0];
|
||||
[$type, $oldTypeId] = array_values(DB::Aowow()->selectRow('SELECT type, typeId FROM ?_screenshots WHERE id = ?d', $id));
|
||||
$typeId = (int)$this->_get['typeid'];
|
||||
|
||||
$tc = Type::newList($type, [['id', $typeId]]);
|
||||
if ($tc && !$tc->error)
|
||||
{
|
||||
// move screenshot
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET typeId = ?d WHERE id = ?d', $typeId, $id);
|
||||
|
||||
// flag target as having screenshot
|
||||
DB::Aowow()->query('UPDATE '.$tc::$dataTable.' SET cuFlags = cuFlags | ?d WHERE id = ?d', CUSTOM_HAS_SCREENSHOT, $typeId);
|
||||
|
||||
// deflag source for having had screenshots (maybe)
|
||||
$ssInfo = DB::Aowow()->selectRow('SELECT IF(BIT_OR(~status) & ?d, 1, 0) AS hasMore FROM ?_screenshots WHERE `status`& ?d AND `type` = ?d AND typeId = ?d', CC_FLAG_DELETED, CC_FLAG_APPROVED, $type, $oldTypeId);
|
||||
if($ssInfo || !$ssInfo['hasMore'])
|
||||
DB::Aowow()->query('UPDATE '.$tc::$dataTable.' SET cuFlags = cuFlags & ~?d WHERE id = ?d', CUSTOM_HAS_SCREENSHOT, $oldTypeId);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxAdmin::ssRelocate - invalid typeId #'.$typeId.' for type #'.$type, E_USER_ERROR);
|
||||
}
|
||||
|
||||
protected function confAdd() : string
|
||||
{
|
||||
$key = trim($this->_get['key']);
|
||||
$val = trim(urldecode($this->_get['val']));
|
||||
|
||||
if ($key === null)
|
||||
return 'empty option name given';
|
||||
|
||||
if (!strlen($key))
|
||||
return 'invalid chars in option name: [a-z 0-9 _ . -] are allowed';
|
||||
|
||||
if (ini_get($key) === false || ini_set($key, $val) === false)
|
||||
return 'this configuration option cannot be set';
|
||||
|
||||
if (DB::Aowow()->selectCell('SELECT 1 FROM ?_config WHERE `flags` & ?d AND `key` = ?', CON_FLAG_PHP, $key))
|
||||
return 'this configuration option is already in use';
|
||||
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_config (`key`, `value`, `cat`, `flags`) VALUES (?, ?, 0, ?d)', $key, $val, CON_FLAG_TYPE_STRING | CON_FLAG_PHP);
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function confRemove() : string
|
||||
{
|
||||
if (!$this->reqGET('key'))
|
||||
return 'invalid configuration option given';
|
||||
|
||||
if (DB::Aowow()->query('DELETE FROM ?_config WHERE `key` = ? AND (`flags` & ?d) = 0', $this->_get['key'], CON_FLAG_PERSISTENT))
|
||||
return '';
|
||||
else
|
||||
return 'option name is either protected or was not found';
|
||||
}
|
||||
|
||||
protected function confUpdate() : string
|
||||
{
|
||||
$key = trim($this->_get['key']);
|
||||
$val = trim(urldecode($this->_get['val']));
|
||||
$msg = '';
|
||||
|
||||
if (!strlen($key))
|
||||
return 'empty option name given';
|
||||
|
||||
$cfg = DB::Aowow()->selectRow('SELECT `flags`, `value` FROM ?_config WHERE `key` = ?', $key);
|
||||
if (!$cfg)
|
||||
return 'configuration option not found';
|
||||
|
||||
if (!($cfg['flags'] & CON_FLAG_TYPE_STRING) && !strlen($val))
|
||||
return 'empty value given';
|
||||
else if ($cfg['flags'] & CON_FLAG_TYPE_INT && !preg_match('/^-?\d+$/i', $val))
|
||||
return "value must be integer";
|
||||
else if ($cfg['flags'] & CON_FLAG_TYPE_FLOAT && !preg_match('/^-?\d*(,|.)?\d+$/i', $val))
|
||||
return "value must be float";
|
||||
else if ($cfg['flags'] & CON_FLAG_TYPE_BOOL && $val != '1')
|
||||
$val = '0';
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', $val, $key);
|
||||
if (!$this->confOnChange($key, $val, $msg))
|
||||
DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', $cfg['value'], $key);
|
||||
|
||||
return $msg;
|
||||
}
|
||||
|
||||
protected function wtSave() : string
|
||||
{
|
||||
if (!$this->reqPOST('id', '__icon'))
|
||||
return '3';
|
||||
|
||||
// save to db
|
||||
DB::Aowow()->query('DELETE FROM ?_account_weightscale_data WHERE id = ?d', $this->_post['id']);
|
||||
DB::Aowow()->query('UPDATE ?_account_weightscales SET `icon`= ? WHERE `id` = ?d', $this->_post['__icon'], $this->_post['id']);
|
||||
|
||||
foreach (explode(',', $this->_post['scale']) as $s)
|
||||
{
|
||||
[$k, $v] = explode(':', $s);
|
||||
|
||||
if (!in_array($k, Util::$weightScales) || $v < 1)
|
||||
continue;
|
||||
|
||||
if (DB::Aowow()->query('INSERT INTO ?_account_weightscale_data VALUES (?d, ?, ?d)', $this->_post['id'], $k, $v) === null)
|
||||
return '1';
|
||||
}
|
||||
|
||||
// write dataset
|
||||
exec('php aowow --build=weightPresets', $out);
|
||||
foreach ($out as $o)
|
||||
if (strstr($o, 'ERR'))
|
||||
return '2';
|
||||
|
||||
// all done
|
||||
return '0';
|
||||
}
|
||||
|
||||
protected function spawnPosFix() : string
|
||||
{
|
||||
if (!$this->reqGET('type', 'guid', 'area', 'floor'))
|
||||
return '-4';
|
||||
|
||||
$guid = $this->_get['guid'];
|
||||
$type = $this->_get['type'];
|
||||
$area = $this->_get['area'];
|
||||
$floor = $this->_get['floor'];
|
||||
|
||||
if (!in_array($type, [Type::NPC, Type::OBJECT, Type::SOUND, Type::AREATRIGGER]))
|
||||
return '-3';
|
||||
|
||||
DB::Aowow()->query('REPLACE INTO ?_spawns_override VALUES (?d, ?d, ?d, ?d, ?d)', $type, $guid, $area, $floor, AOWOW_REVISION);
|
||||
|
||||
if ($wPos = Game::getWorldPosForGUID($type, $guid))
|
||||
{
|
||||
if ($point = Game::worldPosToZonePos($wPos[$guid]['mapId'], $wPos[$guid]['posX'], $wPos[$guid]['posY'], $area, $floor))
|
||||
{
|
||||
$updGUIDs = [$guid];
|
||||
$newPos = array(
|
||||
'posX' => $point[0]['posX'],
|
||||
'posY' => $point[0]['posY'],
|
||||
'areaId' => $point[0]['areaId'],
|
||||
'floor' => $point[0]['floor']
|
||||
);
|
||||
|
||||
// if creature try for waypoints
|
||||
if ($type == Type::NPC)
|
||||
{
|
||||
$jobs = array(
|
||||
'SELECT -w.id AS `entry`, w.point AS `pointId`, w.position_y AS `posX`, w.position_x AS `posY` FROM creature_addon ca JOIN waypoint_data w ON w.id = ca.path_id WHERE ca.guid = ?d AND ca.path_id <> 0',
|
||||
'SELECT `entry`, `pointId`, `location_y` AS `posX`, `location_x` AS `posY` FROM `script_waypoint` WHERE `entry` = ?d',
|
||||
'SELECT `entry`, `pointId`, `position_y` AS `posX`, `position_x` AS `posY` FROM `waypoints` WHERE `entry` = ?d'
|
||||
);
|
||||
|
||||
foreach ($jobs as $idx => $job)
|
||||
{
|
||||
if ($swp = DB::World()->select($job, $idx ? $wPos[$guid]['id'] : $guid))
|
||||
{
|
||||
foreach ($swp as $w)
|
||||
{
|
||||
if ($point = Game::worldPosToZonePos($wPos[$guid]['mapId'], $w['posX'], $w['posY'], $area, $floor))
|
||||
{
|
||||
$p = array(
|
||||
'posX' => $point[0]['posX'],
|
||||
'posY' => $point[0]['posY'],
|
||||
'areaId' => $point[0]['areaId'],
|
||||
'floor' => $point[0]['floor']
|
||||
);
|
||||
}
|
||||
DB::Aowow()->query('UPDATE ?_creature_waypoints SET ?a WHERE `creatureOrPath` = ?d AND `point` = ?d', $p, $w['entry'], $w['pointId']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// also move linked vehicle accessories (on the very same position)
|
||||
$updGUIDs = array_merge($updGUIDs, DB::Aowow()->selectCol('SELECT s2.guid FROM ?_spawns s1 JOIN ?_spawns s2 ON s1.posX = s2.posX AND s1.posY = s2.posY AND
|
||||
s1.areaId = s2.areaId AND s1.floor = s2.floor AND s2.guid < 0 WHERE s1.guid = ?d', $guid));
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_spawns SET ?a WHERE `type` = ?d AND `guid` IN (?a)', $newPos, $type, $updGUIDs);
|
||||
|
||||
return '1';
|
||||
}
|
||||
|
||||
return '-2';
|
||||
}
|
||||
|
||||
return '-1';
|
||||
}
|
||||
|
||||
protected function guideManage() : string
|
||||
{
|
||||
$update = function (int $id, int $status, ?string $msg = null) : bool
|
||||
{
|
||||
if (!DB::Aowow()->query('UPDATE ?_guides SET `status` = ?d WHERE `id` = ?d', $status, $id))
|
||||
return false;
|
||||
|
||||
// set display rev to latest
|
||||
if ($status == GUIDE_STATUS_APPROVED)
|
||||
DB::Aowow()->query('UPDATE ?_guides SET `rev` = (SELECT `rev` FROM ?_articles WHERE `type` = ?d AND `typeId` = ?d ORDER BY `rev` DESC LIMIT 1) WHERE `id` = ?d', Type::GUIDE, $id, $id);
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `date`, `userId`, `status`) VALUES (?d, ?d, ?d, ?d)', $id, time(), User::$id, $status);
|
||||
if ($msg)
|
||||
DB::Aowow()->query('INSERT INTO ?_guides_changelog (`id`, `date`, `userId`, `msg`) VALUES (?d, ?d, ?d, ?)' , $id, time(), User::$id, $msg);
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!$this->_post['id'])
|
||||
trigger_error('AjaxHander::guideManage - malformed request: id: '.$this->_post['id'].', status: '.$this->_post['status']);
|
||||
else
|
||||
{
|
||||
$guide = DB::Aowow()->selectRow('SELECT `userId`, `status` FROM ?_guides WHERE `id` = ?d', $this->_post['id']);
|
||||
if (!$guide)
|
||||
trigger_error('AjaxHander::guideManage - guide #'.$this->_post['id'].' not found');
|
||||
else
|
||||
{
|
||||
if ($this->_post['status'] == $guide['status'])
|
||||
trigger_error('AjaxHander::guideManage - guide #'.$this->_post['id'].' already has status #'.$this->_post['status']);
|
||||
else
|
||||
{
|
||||
if ($this->_post['status'] == GUIDE_STATUS_APPROVED)
|
||||
{
|
||||
if ($update($this->_post['id'], GUIDE_STATUS_APPROVED, $this->_post['msg']))
|
||||
{
|
||||
Util::gainSiteReputation($guide['userId'], SITEREP_ACTION_ARTICLE, ['id' => $this->_post['id']]);
|
||||
return '1';
|
||||
}
|
||||
else
|
||||
return '-2';
|
||||
}
|
||||
else if ($this->_post['status'] == GUIDE_STATUS_REJECTED)
|
||||
return $update($this->_post['id'], GUIDE_STATUS_REJECTED, $this->_post['msg']) ? '1' : '-2';
|
||||
else
|
||||
trigger_error('AjaxHander::guideManage - unhandled status change request');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '-1';
|
||||
}
|
||||
|
||||
|
||||
/***************************/
|
||||
/* additional input filter */
|
||||
/***************************/
|
||||
|
||||
protected static function checkKey(string $val) : string
|
||||
{
|
||||
// expecting string
|
||||
if (preg_match('/[^a-z0-9_\.\-]/i', $val))
|
||||
return '';
|
||||
|
||||
return strtolower($val);
|
||||
}
|
||||
|
||||
protected static function checkUser($val) : string
|
||||
{
|
||||
$n = Util::lower(trim(urldecode($val)));
|
||||
|
||||
if (User::isValidName($n))
|
||||
return $n;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected static function checkScale($val) : string
|
||||
{
|
||||
if (preg_match('/^((\w+:\d+)(,\w+:\d+)*)$/', $val))
|
||||
return $val;
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**********/
|
||||
/* helper */
|
||||
/**********/
|
||||
|
||||
private static function confOnChange(string $key, string $val, string &$msg) : bool
|
||||
{
|
||||
$fn = $buildList = null;
|
||||
|
||||
switch ($key)
|
||||
{
|
||||
case 'battlegroup':
|
||||
$buildList = 'realms,realmMenu';
|
||||
break;
|
||||
case 'name_short':
|
||||
$buildList = 'searchboxBody,demo,searchplugin';
|
||||
break;
|
||||
case 'site_host':
|
||||
$buildList = 'searchplugin,demo,power,searchboxBody';
|
||||
break;
|
||||
case 'static_host':
|
||||
$buildList = 'searchplugin,power,searchboxBody,searchboxScript';
|
||||
break;
|
||||
case 'contact_email':
|
||||
$buildList = 'markup';
|
||||
break;
|
||||
case 'locales':
|
||||
$buildList = 'locales';
|
||||
$msg .= ' * remember to rebuild all static files for the language you just added.<br />';
|
||||
$msg .= ' * you can speed this up by supplying the regionCode to the setup: <pre class="q1">--locales=<regionCodes,> -f</pre>';
|
||||
break;
|
||||
case 'profiler_enable':
|
||||
$buildList = 'realms,realmMenu';
|
||||
$fn = function($x) use (&$msg) {
|
||||
if (!$x)
|
||||
return true;
|
||||
|
||||
return Profiler::queueStart($msg);
|
||||
};
|
||||
break;
|
||||
case 'acc_auth_mode':
|
||||
$fn = function($x) use (&$msg) {
|
||||
if ($x == 1 && !extension_loaded('gmp'))
|
||||
{
|
||||
$msg .= 'PHP extension GMP is required to use TrinityCore as auth source, but is not currently enabled.<br />';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
break;
|
||||
default: // nothing to do, everything is fine
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($buildList)
|
||||
{
|
||||
// we need to use exec as build() can only be run from CLI
|
||||
exec('php aowow --build='.$buildList, $out);
|
||||
foreach ($out as $o)
|
||||
if (strstr($o, 'ERR'))
|
||||
$msg .= explode('0m]', $o)[1]."<br />\n";
|
||||
}
|
||||
|
||||
return $fn ? $fn($val) : true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('invalid access');
|
||||
|
||||
class AjaxArenaTeam extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['resync', 'status'];
|
||||
protected $_get = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkIdList' ],
|
||||
'profile' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkEmptySet'],
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$this->params)
|
||||
return;
|
||||
|
||||
switch ($this->params[0])
|
||||
{
|
||||
case 'resync':
|
||||
$this->handler = 'handleResync';
|
||||
break;
|
||||
case 'status':
|
||||
$this->handler = 'handleStatus';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional, not used]
|
||||
profile: <empty> [optional, also get related chars]
|
||||
return: 1
|
||||
*/
|
||||
protected function handleResync() : string
|
||||
{
|
||||
if ($teams = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_arena_team WHERE id IN (?a)', $this->_get['id']))
|
||||
foreach ($teams as $t)
|
||||
Profiler::scheduleResync(Type::ARENA_TEAM, $t['realm'], $t['realmGUID']);
|
||||
|
||||
if ($this->_get['profile'])
|
||||
if ($chars = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_profiles p JOIN ?_profiler_arena_team_member atm ON atm.profileId = p.id WHERE atm.arenaTeamId IN (?a)', $this->_get['id']))
|
||||
foreach ($chars as $c)
|
||||
Profiler::scheduleResync(Type::PROFILE, $c['realm'], $c['realmGUID']);
|
||||
|
||||
return '1';
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
<status object>
|
||||
[
|
||||
nQueueProcesses,
|
||||
[statusCode, timeToRefresh, curQueuePos, errorCode, nResyncTries],
|
||||
[<anotherStatus>]
|
||||
...
|
||||
]
|
||||
|
||||
not all fields are required, if zero they are omitted
|
||||
statusCode:
|
||||
0: end the request
|
||||
1: waiting
|
||||
2: working...
|
||||
3: ready; click to view
|
||||
4: error / retry
|
||||
errorCode:
|
||||
0: unk error
|
||||
1: char does not exist
|
||||
2: armory gone
|
||||
*/
|
||||
protected function handleStatus() : string
|
||||
{
|
||||
$response = Profiler::resyncStatus(Type::ARENA_TEAM, $this->_get['id']);
|
||||
return Util::toJSON($response);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,475 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxComment extends AjaxHandler
|
||||
{
|
||||
const COMMENT_LENGTH_MIN = 10;
|
||||
const COMMENT_LENGTH_MAX = 7500;
|
||||
const REPLY_LENGTH_MIN = 15;
|
||||
const REPLY_LENGTH_MAX = 600;
|
||||
|
||||
protected $_post = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkIdListUnsigned'],
|
||||
'body' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkFulltext' ],
|
||||
'commentbody' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkFulltext' ],
|
||||
'response' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
|
||||
'reason' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
|
||||
'remove' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'commentId' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'replyId' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'sticky' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
// 'username' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW ]
|
||||
);
|
||||
|
||||
protected $_get = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt'],
|
||||
'type' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt'],
|
||||
'typeid' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt'],
|
||||
'rating' => ['filter' => FILTER_SANITIZE_NUMBER_INT]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$this->params || count($this->params) != 1)
|
||||
return;
|
||||
|
||||
// note: return values must be formated as STRICT json!
|
||||
|
||||
// select handler
|
||||
if ($this->params[0] == 'add')
|
||||
$this->handler = 'handleCommentAdd';
|
||||
else if ($this->params[0] == 'edit')
|
||||
$this->handler = 'handleCommentEdit';
|
||||
else if ($this->params[0] == 'delete')
|
||||
$this->handler = 'handleCommentDelete';
|
||||
else if ($this->params[0] == 'undelete')
|
||||
$this->handler = 'handleCommentUndelete';
|
||||
else if ($this->params[0] == 'rating') // up/down - distribution
|
||||
$this->handler = 'handleCommentRating';
|
||||
else if ($this->params[0] == 'vote') // up, down and remove
|
||||
$this->handler = 'handleCommentVote';
|
||||
else if ($this->params[0] == 'sticky') // toggle flag
|
||||
$this->handler = 'handleCommentSticky';
|
||||
else if ($this->params[0] == 'out-of-date') // toggle flag
|
||||
$this->handler = 'handleCommentOutOfDate';
|
||||
else if ($this->params[0] == 'show-replies')
|
||||
$this->handler = 'handleCommentShowReplies';
|
||||
else if ($this->params[0] == 'add-reply') // also returns all replies on success
|
||||
$this->handler = 'handleReplyAdd';
|
||||
else if ($this->params[0] == 'edit-reply') // also returns all replies on success
|
||||
$this->handler = 'handleReplyEdit';
|
||||
else if ($this->params[0] == 'detach-reply')
|
||||
$this->handler = 'handleReplyDetach';
|
||||
else if ($this->params[0] == 'delete-reply')
|
||||
$this->handler = 'handleReplyDelete';
|
||||
else if ($this->params[0] == 'flag-reply')
|
||||
$this->handler = 'handleReplyFlag';
|
||||
else if ($this->params[0] == 'upvote-reply')
|
||||
$this->handler = 'handleReplyUpvote';
|
||||
else if ($this->params[0] == 'downvote-reply')
|
||||
$this->handler = 'handleReplyDownvote';
|
||||
}
|
||||
|
||||
// i .. have problems believing, that everything uses nifty ajax while adding comments requires a brutal header(Loacation: <wherever>), yet, thats how it is
|
||||
protected function handleCommentAdd() : string
|
||||
{
|
||||
if (!$this->_get['typeid'] || !$this->_get['type'] || !Type::exists($this->_get['type']))
|
||||
{
|
||||
trigger_error('AjaxComment::handleCommentAdd - malforemd request received', E_USER_ERROR);
|
||||
return ''; // whatever, we cant even send him back
|
||||
}
|
||||
|
||||
// this type cannot be commented on
|
||||
if (!Type::checkClassAttrib($this->_get['type'], 'contribute', CONTRIBUTE_CO))
|
||||
{
|
||||
trigger_error('AjaxComment::handleCommentAdd - tried to comment on unsupported type #'.$this->_get['type'], E_USER_ERROR);
|
||||
return '';
|
||||
}
|
||||
|
||||
// trim to max length
|
||||
if (!User::isInGroup(U_GROUP_MODERATOR) && mb_strlen($this->_post['commentbody']) > (self::COMMENT_LENGTH_MAX * (User::isPremium() ? 3 : 1)))
|
||||
$this->_post['commentbody'] = mb_substr($this->_post['commentbody'], 0, (self::COMMENT_LENGTH_MAX * (User::isPremium() ? 3 : 1)));
|
||||
|
||||
if (User::canComment())
|
||||
{
|
||||
if (!empty($this->_post['commentbody']) && mb_strlen($this->_post['commentbody']) >= self::COMMENT_LENGTH_MIN)
|
||||
{
|
||||
if ($postIdx = DB::Aowow()->query('INSERT INTO ?_comments (type, typeId, userId, roles, body, date) VALUES (?d, ?d, ?d, ?d, ?, UNIX_TIMESTAMP())', $this->_get['type'], $this->_get['typeid'], User::$id, User::$groups, $this->_post['commentbody']))
|
||||
{
|
||||
Util::gainSiteReputation(User::$id, SITEREP_ACTION_COMMENT, ['id' => $postIdx]);
|
||||
|
||||
// every comment starts with a rating of +1 and i guess the simplest thing to do is create a db-entry with the system as owner
|
||||
DB::Aowow()->query('INSERT INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, 0, 1)', RATING_COMMENT, $postIdx);
|
||||
|
||||
// flag target with hasComment
|
||||
if ($tbl = Type::getClassAttrib($this->_get['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE '.$tbl.' SET cuFlags = cuFlags | ?d WHERE id = ?d', CUSTOM_HAS_COMMENT, $this->_get['typeid']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$_SESSION['error']['co'] = Lang::main('intError');
|
||||
trigger_error('AjaxComment::handleCommentAdd - write to db failed', E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
$_SESSION['error']['co'] = Lang::main('textLength', [mb_strlen($this->_post['commentbody']), self::COMMENT_LENGTH_MIN, self::COMMENT_LENGTH_MAX]);
|
||||
}
|
||||
else
|
||||
$_SESSION['error']['co'] = Lang::main('cannotComment');
|
||||
|
||||
$this->doRedirect = true;
|
||||
|
||||
$idOrUrl = $this->_get['typeid'];
|
||||
if ($this->_get['type'] == Type::GUIDE)
|
||||
if ($_ = DB::Aowow()->selectCell('SELECT `url` FROM ?_guides WHERE `id` = ?d', $this->_get['typeid']))
|
||||
$idOrUrl = $_;
|
||||
|
||||
return '?'.Type::getFileString($this->_get['type']).'='.$idOrUrl.'#comments';
|
||||
}
|
||||
|
||||
protected function handleCommentEdit() : void
|
||||
{
|
||||
if (!User::canComment() && !User::isInGroup(U_GROUP_MODERATOR))
|
||||
{
|
||||
trigger_error('AjaxComment::handleCommentEdit - user #'.User::$id.' not allowed to edit', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->_get['id'] || !$this->_post['body'])
|
||||
{
|
||||
trigger_error('AjaxComment::handleCommentEdit - malforemd request received', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mb_strlen($this->_post['body']) < self::COMMENT_LENGTH_MIN)
|
||||
return; // no point in reporting this trifle
|
||||
|
||||
// trim to max length
|
||||
if (!User::isInGroup(U_GROUP_MODERATOR) && mb_strlen($this->_post['body']) > (self::COMMENT_LENGTH_MAX * (User::isPremium() ? 3 : 1)))
|
||||
$this->_post['body'] = mb_substr($this->_post['body'], 0, (self::COMMENT_LENGTH_MAX * (User::isPremium() ? 3 : 1)));
|
||||
|
||||
$update = array(
|
||||
'body' => $this->_post['body'],
|
||||
'editUserId' => User::$id,
|
||||
'editDate' => time()
|
||||
);
|
||||
|
||||
if (User::isInGroup(U_GROUP_MODERATOR))
|
||||
{
|
||||
$update['responseBody'] = !$this->_post['response'] ? '' : $this->_post['response'];
|
||||
$update['responseUserId'] = !$this->_post['response'] ? 0 : User::$id;
|
||||
$update['responseRoles'] = !$this->_post['response'] ? 0 : User::$groups;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_comments SET editCount = editCount + 1, ?a WHERE id = ?d', $update, $this->_get['id']);
|
||||
}
|
||||
|
||||
protected function handleCommentDelete() : void
|
||||
{
|
||||
if (!$this->_post['id'] || !User::$id)
|
||||
{
|
||||
trigger_error('AjaxComment::handleCommentDelete - commentId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// in theory, there is a username passed alongside... lets just use the current user (see user.js)
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags | ?d, deleteUserId = ?d, deleteDate = UNIX_TIMESTAMP() WHERE id IN (?a){ AND userId = ?d}',
|
||||
CC_FLAG_DELETED,
|
||||
User::$id,
|
||||
$this->_post['id'],
|
||||
User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id
|
||||
);
|
||||
|
||||
// deflag hasComment
|
||||
if ($ok)
|
||||
{
|
||||
$coInfo = DB::Aowow()->selectRow('SELECT IF(BIT_OR(~b.flags) & ?d, 1, 0) as hasMore, b.type, b.typeId FROM ?_comments a JOIN ?_comments b ON a.type = b.type AND a.typeId = b.typeId WHERE a.id = ?d',
|
||||
CC_FLAG_DELETED,
|
||||
$this->_post['id']
|
||||
);
|
||||
|
||||
if (!$coInfo['hasMore'] && ($tbl = Type::getClassAttrib($coInfo['type'], 'dataTable')))
|
||||
DB::Aowow()->query('UPDATE '.$tbl.' SET cuFlags = cuFlags & ~?d WHERE id = ?d', CUSTOM_HAS_COMMENT, $coInfo['typeId']);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxComment::handleCommentDelete - user #'.User::$id.' could not flag comment #'.$this->_post['id'].' as deleted', E_USER_ERROR);
|
||||
}
|
||||
|
||||
protected function handleCommentUndelete() : void
|
||||
{
|
||||
if (!$this->_post['id'] || !User::$id)
|
||||
{
|
||||
trigger_error('AjaxComment::handleCommentUndelete - commentId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// in theory, there is a username passed alongside... lets just use the current user (see user.js)
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags & ~?d WHERE id IN (?a){ AND userId = deleteUserId AND deleteUserId = ?d}',
|
||||
CC_FLAG_DELETED,
|
||||
$this->_post['id'],
|
||||
User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id
|
||||
);
|
||||
|
||||
// reflag hasComment
|
||||
if ($ok)
|
||||
{
|
||||
$coInfo = DB::Aowow()->selectRow('SELECT type, typeId FROM ?_comments WHERE id = ?d', $this->_post['id']);
|
||||
if ($tbl = Type::getClassAttrib($coInfo['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE '.$tbl.' SET cuFlags = cuFlags | ?d WHERE id = ?d', CUSTOM_HAS_COMMENT, $coInfo['typeId']);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxComment::handleCommentUndelete - user #'.User::$id.' could not unflag comment #'.$this->_post['id'].' as deleted', E_USER_ERROR);
|
||||
}
|
||||
|
||||
protected function handleCommentRating() : string
|
||||
{
|
||||
if (!$this->_get['id'])
|
||||
return Util::toJSON(['success' => 0]);
|
||||
|
||||
if ($votes = DB::Aowow()->selectRow('SELECT 1 AS success, SUM(IF(`value` > 0, `value`, 0)) AS up, SUM(IF(`value` < 0, -`value`, 0)) AS down FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d AND userId <> 0 GROUP BY `entry`', RATING_COMMENT, $this->_get['id']))
|
||||
return Util::toJSON($votes);
|
||||
else
|
||||
return Util::toJSON(['success' => 1, 'up' => 0, 'down' => 0]);
|
||||
}
|
||||
|
||||
protected function handleCommentVote() : string
|
||||
{
|
||||
if (!User::$id || !$this->_get['id'] || !$this->_get['rating'])
|
||||
return Util::toJSON(['error' => 1, 'message' => Lang::main('genericError')]);
|
||||
|
||||
$target = DB::Aowow()->selectRow('SELECT c.`userId` AS owner, ur.`value` FROM ?_comments c LEFT JOIN ?_user_ratings ur ON ur.`type` = ?d AND ur.`entry` = c.id AND ur.`userId` = ?d WHERE c.id = ?d', RATING_COMMENT, User::$id, $this->_get['id']);
|
||||
$val = User::canSupervote() ? 2 : 1;
|
||||
if ($this->_get['rating'] < 0)
|
||||
$val *= -1;
|
||||
|
||||
if (User::getCurDailyVotes() <= 0)
|
||||
return Util::toJSON(['error' => 1, 'message' => Lang::main('tooManyVotes')]);
|
||||
else if (!$target || $val != $this->_get['rating'])
|
||||
return Util::toJSON(['error' => 1, 'message' => Lang::main('genericError')]);
|
||||
else if (($val > 0 && !User::canUpvote()) || ($val < 0 && !User::canDownvote()))
|
||||
return Util::toJSON(['error' => 1, 'message' => Lang::main('bannedRating')]);
|
||||
|
||||
$ok = false;
|
||||
// old and new have same sign; undo vote (user may have gained/lost access to superVote in the meantime)
|
||||
if ($target['value'] && ($target['value'] < 0) == ($val < 0))
|
||||
$ok = DB::Aowow()->query('DELETE FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d AND `userId` = ?d', RATING_COMMENT, $this->_get['id'], User::$id);
|
||||
else // replace, because we may be overwriting an old, opposing vote
|
||||
if ($ok = DB::Aowow()->query('REPLACE INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, ?d, ?d)', RATING_COMMENT, (int)$this->_get['id'], User::$id, $val))
|
||||
User::decrementDailyVotes(); // do not refund retracted votes!
|
||||
|
||||
if (!$ok)
|
||||
return Util::toJSON(['error' => 1, 'message' => Lang::main('genericError')]);
|
||||
|
||||
if ($val > 0) // gain rep
|
||||
Util::gainSiteReputation($target['owner'], SITEREP_ACTION_UPVOTED, ['id' => $this->_get['id'], 'voterId' => User::$id]);
|
||||
else if ($val < 0)
|
||||
Util::gainSiteReputation($target['owner'], SITEREP_ACTION_DOWNVOTED, ['id' => $this->_get['id'], 'voterId' => User::$id]);
|
||||
|
||||
return Util::toJSON(['error' => 0]);
|
||||
}
|
||||
|
||||
protected function handleCommentSticky() : void
|
||||
{
|
||||
if (!$this->_post['id'] || !User::isInGroup(U_GROUP_MODERATOR))
|
||||
{
|
||||
trigger_error('AjaxComment::handleCommentSticky - commentId empty or user #'.User::$id.' not moderator', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->_post['sticky'])
|
||||
DB::Aowow()->query('UPDATE ?_comments SET flags = flags | ?d WHERE id = ?d', CC_FLAG_STICKY, $this->_post['id'][0]);
|
||||
else
|
||||
DB::Aowow()->query('UPDATE ?_comments SET flags = flags & ~?d WHERE id = ?d', CC_FLAG_STICKY, $this->_post['id'][0]);
|
||||
}
|
||||
|
||||
protected function handleCommentOutOfDate() : string
|
||||
{
|
||||
$this->contentType = MIME_TYPE_TEXT;
|
||||
|
||||
if (!$this->_post['id'])
|
||||
{
|
||||
trigger_error('AjaxComment::handleCommentOutOfDate - commentId empty', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
$ok = false;
|
||||
if (User::isInGroup(U_GROUP_MODERATOR)) // directly mark as outdated
|
||||
{
|
||||
if (!$this->_post['remove'])
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags | 0x4 WHERE id = ?d', $this->_post['id'][0]);
|
||||
else
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags & ~0x4 WHERE id = ?d', $this->_post['id'][0]);
|
||||
}
|
||||
else if (DB::Aowow()->selectCell('SELECT 1 FROM ?_reports WHERE `mode` = ?d AND `reason`= ?d AND `subject` = ?d AND `userId` = ?d', 1, 17, $this->_post['id'][0], User::$id))
|
||||
return Lang::main('alreadyReport');
|
||||
else if (User::$id && !$this->_post['reason'] || mb_strlen($this->_post['reason']) < self::REPLY_LENGTH_MIN)
|
||||
return Lang::main('textTooShort');
|
||||
else if (User::$id) // only report as outdated
|
||||
$ok = Util::createReport(1, 17, $this->_post['id'][0], '[Outdated Comment] '.$this->_post['reason']);
|
||||
|
||||
if ($ok) // this one is very special; as in: completely retarded
|
||||
return 'ok'; // the script expects the actual characters 'ok' not some string like "ok"
|
||||
else
|
||||
trigger_error('AjaxComment::handleCommentOutOfDate - failed to update comment in db', E_USER_ERROR);
|
||||
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
protected function handleCommentShowReplies() : string
|
||||
{
|
||||
return Util::toJSON(!$this->_get['id'] ? [] : CommunityContent::getCommentReplies($this->_get['id']));
|
||||
}
|
||||
|
||||
protected function handleReplyAdd() : string
|
||||
{
|
||||
$this->contentType = MIME_TYPE_TEXT;
|
||||
|
||||
if (!User::canComment())
|
||||
return Lang::main('cannotComment');
|
||||
|
||||
if (!$this->_post['commentId'] || !DB::Aowow()->selectCell('SELECT 1 FROM ?_comments WHERE id = ?d', $this->_post['commentId']))
|
||||
{
|
||||
trigger_error('AjaxComment::handleReplyAdd - comment #'.$this->_post['commentId'].' does not exist', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
if (!$this->_post['body'] || mb_strlen($this->_post['body']) < self::REPLY_LENGTH_MIN || mb_strlen($this->_post['body']) > self::REPLY_LENGTH_MAX)
|
||||
return Lang::main('textLength', [mb_strlen($this->_post['body']), self::REPLY_LENGTH_MIN, self::REPLY_LENGTH_MAX]);
|
||||
|
||||
if (DB::Aowow()->query('INSERT INTO ?_comments (`userId`, `roles`, `body`, `date`, `replyTo`) VALUES (?d, ?d, ?, UNIX_TIMESTAMP(), ?d)', User::$id, User::$groups, $this->_post['body'], $this->_post['commentId']))
|
||||
return Util::toJSON(CommunityContent::getCommentReplies($this->_post['commentId']));
|
||||
|
||||
trigger_error('AjaxComment::handleReplyAdd - write to db failed', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
protected function handleReplyEdit() : string
|
||||
{
|
||||
$this->contentType = MIME_TYPE_TEXT;
|
||||
|
||||
if (!User::canComment())
|
||||
return Lang::main('cannotComment');
|
||||
|
||||
if ((!$this->_post['replyId'] || !$this->_post['commentId']) && DB::Aowow()->selectCell('SELECT COUNT(1) FROM ?_comments WHERE id IN (?a)', [$this->_post['replyId'], $this->_post['commentId']]))
|
||||
{
|
||||
trigger_error('AjaxComment::handleReplyEdit - comment #'.$this->_post['commentId'].' or reply #'.$this->_post['replyId'].' does not exist', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
if (!$this->_post['body'] || mb_strlen($this->_post['body']) < self::REPLY_LENGTH_MIN || mb_strlen($this->_post['body']) > self::REPLY_LENGTH_MAX)
|
||||
return Lang::main('textLength', [mb_strlen($this->_post['body']), self::REPLY_LENGTH_MIN, self::REPLY_LENGTH_MAX]);
|
||||
|
||||
if (DB::Aowow()->query('UPDATE ?_comments SET body = ?, editUserId = ?d, editDate = UNIX_TIMESTAMP(), editCount = editCount + 1 WHERE id = ?d AND replyTo = ?d{ AND userId = ?d}',
|
||||
$this->_post['body'], User::$id, $this->_post['replyId'], $this->_post['commentId'], User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id))
|
||||
return Util::toJSON(CommunityContent::getCommentReplies($this->_post['commentId']));
|
||||
|
||||
trigger_error('AjaxComment::handleReplyEdit - write to db failed', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
protected function handleReplyDetach() : void
|
||||
{
|
||||
if (!$this->_post['id'] || !User::isInGroup(U_GROUP_MODERATOR))
|
||||
{
|
||||
trigger_error('AjaxComment::handleReplyDetach - commentId empty or user #'.User::$id.' not moderator', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_comments c1, ?_comments c2 SET c1.replyTo = 0, c1.type = c2.type, c1.typeId = c2.typeId WHERE c1.replyTo = c2.id AND c1.id = ?d', $this->_post['id'][0]);
|
||||
}
|
||||
|
||||
protected function handleReplyDelete() : void
|
||||
{
|
||||
if (!User::$id || !$this->_post['id'])
|
||||
{
|
||||
trigger_error('AjaxComment::handleReplyDelete - commentId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DB::Aowow()->query('DELETE FROM ?_comments WHERE id = ?d{ AND userId = ?d}', $this->_post['id'][0], User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id))
|
||||
DB::Aowow()->query('DELETE FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d', RATING_COMMENT, $this->_post['id'][0]);
|
||||
else
|
||||
trigger_error('AjaxComment::handleReplyDelete - deleting comment #'.$this->_post['id'][0].' by user #'.User::$id.' from db failed', E_USER_ERROR);
|
||||
}
|
||||
|
||||
protected function handleReplyFlag() : void
|
||||
{
|
||||
if (!User::$id || !$this->_post['id'])
|
||||
{
|
||||
trigger_error('AjaxComment::handleReplyFlag - commentId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
Util::createReport(1, 19, $this->_post['id'][0], '[General Reply Report]');
|
||||
}
|
||||
|
||||
protected function handleReplyUpvote() : void
|
||||
{
|
||||
if (!$this->_post['id'] || !User::canUpvote())
|
||||
{
|
||||
trigger_error('AjaxComment::handleReplyUpvote - commentId empty or user not allowed to vote', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$owner = DB::Aowow()->selectCell('SELECT userId FROM ?_comments WHERE id = ?d', $this->_post['id'][0]);
|
||||
if (!$owner)
|
||||
{
|
||||
trigger_error('AjaxComment::handleReplyUpvote - comment #'.$this->_post['id'][0].' not found in db', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$ok = DB::Aowow()->query(
|
||||
'INSERT INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, ?d, ?d)',
|
||||
RATING_COMMENT,
|
||||
$this->_post['id'][0],
|
||||
User::$id,
|
||||
User::canSupervote() ? 2 : 1
|
||||
);
|
||||
|
||||
if ($ok)
|
||||
{
|
||||
Util::gainSiteReputation($owner, SITEREP_ACTION_UPVOTED, ['id' => $this->_post['id'][0], 'voterId' => User::$id]);
|
||||
User::decrementDailyVotes();
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxComment::handleReplyUpvote - write to db failed', E_USER_ERROR);
|
||||
}
|
||||
|
||||
protected function handleReplyDownvote() : void
|
||||
{
|
||||
if (!$this->_post['id'] || !User::canDownvote())
|
||||
{
|
||||
trigger_error('AjaxComment::handleReplyDownvote - commentId empty or user not allowed to vote', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$owner = DB::Aowow()->selectCell('SELECT userId FROM ?_comments WHERE id = ?d', $this->_post['id'][0]);
|
||||
if (!$owner)
|
||||
{
|
||||
trigger_error('AjaxComment::handleReplyDownvote - comment #'.$this->_post['id'][0].' not found in db', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$ok = DB::Aowow()->query(
|
||||
'INSERT INTO ?_user_ratings (`type`, `entry`, `userId`, `value`) VALUES (?d, ?d, ?d, ?d)',
|
||||
RATING_COMMENT,
|
||||
$this->_post['id'][0],
|
||||
User::$id,
|
||||
User::canSupervote() ? -2 : -1
|
||||
);
|
||||
|
||||
if ($ok)
|
||||
{
|
||||
Util::gainSiteReputation($owner, SITEREP_ACTION_DOWNVOTED, ['id' => $this->_post['id'][0], 'voterId' => User::$id]);
|
||||
User::decrementDailyVotes();
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxComment::handleReplyDownvote - write to db failed', E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,93 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxContactus extends AjaxHandler
|
||||
{
|
||||
protected $_post = array(
|
||||
'mode' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'reason' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'ua' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'appname' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'page' => ['filter' => FILTER_SANITIZE_URL],
|
||||
'desc' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'id' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'relatedurl' => ['filter' => FILTER_SANITIZE_URL],
|
||||
'email' => ['filter' => FILTER_SANITIZE_EMAIL]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
// always this one
|
||||
$this->handler = 'handleContactUs';
|
||||
}
|
||||
|
||||
/* responses
|
||||
0: success
|
||||
1: captcha invalid
|
||||
2: description too long
|
||||
3: reason missing
|
||||
7: already reported
|
||||
$: prints response
|
||||
*/
|
||||
protected function handleContactUs() : string
|
||||
{
|
||||
$mode = $this->_post['mode'];
|
||||
$rsn = $this->_post['reason'];
|
||||
$ua = $this->_post['ua'];
|
||||
$app = $this->_post['appname'];
|
||||
$url = $this->_post['page'];
|
||||
$desc = $this->_post['desc'];
|
||||
$subj = $this->_post['id'];
|
||||
|
||||
$contexts = array(
|
||||
[1, 2, 3, 4, 5, 6, 7, 8],
|
||||
[15, 16, 17, 18, 19, 20],
|
||||
[30, 31, 32, 33, 34, 35, 36, 37],
|
||||
[45, 46, 47, 48],
|
||||
[60, 61],
|
||||
[45, 46, 47, 48],
|
||||
[45, 46, 48]
|
||||
);
|
||||
|
||||
if ($mode === null || $rsn === null || $ua === null || $app === null || $url === null)
|
||||
{
|
||||
trigger_error('AjaxContactus::handleContactUs - malformed contact request received', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
if (!isset($contexts[$mode]) || !in_array($rsn, $contexts[$mode]))
|
||||
{
|
||||
trigger_error('AjaxContactus::handleContactUs - report has invalid context (mode:'.$mode.' / reason:'.$rsn.')', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
if (!$desc)
|
||||
return 3;
|
||||
|
||||
if (mb_strlen($desc) > 500)
|
||||
return 2;
|
||||
|
||||
if (!User::$id && !User::$ip)
|
||||
{
|
||||
trigger_error('AjaxContactus::handleContactUs - could not determine IP for anonymous user', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
// check already reported
|
||||
$field = User::$id ? 'userId' : 'ip';
|
||||
if (DB::Aowow()->selectCell('SELECT 1 FROM ?_reports WHERE `mode` = ?d AND `reason`= ?d AND `subject` = ?d AND ?# = ?', $mode, $rsn, $subj, $field, User::$id ?: User::$ip))
|
||||
return 7;
|
||||
|
||||
if (Util::createReport($mode, $rsn, $subj, $desc, $ua, $app, $url, $this->_post['relatedurl'], $this->_post['email']))
|
||||
return 0;
|
||||
|
||||
trigger_error('AjaxContactus::handleContactUs - write to db failed', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxCookie extends AjaxHandler
|
||||
{
|
||||
public function __construct(array $params)
|
||||
{
|
||||
// note that parent::__construct has to come after this
|
||||
if (!$params || !User::$id)
|
||||
return;
|
||||
|
||||
$this->_get = array(
|
||||
$params[0] => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
);
|
||||
|
||||
// NOW we know, what to expect and sanitize
|
||||
parent::__construct($params);
|
||||
|
||||
// always this one
|
||||
$this->handler = 'handleCookie';
|
||||
}
|
||||
|
||||
/* responses
|
||||
0: success
|
||||
$: silent error
|
||||
*/
|
||||
protected function handleCookie() : string
|
||||
{
|
||||
if (User::$id && $this->params && $this->_get[$this->params[0]])
|
||||
{
|
||||
if (DB::Aowow()->query('REPLACE INTO ?_account_cookies VALUES (?d, ?, ?)', User::$id, $this->params[0], $this->_get[$this->params[0]]))
|
||||
return '0';
|
||||
else
|
||||
trigger_error('AjaxCookie::handleCookie - write to db failed', E_USER_ERROR);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxCookie::handleCookie - malformed request received', E_USER_ERROR);
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,142 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxData extends AjaxHandler
|
||||
{
|
||||
protected $_get = array(
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkLocale'],
|
||||
't' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
|
||||
'catg' => ['filter' => FILTER_SANITIZE_NUMBER_INT ],
|
||||
'skill' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxData::checkSkill' ],
|
||||
'class' => ['filter' => FILTER_SANITIZE_NUMBER_INT ],
|
||||
'callback' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxData::checkCallback' ]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (is_numeric($this->_get['locale']))
|
||||
User::useLocale($this->_get['locale']);
|
||||
|
||||
// always this one
|
||||
$this->handler = 'handleData';
|
||||
}
|
||||
|
||||
/* responses
|
||||
<string>
|
||||
*/
|
||||
protected function handleData() : string
|
||||
{
|
||||
$result = '';
|
||||
|
||||
// different data can be strung together
|
||||
foreach ($this->params as $set)
|
||||
{
|
||||
// requires valid token to hinder automated access
|
||||
if ($set != 'item-scaling' && (!$this->_get['t'] || empty($_SESSION['dataKey']) || $this->_get['t'] != $_SESSION['dataKey']))
|
||||
{
|
||||
trigger_error('AjaxData::handleData - session data key empty or expired', E_USER_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($set)
|
||||
{
|
||||
/* issue on no initial data:
|
||||
when we loadOnDemand, the jScript tries to generate the catg-tree before it is initialized
|
||||
it cant be initialized, without loading the data as empty catg are omitted
|
||||
loading the data triggers the generation of the catg-tree
|
||||
*/
|
||||
case 'factions':
|
||||
$result .= $this->loadProfilerData($set);
|
||||
break;
|
||||
case 'companions':
|
||||
$result .= $this->loadProfilerData($set, '778');
|
||||
break;
|
||||
case 'mounts':
|
||||
$result .= $this->loadProfilerData($set, '777');
|
||||
break;
|
||||
case 'quests':
|
||||
// &partial: im not doing this right
|
||||
// it expects a full quest dump on first lookup but will query subCats again if clicked..?
|
||||
// for now omiting the detail clicks with empty results and just set catg update
|
||||
$catg = isset($this->_get['catg']) ? $this->_get['catg'] : 'null';
|
||||
if ($catg == 'null')
|
||||
$result .= $this->loadProfilerData($set);
|
||||
else if ($this->_get['callback'])
|
||||
$result .= "\n\$WowheadProfiler.loadOnDemand('quests', ".$catg.");\n";
|
||||
|
||||
break;
|
||||
case 'recipes':
|
||||
if (!$this->_get['callback'] || !$this->_get['skill'])
|
||||
break;
|
||||
|
||||
foreach ($this->_get['skill'] as $s)
|
||||
Util::loadStaticFile('p-recipes-'.$s, $result, true);
|
||||
|
||||
Util::loadStaticFile('p-recipes-sec', $result, true);
|
||||
$result .= "\n\$WowheadProfiler.loadOnDemand('recipes', null);\n";
|
||||
|
||||
break;
|
||||
// locale independant
|
||||
case 'quick-excludes':
|
||||
case 'zones':
|
||||
case 'weight-presets':
|
||||
case 'item-scaling':
|
||||
case 'realms':
|
||||
case 'statistics':
|
||||
if (!Util::loadStaticFile($set, $result) && CFG_DEBUG)
|
||||
$result .= "alert('could not fetch static data: ".$set."');";
|
||||
|
||||
$result .= "\n\n";
|
||||
break;
|
||||
// localized
|
||||
case 'talents':
|
||||
if ($_ = $this->_get['class'])
|
||||
$set .= "-".$_;
|
||||
case 'achievements':
|
||||
case 'pet-talents':
|
||||
case 'glyphs':
|
||||
case 'gems':
|
||||
case 'enchants':
|
||||
case 'itemsets':
|
||||
case 'pets':
|
||||
if (!Util::loadStaticFile($set, $result, true) && CFG_DEBUG)
|
||||
$result .= "alert('could not fetch static data: ".$set." for locale: ".User::$localeString."');";
|
||||
|
||||
$result .= "\n\n";
|
||||
break;
|
||||
default:
|
||||
trigger_error('AjaxData::handleData - invalid file "'.$set.'" in request', E_USER_ERROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected static function checkSkill(string $val) : array
|
||||
{
|
||||
return array_intersect([171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, 185, 129, 356], explode(',', $val));
|
||||
}
|
||||
|
||||
protected static function checkCallback(string $val) : bool
|
||||
{
|
||||
return substr($val, 0, 29) === '$WowheadProfiler.loadOnDemand';
|
||||
}
|
||||
|
||||
private function loadProfilerData(string $file, string $catg = 'null') : string
|
||||
{
|
||||
$result = '';
|
||||
if ($this->_get['callback'])
|
||||
if (Util::loadStaticFile('p-'.$file, $result, true))
|
||||
$result .= "\n\$WowheadProfiler.loadOnDemand('".$file."', ".$catg.");\n";
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxEdit extends AjaxHandler
|
||||
{
|
||||
protected $_get = array(
|
||||
'qqfile' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'guide' => ['filter' => FILTER_SANITIZE_NUMBER_INT]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$params)
|
||||
return;
|
||||
|
||||
if ($params[0] == 'image')
|
||||
$this->handler = 'handleUpload';
|
||||
else if ($params[0] == 'article') // has it's own editor page
|
||||
$this->handler = null;
|
||||
}
|
||||
|
||||
/*
|
||||
success: bool
|
||||
id: image enumerator
|
||||
type: 3 ? png : jpg
|
||||
name: old filename
|
||||
error: errString
|
||||
*/
|
||||
protected function handleUpload() : string
|
||||
{
|
||||
if (!User::$id || $this->_get['guide'] != 1)
|
||||
return Util::toJSON(['success' => false, 'error' => '']);
|
||||
|
||||
require_once('includes/libs/qqFileUploader.class.php');
|
||||
|
||||
$targetPath = 'static/uploads/guide/images/';
|
||||
$tmpPath = 'static/uploads/temp/';
|
||||
$tmpFile = User::$displayName.'-'.Type::GUIDE.'-0-'.Util::createHash(16);
|
||||
|
||||
$uploader = new qqFileUploader(['jpg', 'jpeg', 'png'], 10 * 1024 * 1024);
|
||||
$result = $uploader->handleUpload($tmpPath, $tmpFile, true);
|
||||
|
||||
if (isset($result['success']))
|
||||
{
|
||||
$finfo = new finfo(FILEINFO_MIME);
|
||||
$mime = $finfo->file($tmpPath.$result['newFilename']);
|
||||
if (preg_match('/^image\/(png|jpe?g)/i', $mime, $m))
|
||||
{
|
||||
$i = 1; // image index
|
||||
if ($files = scandir($targetPath, SCANDIR_SORT_DESCENDING))
|
||||
if (rsort($files, SORT_NATURAL) && $files[0] != '.' && $files[0] != '..')
|
||||
$i = explode('.', $files[0])[0] + 1;
|
||||
|
||||
$targetFile = $i . ($m[1] == 'png' ? '.png' : '.jpg');
|
||||
|
||||
// move to final location
|
||||
if (!rename($tmpPath.$result['newFilename'], $targetPath.$targetFile))
|
||||
return Util::toJSON(['error' => Lang::main('intError')]);
|
||||
|
||||
// send success
|
||||
return Util::toJSON(array(
|
||||
'success' => true,
|
||||
'id' => $i,
|
||||
'type' => $m[1] == 'png' ? 3 : 2,
|
||||
'name' => $this->_get['qqfile']
|
||||
));
|
||||
}
|
||||
|
||||
return Util::toJSON(['error' => Lang::screenshot('error', 'unkFormat')]);
|
||||
}
|
||||
|
||||
return Util::toJSON($result);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AjaxFilter extends AjaxHandler
|
||||
{
|
||||
public $doRedirect = true;
|
||||
|
||||
private $cat = [];
|
||||
private $page = '';
|
||||
private $filter = null;
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
if (!$params)
|
||||
return;
|
||||
|
||||
$p = explode('=', $params[0]);
|
||||
|
||||
$this->page = $p[0];
|
||||
|
||||
if (isset($p[1]))
|
||||
$this->cat[] = $p[1];
|
||||
|
||||
if (count($params) > 1)
|
||||
for ($i = 1; $i < count($params); $i++)
|
||||
$this->cat[] = $params[$i];
|
||||
|
||||
$opts = ['parentCats' => $this->cat];
|
||||
|
||||
switch ($p[0])
|
||||
{
|
||||
case 'achievements':
|
||||
$this->filter = (new AchievementListFilter(true, $opts));
|
||||
break;
|
||||
case 'areatriggers':
|
||||
$this->filter = (new AreaTriggerListFilter(true, $opts));
|
||||
break;
|
||||
case 'enchantments':
|
||||
$this->filter = (new EnchantmentListFilter(true, $opts));
|
||||
break;
|
||||
case 'icons':
|
||||
$this->filter = (new IconListFilter(true, $opts));
|
||||
break;
|
||||
case 'items':
|
||||
$this->filter = (new ItemListFilter(true, $opts));
|
||||
break;
|
||||
case 'itemsets':
|
||||
$this->filter = (new ItemsetListFilter(true, $opts));
|
||||
break;
|
||||
case 'npcs':
|
||||
$this->filter = (new CreatureListFilter(true, $opts));
|
||||
break;
|
||||
case 'objects':
|
||||
$this->filter = (new GameObjectListFilter(true, $opts));
|
||||
break;
|
||||
case 'quests':
|
||||
$this->filter = (new QuestListFilter(true, $opts));
|
||||
break;
|
||||
case 'sounds':
|
||||
$this->filter = (new SoundListFilter(true, $opts));
|
||||
break;
|
||||
case 'spells':
|
||||
$this->filter = (new SpellListFilter(true, $opts));
|
||||
break;
|
||||
case 'profiles':
|
||||
$this->filter = (new ProfileListFilter(true, $opts));
|
||||
break;
|
||||
case 'guilds':
|
||||
$this->filter = (new GuildListFilter(true, $opts));
|
||||
break;
|
||||
case 'arena-teams':
|
||||
$this->filter = (new ArenaTeamListFilter(true, $opts));
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
parent::__construct($params);
|
||||
|
||||
// always this one
|
||||
$this->handler = 'handleFilter';
|
||||
}
|
||||
|
||||
protected function handleFilter() : string
|
||||
{
|
||||
$url = '?'.$this->page;
|
||||
|
||||
$this->filter->mergeCat($this->cat);
|
||||
|
||||
if ($this->cat)
|
||||
$url .= '='.implode('.', $this->cat);
|
||||
|
||||
$fi = [];
|
||||
if ($x = $this->filter->getFilterString())
|
||||
$url .= '&filter='.$x;
|
||||
|
||||
if ($this->filter->error)
|
||||
$_SESSION['fiError'] = get_class($this->filter);
|
||||
|
||||
if ($fi)
|
||||
$url .= '&filter='.implode(';', $fi);
|
||||
|
||||
// do get request
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxGetdescription extends AjaxHandler
|
||||
{
|
||||
protected $_post = array(
|
||||
'description' => [FILTER_CALLBACK, ['options' => 'AjaxHandler::checkFulltext']]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$params || $params[0]) // should be empty
|
||||
return;
|
||||
|
||||
$this->handler = 'handleDescription';
|
||||
}
|
||||
|
||||
protected function handleDescription() : string
|
||||
{
|
||||
$this->contentType = MIME_TYPE_TEXT;
|
||||
|
||||
if (!User::$id)
|
||||
return '';
|
||||
|
||||
$desc = (new Markup($this->_post['description']))->stripTags();
|
||||
|
||||
return Lang::trimTextClean($desc, 120);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxGotocomment extends AjaxHandler
|
||||
{
|
||||
protected $_get = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt']
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
// always this one
|
||||
$this->handler = 'handleGoToComment';
|
||||
$this->doRedirect = true;
|
||||
}
|
||||
|
||||
/* responses
|
||||
header()
|
||||
*/
|
||||
protected function handleGoToComment() : string
|
||||
{
|
||||
if (!$this->_get['id'])
|
||||
return '.'; // go home
|
||||
|
||||
if ($_ = 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']))
|
||||
return '?'.Type::getFileString(intVal($_['type'])).'='.$_['typeId'].'#comments:id='.$_['id'].($_['id'] != $this->_get['id'] ? ':reply='.$this->_get['id'] : null);
|
||||
else
|
||||
trigger_error('AjaxGotocomment::handleGoToComment - could not find comment #'.$this->get['id'], E_USER_ERROR);
|
||||
|
||||
return '.';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxGuide extends AjaxHandler
|
||||
{
|
||||
protected $_post = array(
|
||||
'id' => [FILTER_SANITIZE_NUMBER_INT, null],
|
||||
'rating' => [FILTER_SANITIZE_NUMBER_INT, null]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$this->params || count($this->params) != 1)
|
||||
return;
|
||||
|
||||
$this->contentType = MIME_TYPE_TEXT;
|
||||
|
||||
// select handler
|
||||
if ($this->params[0] == 'vote')
|
||||
$this->handler = 'voteGuide';
|
||||
}
|
||||
|
||||
protected function voteGuide() : string
|
||||
{
|
||||
if (!$this->_post['id'] || $this->_post['rating'] < 0 || $this->_post['rating'] > 5)
|
||||
{
|
||||
header('HTTP/1.0 404 Not Found', true, 404);
|
||||
return '';
|
||||
}
|
||||
else if (!User::canUpvote() || !User::canDownvote()) // same logic as comments?
|
||||
{
|
||||
header('HTTP/1.0 403 Forbidden', true, 403);
|
||||
return '';
|
||||
}
|
||||
// by id, not own, published
|
||||
if ($g = DB::Aowow()->selectRow('SELECT `userId`, `cuFlags` FROM ?_guides WHERE `id` = ?d AND (`status` = ?d OR `rev` > 0)', $this->_post['id'], GUIDE_STATUS_APPROVED))
|
||||
{
|
||||
if ($g['cuFlags'] & GUIDE_CU_NO_RATING || $g['userId'] == User::$id)
|
||||
{
|
||||
header('HTTP/1.0 403 Forbidden', true, 403);
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!$this->_post['rating'])
|
||||
DB::Aowow()->query('DELETE FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d AND `userId` = ?d', RATING_GUIDE, $this->_post['id'], User::$id);
|
||||
else
|
||||
DB::Aowow()->query('REPLACE INTO ?_user_ratings VALUES (?d, ?d, ?d, ?d)', RATING_GUIDE, $this->_post['id'], User::$id, $this->_post['rating']);
|
||||
|
||||
$res = DB::Aowow()->selectRow('SELECT IFNULL(SUM(`value`), 0) AS `t`, IFNULL(COUNT(*), 0) AS `n` FROM ?_user_ratings WHERE `type` = ?d AND `entry` = ?d', RATING_GUIDE, $this->_post['id']);
|
||||
return Util::toJSON($res['n'] ? ['rating' => $res['t'] / $res['n'], 'nvotes' => $res['n']] : ['rating' => 0, 'nvotes' => 0]);
|
||||
}
|
||||
|
||||
return Util::toJSON(['rating' => 0, 'nvotes' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('invalid access');
|
||||
|
||||
class AjaxGuild extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['resync', 'status'];
|
||||
protected $_get = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkIdList' ],
|
||||
'profile' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkEmptySet'],
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$this->params)
|
||||
return;
|
||||
|
||||
switch ($this->params[0])
|
||||
{
|
||||
case 'resync':
|
||||
$this->handler = 'handleResync';
|
||||
break;
|
||||
case 'status':
|
||||
$this->handler = 'handleStatus';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional, not used]
|
||||
profile: <empty> [optional, also get related chars]
|
||||
return: 1
|
||||
*/
|
||||
protected function handleResync() : string
|
||||
{
|
||||
if ($guilds = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_guild WHERE id IN (?a)', $this->_get['id']))
|
||||
foreach ($guilds as $g)
|
||||
Profiler::scheduleResync(Type::GUILD, $g['realm'], $g['realmGUID']);
|
||||
|
||||
if ($this->_get['profile'])
|
||||
if ($chars = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_profiles WHERE guild IN (?a)', $this->_get['id']))
|
||||
foreach ($chars as $c)
|
||||
Profiler::scheduleResync(Type::PROFILE, $c['realm'], $c['realmGUID']);
|
||||
|
||||
return '1';
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
<status object>
|
||||
[
|
||||
nQueueProcesses,
|
||||
[statusCode, timeToRefresh, curQueuePos, errorCode, nResyncTries],
|
||||
[<anotherStatus>]
|
||||
...
|
||||
]
|
||||
|
||||
not all fields are required, if zero they are omitted
|
||||
statusCode:
|
||||
0: end the request
|
||||
1: waiting
|
||||
2: working...
|
||||
3: ready; click to view
|
||||
4: error / retry
|
||||
errorCode:
|
||||
0: unk error
|
||||
1: char does not exist
|
||||
2: armory gone
|
||||
*/
|
||||
protected function handleStatus() : string
|
||||
{
|
||||
$response = Profiler::resyncStatus(Type::GUILD, $this->_get['id']);
|
||||
return Util::toJSON($response);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxLocale extends AjaxHandler
|
||||
{
|
||||
protected $_get = array(
|
||||
'locale' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkLocale']
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
// always this one
|
||||
$this->handler = 'handleLocale';
|
||||
$this->doRedirect = true;
|
||||
}
|
||||
|
||||
/* responses
|
||||
header()
|
||||
*/
|
||||
protected function handleLocale() : string
|
||||
{
|
||||
User::setLocale($this->_get['locale']);
|
||||
User::save();
|
||||
|
||||
return isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '.';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,767 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
class AjaxProfile extends AjaxHandler
|
||||
{
|
||||
private $undo = false;
|
||||
|
||||
protected $validParams = ['link', 'unlink', 'pin', 'unpin', 'public', 'private', 'avatar', 'resync', 'status', 'save', 'delete', 'purge', 'summary', 'load'];
|
||||
protected $_get = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkIdList' ],
|
||||
'items' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxProfile::checkItemList'],
|
||||
'size' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
|
||||
'guild' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkEmptySet'],
|
||||
'arena-team' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkEmptySet'],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxProfile::checkUser' ]
|
||||
);
|
||||
|
||||
protected $_post = array(
|
||||
'name' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkFulltext'],
|
||||
'level' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'class' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'race' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'gender' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'nomodel' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'talenttree1' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'talenttree2' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'talenttree3' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'activespec' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'talentbuild1' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'glyphs1' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'talentbuild2' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'glyphs2' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'icon' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'description' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkFulltext'],
|
||||
'source' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'copy' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'public' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'gearscore' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'inv' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkIdListUnsigned', 'flags' => FILTER_REQUIRE_ARRAY],
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
{
|
||||
parent::__construct($params);
|
||||
|
||||
if (!$this->params)
|
||||
return;
|
||||
|
||||
if (!CFG_PROFILER_ENABLE)
|
||||
return;
|
||||
|
||||
switch ($this->params[0])
|
||||
{
|
||||
case 'unlink':
|
||||
$this->undo = true;
|
||||
case 'link':
|
||||
$this->handler = 'handleLink'; // always returns null
|
||||
break;
|
||||
case 'unpin':
|
||||
$this->undo = true;
|
||||
case 'pin':
|
||||
$this->handler = 'handlePin'; // always returns null
|
||||
break;
|
||||
case 'private':
|
||||
$this->undo = true;
|
||||
case 'public':
|
||||
$this->handler = 'handlePrivacy'; // always returns null
|
||||
break;
|
||||
case 'avatar':
|
||||
$this->handler = 'handleAvatar'; // sets an image header
|
||||
break; // so it has to die here or another header will be set
|
||||
case 'resync':
|
||||
$this->handler = 'handleResync'; // always returns "1"
|
||||
break;
|
||||
case 'status':
|
||||
$this->handler = 'handleStatus'; // returns status object
|
||||
break;
|
||||
case 'save':
|
||||
$this->handler = 'handleSave';
|
||||
break;
|
||||
case 'delete':
|
||||
$this->handler = 'handleDelete';
|
||||
break;
|
||||
case 'purge':
|
||||
$this->handler = 'handlePurge';
|
||||
break;
|
||||
case 'summary': // page is generated by jScript
|
||||
die(); // just be empty
|
||||
case 'load':
|
||||
$this->handler = 'handleLoad';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function handleLink() : void // links char with account
|
||||
{
|
||||
if (!User::$id || empty($this->_get['id']))
|
||||
{
|
||||
trigger_error('AjaxProfile::handleLink - profileId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = User::$id;
|
||||
if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
{
|
||||
if (!($uid = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE user = ?', $this->_get['user'])))
|
||||
{
|
||||
trigger_error('AjaxProfile::handleLink - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->undo)
|
||||
DB::Aowow()->query('DELETE FROM ?_account_profiles WHERE accountId = ?d AND profileId IN (?a)', $uid, $this->_get['id']);
|
||||
else
|
||||
{
|
||||
foreach ($this->_get['id'] as $prId) // only link characters, not custom profiles
|
||||
{
|
||||
if ($prId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_profiles WHERE id = ?d AND realm IS NOT NULL', $prId))
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_account_profiles VALUES (?d, ?d, 0)', $uid, $prId);
|
||||
else
|
||||
{
|
||||
trigger_error('AjaxProfile::handleLink - profile #'.$prId.' is custom or does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function handlePin() : void // (un)favorite
|
||||
{
|
||||
if (!User::$id || empty($this->_get['id'][0]))
|
||||
{
|
||||
trigger_error('AjaxProfile::handlePin - profileId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = User::$id;
|
||||
if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
{
|
||||
if (!($uid = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE user = ?', $this->_get['user'])))
|
||||
{
|
||||
trigger_error('AjaxProfile::handlePin - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// since only one character can be pinned at a time we can reset everything
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET extraFlags = extraFlags & ?d WHERE accountId = ?d', ~PROFILER_CU_PINNED, $uid);
|
||||
// and set a single char if necessary
|
||||
if (!$this->undo)
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET extraFlags = extraFlags | ?d WHERE profileId = ?d AND accountId = ?d', PROFILER_CU_PINNED, $this->_get['id'][0], $uid);
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional]
|
||||
return: null
|
||||
*/
|
||||
protected function handlePrivacy() : void // public visibility
|
||||
{
|
||||
if (!User::$id || empty($this->_get['id'][0]))
|
||||
{
|
||||
trigger_error('AjaxProfile::handlePrivacy - profileId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$uid = User::$id;
|
||||
if ($this->_get['user'] && User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
{
|
||||
if (!($uid = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE user = ?', $this->_get['user'])))
|
||||
{
|
||||
trigger_error('AjaxProfile::handlePrivacy - user "'.$this->_get['user'].'" does not exist', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->undo)
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET extraFlags = extraFlags & ?d WHERE profileId IN (?a) AND accountId = ?d', ~PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET cuFlags = cuFlags & ?d WHERE id IN (?a) AND user = ?d', ~PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_account_profiles SET extraFlags = extraFlags | ?d WHERE profileId IN (?a) AND accountId = ?d', PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET cuFlags = cuFlags | ?d WHERE id IN (?a) AND user = ?d', PROFILER_CU_PUBLISHED, $this->_get['id'], $uid);
|
||||
}
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId>
|
||||
size: <string> [optional]
|
||||
return: image-header
|
||||
*/
|
||||
protected function handleAvatar() : void // image
|
||||
{
|
||||
// something happened in the last years: those textures do not include tiny icons
|
||||
$sizes = [/* 'tiny' => 15, */'small' => 18, 'medium' => 36, 'large' => 56];
|
||||
$aPath = 'uploads/avatars/%d.jpg';
|
||||
$s = $this->_get['size'] ?: 'medium';
|
||||
|
||||
if (!$this->_get['id'] || !preg_match('/^([0-9]+)\.(jpg|gif)$/', $this->_get['id'][0], $matches) || !in_array($s, array_keys($sizes)))
|
||||
{
|
||||
trigger_error('AjaxProfile::handleAvatar - malformed request received', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->contentType = $matches[2] == 'png' ? MIME_TYPE_PNG : MIME_TYPE_JPEG;
|
||||
|
||||
$id = $matches[1];
|
||||
$dest = imageCreateTruecolor($sizes[$s], $sizes[$s]);
|
||||
|
||||
if (file_exists(sprintf($aPath, $id)))
|
||||
{
|
||||
$offsetX = $offsetY = 0;
|
||||
|
||||
switch ($s)
|
||||
{
|
||||
case 'tiny':
|
||||
$offsetX += $sizes['small'];
|
||||
case 'small':
|
||||
$offsetY += $sizes['medium'];
|
||||
case 'medium':
|
||||
$offsetX += $sizes['large'];
|
||||
}
|
||||
|
||||
$src = imageCreateFromJpeg(printf($aPath, $id));
|
||||
imagecopymerge($dest, $src, 0, 0, $offsetX, $offsetY, $sizes[$s], $sizes[$s], 100);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxProfile::handleAvatar - avatar file #'.$id.' not found', E_USER_ERROR);
|
||||
|
||||
if ($matches[2] == 'gif')
|
||||
imageGif($dest);
|
||||
else
|
||||
imageJpeg($dest);
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
user: <string> [optional, not used]
|
||||
return: 1
|
||||
*/
|
||||
protected function handleResync() : string
|
||||
{
|
||||
if ($chars = DB::Aowow()->select('SELECT realm, realmGUID FROM ?_profiler_profiles WHERE id IN (?a)', $this->_get['id']))
|
||||
{
|
||||
foreach ($chars as $c)
|
||||
Profiler::scheduleResync(Type::PROFILE, $c['realm'], $c['realmGUID']);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxProfile::handleResync - profiles '.implode(', ', $this->_get['id']).' not found in db', E_USER_ERROR);
|
||||
|
||||
return '1';
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
<status object>
|
||||
[
|
||||
nQueueProcesses,
|
||||
[statusCode, timeToRefresh, curQueuePos, errorCode, nResyncTries],
|
||||
[<anotherStatus>]
|
||||
...
|
||||
]
|
||||
|
||||
not all fields are required, if zero they are omitted
|
||||
statusCode:
|
||||
0: end the request
|
||||
1: waiting
|
||||
2: working...
|
||||
3: ready; click to view
|
||||
4: error / retry
|
||||
errorCode:
|
||||
0: unk error
|
||||
1: char does not exist
|
||||
2: armory gone
|
||||
*/
|
||||
protected function handleStatus() : string
|
||||
{
|
||||
// roster resync for this guild was requested -> get char list
|
||||
if ($this->_get['guild'])
|
||||
$ids = DB::Aowow()->selectCol('SELECT id FROM ?_profiler_profiles WHERE guild IN (?a)', $this->_get['id']);
|
||||
else if ($this->_get['arena-team'])
|
||||
$ids = DB::Aowow()->selectCol('SELECT profileId FROM ?_profiler_arena_team_member WHERE arenaTeamId IN (?a)', $this->_get['id']);
|
||||
else
|
||||
$ids = $this->_get['id'];
|
||||
|
||||
if (!$ids)
|
||||
{
|
||||
trigger_error('AjaxProfile::handleStatus - 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);
|
||||
return Util::toJSON([1, [PR_QUEUE_STATUS_ERROR, 0, 0, PR_QUEUE_ERROR_CHAR]]);
|
||||
}
|
||||
|
||||
$response = Profiler::resyncStatus(Type::PROFILE, $ids);
|
||||
return Util::toJSON($response);
|
||||
}
|
||||
|
||||
/* params (get))
|
||||
id: <prId1,0> [0: new profile]
|
||||
params (post)
|
||||
<various char data> [see below]
|
||||
return:
|
||||
proileId [onSuccess]
|
||||
-1 [onError]
|
||||
*/
|
||||
protected function handleSave() : string // unKill a profile
|
||||
{
|
||||
// todo (med): detail check this post-data
|
||||
$cuProfile = array(
|
||||
'user' => User::$id,
|
||||
// 'userName' => User::$displayName,
|
||||
'name' => $this->_post['name'],
|
||||
'level' => $this->_post['level'],
|
||||
'class' => $this->_post['class'],
|
||||
'race' => $this->_post['race'],
|
||||
'gender' => $this->_post['gender'],
|
||||
'nomodelMask' => $this->_post['nomodel'],
|
||||
'talenttree1' => $this->_post['talenttree1'],
|
||||
'talenttree2' => $this->_post['talenttree2'],
|
||||
'talenttree3' => $this->_post['talenttree3'],
|
||||
'talentbuild1' => $this->_post['talentbuild1'],
|
||||
'talentbuild2' => $this->_post['talentbuild2'],
|
||||
'activespec' => $this->_post['activespec'],
|
||||
'glyphs1' => $this->_post['glyphs1'],
|
||||
'glyphs2' => $this->_post['glyphs2'],
|
||||
'gearscore' => $this->_post['gearscore'],
|
||||
'icon' => $this->_post['icon'],
|
||||
'cuFlags' => PROFILER_CU_PROFILE | ($this->_post['public'] ? PROFILER_CU_PUBLISHED : 0)
|
||||
);
|
||||
|
||||
if (strstr($cuProfile['icon'], 'profile=avatar')) // how the profiler is supposed to handle icons is beyond me
|
||||
$cuProfile['icon'] = '';
|
||||
|
||||
if ($_ = $this->_post['description'])
|
||||
$cuProfile['description'] = $_;
|
||||
|
||||
if ($_ = $this->_post['source']) // should i also set sourcename?
|
||||
$cuProfile['sourceId'] = $_;
|
||||
|
||||
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', $_))
|
||||
$cuProfile['realm'] = $r;
|
||||
|
||||
$cuProfile['sourceId'] = $_;
|
||||
}
|
||||
|
||||
if ($cuProfile['sourceId'])
|
||||
$cuProfile['sourceName'] = DB::Aowow()->selectCell('SELECT name FROM ?_profiler_profiles WHERE id = ?d', $cuProfile['sourceId']);
|
||||
|
||||
$charId = -1;
|
||||
if ($id = $this->_get['id'][0]) // update
|
||||
{
|
||||
if ($charId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_profiles WHERE id = ?d', $id))
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET ?a WHERE id = ?d', $cuProfile, $id);
|
||||
}
|
||||
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);
|
||||
if ($nProfiles < 10 || User::isPremium())
|
||||
if ($newId = DB::Aowow()->query('INSERT INTO ?_profiler_profiles (?#) VALUES (?a)', array_keys($cuProfile), array_values($cuProfile)))
|
||||
$charId = $newId;
|
||||
}
|
||||
|
||||
// update items
|
||||
if ($charId != -1)
|
||||
{
|
||||
// ok, 'funny' thing: wether an item has en extra prismatic sockel is determined contextual
|
||||
// either the socket is -1 or it has an itemId in a socket where there shouldn't be one
|
||||
$keys = ['id', 'slot', 'item', 'subitem', 'permEnchant', 'tempEnchant', 'gem1', 'gem2', 'gem3', 'gem4'];
|
||||
|
||||
// validate Enchantments
|
||||
$enchIds = array_merge(
|
||||
array_column($this->_post['inv'], 3), // perm enchantments
|
||||
array_column($this->_post['inv'], 4) // temp enchantments (not used..?)
|
||||
);
|
||||
$enchs = new EnchantmentList(array(['id', $enchIds]));
|
||||
|
||||
// validate items
|
||||
$itemIds = array_merge(
|
||||
array_column($this->_post['inv'], 1), // base item
|
||||
array_column($this->_post['inv'], 5), // gem slot 1
|
||||
array_column($this->_post['inv'], 6), // gem slot 2
|
||||
array_column($this->_post['inv'], 7), // gem slot 3
|
||||
array_column($this->_post['inv'], 8) // gem slot 4
|
||||
);
|
||||
|
||||
$items = new ItemList(array(['id', $itemIds]));
|
||||
if (!$items->error)
|
||||
{
|
||||
foreach ($this->_post['inv'] as $slot => $itemData)
|
||||
{
|
||||
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]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// item does not exist
|
||||
if (!$items->getEntry($itemData[1]))
|
||||
continue;
|
||||
|
||||
// sub-item check
|
||||
if (!$items->getRandEnchantForItem($itemData[1]))
|
||||
$itemData[2] = 0;
|
||||
|
||||
// item sockets are fubar
|
||||
$nSockets = $items->json[$itemData[1]]['nsockets'];
|
||||
$nSockets += in_array($slot, [SLOT_WAIST, SLOT_WRISTS, SLOT_HANDS]) ? 1 : 0;
|
||||
for ($i = 5; $i < 9; $i++)
|
||||
if ($itemData[$i] > 0 && (!$items->getEntry($itemData[$i]) || $i >= (5 + $nSockets)))
|
||||
$itemData[$i] = 0;
|
||||
|
||||
// item enchantments are borked
|
||||
if ($itemData[3] && !$enchs->getEntry($itemData[3]))
|
||||
$itemData[3] = 0;
|
||||
|
||||
if ($itemData[4] && !$enchs->getEntry($itemData[4]))
|
||||
$itemData[4] = 0;
|
||||
|
||||
// looks good
|
||||
array_unshift($itemData, $charId);
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_items (?#) VALUES (?a)', $keys, $itemData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (string)$charId;
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId1,prId2,..,prIdN>
|
||||
return
|
||||
null
|
||||
*/
|
||||
protected function handleDelete() : void // kill a profile
|
||||
{
|
||||
if (!User::$id || !$this->_get['id'])
|
||||
{
|
||||
trigger_error('AjaxProfile::handleDelete - profileId empty or user not logged in', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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,
|
||||
$this->_get['id'],
|
||||
PROFILER_CU_PROFILE,
|
||||
User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU) ? DBSIMPLE_SKIP : User::$id
|
||||
);
|
||||
}
|
||||
|
||||
/* params
|
||||
id: profileId
|
||||
items: string [itemIds.join(':')]
|
||||
unnamed: unixtime [only to force the browser to reload instead of cache]
|
||||
return
|
||||
lots...
|
||||
*/
|
||||
protected function handleLoad() : string
|
||||
{
|
||||
// titles, achievements, characterData, talents, pets
|
||||
// and some onLoad-hook to .. load it registerProfile($data)
|
||||
// everything else goes through data.php .. strangely enough
|
||||
|
||||
if (!$this->_get['id'])
|
||||
{
|
||||
trigger_error('AjaxProfile::handleLoad - profileId empty', E_USER_ERROR);
|
||||
return '';
|
||||
}
|
||||
|
||||
$pBase = DB::Aowow()->selectRow('SELECT pg.name AS guildname, p.* FROM ?_profiler_profiles p LEFT JOIN ?_profiler_guild pg ON pg.id = p.guild WHERE p.id = ?d', $this->_get['id'][0]);
|
||||
if (!$pBase)
|
||||
{
|
||||
trigger_error('Profiler::handleLoad - called with invalid profileId #'.$this->_get['id'][0], E_USER_WARNING);
|
||||
return '';
|
||||
}
|
||||
|
||||
if (($pBase['cuFlags'] & PROFILER_CU_DELETED) && !User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
return '';
|
||||
|
||||
|
||||
$rData = [];
|
||||
foreach (Profiler::getRealms() as $rId => $rData)
|
||||
if ($rId == $pBase['realm'])
|
||||
break;
|
||||
|
||||
$profile = array(
|
||||
'id' => $pBase['id'],
|
||||
'source' => $pBase['id'],
|
||||
'level' => $pBase['level'],
|
||||
'classs' => $pBase['class'],
|
||||
'race' => $pBase['race'],
|
||||
'faction' => Game::sideByRaceMask(1 << ($pBase['race'] - 1)) - 1,
|
||||
'gender' => $pBase['gender'],
|
||||
'skincolor' => $pBase['skincolor'],
|
||||
'hairstyle' => $pBase['hairstyle'],
|
||||
'haircolor' => $pBase['haircolor'],
|
||||
'facetype' => $pBase['facetype'],
|
||||
'features' => $pBase['features'],
|
||||
'title' => $pBase['title'],
|
||||
'name' => $pBase['name'],
|
||||
'guild' => "$'".$pBase['guildname']."'",
|
||||
'published' => !!($pBase['cuFlags'] & PROFILER_CU_PUBLISHED),
|
||||
'pinned' => !!($pBase['cuFlags'] & PROFILER_CU_PINNED),
|
||||
'nomodel' => $pBase['nomodelMask'],
|
||||
'playedtime' => $pBase['playedtime'],
|
||||
'lastupdated' => $pBase['lastupdated'] * 1000,
|
||||
'talents' => array(
|
||||
'builds' => array( // notice the bullshit to prevent the talent-string from becoming a float! NOTICE IT!!
|
||||
['talents' => '$"'.$pBase['talentbuild1'].'"', 'glyphs' => $pBase['glyphs1']],
|
||||
['talents' => '$"'.$pBase['talentbuild2'].'"', 'glyphs' => $pBase['glyphs2']]
|
||||
),
|
||||
'active' => $pBase['activespec']
|
||||
),
|
||||
// set later
|
||||
'inventory' => [],
|
||||
'bookmarks' => [], // list of userIds who claimed this profile (claiming and owning are two different things)
|
||||
|
||||
// completion lists: [subjectId => amount/timestamp/1]
|
||||
'skills' => [], // skillId => [curVal, maxVal]
|
||||
'reputation' => [], // factionId => curVal
|
||||
'titles' => [], // titleId => 1
|
||||
'spells' => [], // spellId => 1; recipes, vanity pets, mounts
|
||||
'achievements' => [], // achievementId => timestamp
|
||||
'quests' => [], // questId => 1
|
||||
'achievementpoints' => 0, // max you have
|
||||
'statistics' => [], // all raid activity [achievementId => killCount]
|
||||
'activity' => [], // recent raid activity [achievementId => 1] (is a subset of statistics)
|
||||
);
|
||||
|
||||
if ($pBase['cuFlags'] & PROFILER_CU_PROFILE)
|
||||
{
|
||||
// this parameter is _really_ strange .. probably still not doing this right
|
||||
$profile['source'] = $pBase['realm'] ? $pBase['sourceId'] : 0;
|
||||
|
||||
$profile['sourcename'] = $pBase['sourceName'];
|
||||
$profile['description'] = $pBase['description'];
|
||||
$profile['user'] = $pBase['user'];
|
||||
$profile['username'] = DB::Aowow()->selectCell('SELECT displayName FROM ?_account WHERE id = ?d', $pBase['user']);
|
||||
}
|
||||
|
||||
// custom profiles inherit this when copied from real char :(
|
||||
if ($pBase['realm'])
|
||||
{
|
||||
$profile['region'] = [$rData['region'], Lang::profiler('regions', $rData['region'])];
|
||||
$profile['battlegroup'] = [Profiler::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP];
|
||||
$profile['realm'] = [Profiler::urlize($rData['name'], true), $rData['name']];
|
||||
}
|
||||
|
||||
// bookmarks
|
||||
if ($_ = DB::Aowow()->selectCol('SELECT accountId FROM ?_account_profiles WHERE profileId = ?d', $pBase['id']))
|
||||
$profile['bookmarks'] = $_;
|
||||
|
||||
// arena teams - [size(2|3|5) => DisplayName]; DisplayName gets urlized to use as link
|
||||
if ($at = DB::Aowow()->selectCol('SELECT type AS ARRAY_KEY, name FROM ?_profiler_arena_team at JOIN ?_profiler_arena_team_member atm ON atm.arenaTeamId = at.id WHERE atm.profileId = ?d', $pBase['id']))
|
||||
$profile['arenateams'] = $at;
|
||||
|
||||
// pets if hunter fields: [name:name, family:petFamily, npc:npcId, displayId:modelId, talents:talentString]
|
||||
if ($pets = DB::Aowow()->select('SELECT name, family, npc, displayId, talents FROM ?_profiler_pets WHERE owner = ?d', $pBase['id']))
|
||||
$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))
|
||||
{
|
||||
foreach ($customs as $id => $cu)
|
||||
{
|
||||
if (!$cu['icon'])
|
||||
unset($cu['icon']);
|
||||
|
||||
$profile['customs'][$id] = array_values($cu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* $profile[]
|
||||
// CUSTOM
|
||||
'auras' => [], // custom list of buffs, debuffs [spellId]
|
||||
|
||||
// UNUSED
|
||||
'glyphs' => [], // provided list of already known glyphs (post cataclysm feature)
|
||||
*/
|
||||
|
||||
|
||||
$completion = DB::Aowow()->select('SELECT type AS ARRAY_KEY, typeId AS ARRAY_KEY2, cur, max FROM ?_profiler_completion WHERE id = ?d', $pBase['id']);
|
||||
foreach ($completion as $type => $data)
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case Type::FACTION: // factionId => amount
|
||||
$profile['reputation'] = array_combine(array_keys($data), array_column($data, 'cur'));
|
||||
break;
|
||||
case Type::TITLE:
|
||||
foreach ($data as &$d)
|
||||
$d = 1;
|
||||
|
||||
$profile['titles'] = $data;
|
||||
break;
|
||||
case Type::QUEST:
|
||||
foreach ($data as &$d)
|
||||
$d = 1;
|
||||
|
||||
$profile['quests'] = $data;
|
||||
break;
|
||||
case Type::SPELL:
|
||||
foreach ($data as &$d)
|
||||
$d = 1;
|
||||
|
||||
$profile['spells'] = $data;
|
||||
break;
|
||||
case Type::ACHIEVEMENT:
|
||||
$achievements = array_filter($data, function ($x) { return $x['max'] === null; });
|
||||
$statistics = array_filter($data, function ($x) { return $x['max'] !== null; });
|
||||
|
||||
// achievements
|
||||
$profile['achievements'] = array_combine(array_keys($achievements), array_column($achievements, 'cur'));
|
||||
$profile['achievementpoints'] = DB::Aowow()->selectCell('SELECT SUM(points) FROM ?_achievement WHERE id IN (?a)', array_keys($achievements));
|
||||
|
||||
// raid progression
|
||||
$activity = array_filter($statistics, function ($x) { return $x['cur'] > (time() - MONTH); });
|
||||
foreach ($activity as &$r)
|
||||
$r = 1;
|
||||
|
||||
// ony .. subtract 10-man from 25-man
|
||||
|
||||
$profile['statistics'] = array_combine(array_keys($statistics), array_column($statistics, 'max'));
|
||||
$profile['activity'] = $activity;
|
||||
break;
|
||||
case Type::SKILL:
|
||||
foreach ($data as &$d)
|
||||
$d = [$d['cur'], $d['max']];
|
||||
|
||||
$profile['skills'] = $data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$buff = '';
|
||||
|
||||
$usedSlots = [];
|
||||
if ($this->_get['items'])
|
||||
{
|
||||
$phItems = new ItemList(array(['id', $this->_get['items']], ['slot', INVTYPE_NON_EQUIP, '!']));
|
||||
if (!$phItems->error)
|
||||
{
|
||||
$data = $phItems->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS);
|
||||
foreach ($phItems->iterate() as $iId => $__)
|
||||
{
|
||||
$sl = $phItems->getField('slot');
|
||||
foreach (Profiler::$slot2InvType as $slot => $invTypes)
|
||||
{
|
||||
if (in_array($sl, $invTypes) && !in_array($slot, $usedSlots))
|
||||
{
|
||||
// get and apply inventory
|
||||
$buff .= 'g_items.add('.$iId.', {name_'.User::$localeString.":'".Util::jsEscape($phItems->getField('name', true))."', quality:".$phItems->getField('quality').", icon:'".$phItems->getField('iconString')."', jsonequip:".Util::toJSON($data[$iId])."});\n";
|
||||
$profile['inventory'][$slot] = [$iId, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
$usedSlots[] = $slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($items = DB::Aowow()->select('SELECT * FROM ?_profiler_items WHERE id = ?d', $pBase['id']))
|
||||
{
|
||||
$itemz = new ItemList(array(['id', array_column($items, 'item')], CFG_SQL_LIMIT_NONE));
|
||||
if (!$itemz->error)
|
||||
{
|
||||
$data = $itemz->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS);
|
||||
|
||||
foreach ($items as $i)
|
||||
{
|
||||
if ($itemz->getEntry($i['item']) && !in_array($i['slot'], $usedSlots))
|
||||
{
|
||||
// get and apply inventory
|
||||
$buff .= 'g_items.add('.$i['item'].', {name_'.User::$localeString.":'".Util::jsEscape($itemz->getField('name', true))."', quality:".$itemz->getField('quality').", icon:'".$itemz->getField('iconString')."', jsonequip:".Util::toJSON($data[$i['item']])."});\n";
|
||||
$profile['inventory'][$i['slot']] = [$i['item'], $i['subItem'], $i['permEnchant'], $i['tempEnchant'], $i['gem1'], $i['gem2'], $i['gem3'], $i['gem4']];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($buff)
|
||||
$buff .= "\n";
|
||||
|
||||
|
||||
// if ($au = $char->getField('auras'))
|
||||
// {
|
||||
// $auraz = new SpellList(array(['id', $char->getField('auras')], CFG_SQL_LIMIT_NONE));
|
||||
// $dataz = $auraz->getListviewData();
|
||||
// $modz = $auraz->getProfilerMods();
|
||||
|
||||
// // get and apply aura-mods
|
||||
// foreach ($dataz as $id => $data)
|
||||
// {
|
||||
// $mods = [];
|
||||
// if (!empty($modz[$id]))
|
||||
// {
|
||||
// foreach ($modz[$id] as $k => $v)
|
||||
// {
|
||||
// if (is_array($v))
|
||||
// $mods[] = $v;
|
||||
// else if ($str = @Game::$itemMods[$k])
|
||||
// $mods[$str] = $v;
|
||||
// }
|
||||
// }
|
||||
|
||||
// $buff .= 'g_spells.add('.$id.", {id:".$id.", name:'".Util::jsEscape(mb_substr($data['name'], 1))."', icon:'".$data['icon']."', modifier:".Util::toJSON($mods)."});\n";
|
||||
// }
|
||||
// $buff .= "\n";
|
||||
// }
|
||||
|
||||
|
||||
// load available titles
|
||||
Util::loadStaticFile('p-titles-'.$pBase['gender'], $buff, true);
|
||||
|
||||
// add profile to buffer
|
||||
$buff .= "\n\n\$WowheadProfiler.registerProfile(".Util::toJSON($profile).");";
|
||||
|
||||
return $buff."\n";
|
||||
}
|
||||
|
||||
/* params
|
||||
id: <prId>
|
||||
data: <mode> [string, tabName]
|
||||
return
|
||||
null
|
||||
*/
|
||||
protected function handlePurge() : void { } // removes completion data (as uploaded by the wowhead client) Just fail silently if someone triggers this manually
|
||||
|
||||
protected static function checkItemList($val) : array
|
||||
{
|
||||
// expecting item-list
|
||||
if (preg_match('/\d+(:\d+)*/', $val))
|
||||
return array_map('intVal', explode(':', $val));
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected static function checkUser(string $val) : string
|
||||
{
|
||||
if (User::isValidName($val))
|
||||
return $val;
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -18,19 +18,19 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class CommunityContent
|
||||
{
|
||||
private static array $jsGlobals = [];
|
||||
private static array $subjCache = [];
|
||||
private static $jsGlobals = [];
|
||||
private static $subjCache = [];
|
||||
|
||||
private static string $coQuery = '
|
||||
private static $commentQuery = '
|
||||
SELECT
|
||||
c.*,
|
||||
a1.displayName AS user,
|
||||
a2.displayName AS editUser,
|
||||
a3.displayName AS deleteUser,
|
||||
a4.displayName AS responseUser,
|
||||
IFNULL(SUM(ur.value), 0) AS rating,
|
||||
SUM(IF(ur.userId > 0 AND ur.userId = ?d, ur.value, 0)) AS userRating,
|
||||
SUM(IF( r.userId > 0 AND r.userId = ?d, 1, 0)) AS userReported
|
||||
IFNULL(SUM(cr.value), 0) AS rating,
|
||||
SUM(IF (cr.userId = ?d, value, 0)) AS userRating,
|
||||
SUM(IF (r.userId = ?d, 1, 0)) AS userReported
|
||||
FROM
|
||||
?_comments c
|
||||
JOIN
|
||||
@@ -42,7 +42,7 @@ class CommunityContent
|
||||
LEFT JOIN
|
||||
?_account a4 ON c.responseUserId = a4.id
|
||||
LEFT JOIN
|
||||
?_user_ratings ur ON c.id = ur.entry AND ur.type = ?d
|
||||
?_comments_rates cr ON c.id = cr.commentId
|
||||
LEFT JOIN
|
||||
?_reports r ON r.subject = c.id AND r.mode = 1 AND r.reason = 19
|
||||
WHERE
|
||||
@@ -54,41 +54,24 @@ class CommunityContent
|
||||
rating ASC
|
||||
';
|
||||
|
||||
private static string $ssQuery = '
|
||||
SELECT s.id AS ARRAY_KEY, s.id, a.displayName AS user, s.date, s.width, s.height, s.caption, IF(s.status & ?d, 1, 0) AS "sticky", s.type, s.typeId
|
||||
FROM ?_screenshots s
|
||||
LEFT JOIN ?_account a ON s.userIdOwner = a.id
|
||||
WHERE {s.userIdOwner = ?d AND }{s.type = ? AND }{s.typeId = ? AND }s.status & ?d AND (s.status & ?d) = 0
|
||||
{ORDER BY ?# DESC}
|
||||
{LIMIT ?d}
|
||||
';
|
||||
|
||||
private static string $viQuery = '
|
||||
SELECT v.id AS ARRAY_KEY, v.id, a.displayName AS user, v.date, v.videoId, v.caption, IF(v.status & ?d, 1, 0) AS "sticky", v.type, v.typeId
|
||||
FROM ?_videos v
|
||||
LEFT JOIN ?_account a ON v.userIdOwner = a.id
|
||||
WHERE {v.userIdOwner = ?d AND }{v.type = ? AND }{v.typeId = ? AND }v.status & ?d AND (v.status & ?d) = 0
|
||||
{ORDER BY ?# DESC}
|
||||
{LIMIT ?d}
|
||||
';
|
||||
|
||||
private static string $previewQuery = '
|
||||
private static $previewQuery = '
|
||||
SELECT
|
||||
c.id,
|
||||
c.body AS preview,
|
||||
c.date,
|
||||
c.replyTo AS commentid,
|
||||
UNIX_TIMESTAMP() - c.date AS elapsed,
|
||||
IF(c.flags & ?d, 1, 0) AS deleted,
|
||||
IF(c.type <> 0, c.type, c2.type) AS type,
|
||||
IF(c.typeId <> 0, c.typeId, c2.typeId) AS typeId,
|
||||
IFNULL(SUM(ur.value), 0) AS rating,
|
||||
IFNULL(SUM(cr.value), 0) AS rating,
|
||||
a.displayName AS user
|
||||
FROM
|
||||
?_comments c
|
||||
JOIN
|
||||
?_account a ON c.userId = a.id
|
||||
LEFT JOIN
|
||||
?_user_ratings ur ON ur.entry = c.id AND ur.userId <> 0 AND ur.`type` = 1
|
||||
?_comments_rates cr ON cr.commentId = c.id
|
||||
LEFT JOIN
|
||||
?_comments c2 ON c.replyTo = c2.id
|
||||
WHERE
|
||||
@@ -104,13 +87,13 @@ class CommunityContent
|
||||
?d
|
||||
';
|
||||
|
||||
private static function addSubject(int $type, int $typeId) : void
|
||||
private static function addSubject($type, $typeId)
|
||||
{
|
||||
if (!isset(self::$subjCache[$type][$typeId]))
|
||||
self::$subjCache[$type][$typeId] = 0;
|
||||
}
|
||||
|
||||
private static function getSubjects() : void
|
||||
private static function getSubjects()
|
||||
{
|
||||
foreach (self::$subjCache as $type => $ids)
|
||||
{
|
||||
@@ -118,16 +101,35 @@ class CommunityContent
|
||||
if (!$_)
|
||||
continue;
|
||||
|
||||
$obj = Type::newList($type, [CFG_SQL_LIMIT_NONE, ['id', $_]]);
|
||||
if (!$obj)
|
||||
continue;
|
||||
$cnd = [CFG_SQL_LIMIT_NONE, ['id', $_]];
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case TYPE_NPC: $obj = new CreatureList($cnd); break;
|
||||
case TYPE_OBJECT: $obj = new GameobjectList($cnd); break;
|
||||
case TYPE_ITEM: $obj = new ItemList($cnd); break;
|
||||
case TYPE_ITEMSET: $obj = new ItemsetList($cnd); break;
|
||||
case TYPE_QUEST: $obj = new QuestList($cnd); break;
|
||||
case TYPE_SPELL: $obj = new SpellList($cnd); break;
|
||||
case TYPE_ZONE: $obj = new ZoneList($cnd); break;
|
||||
case TYPE_FACTION: $obj = new FactionList($cnd); break;
|
||||
case TYPE_PET: $obj = new PetList($cnd); break;
|
||||
case TYPE_ACHIEVEMENT: $obj = new AchievementList($cnd); break;
|
||||
case TYPE_TITLE: $obj = new TitleList($cnd); break;
|
||||
case TYPE_WORLDEVENT: $obj = new WorldEventList($cnd); break;
|
||||
case TYPE_CLASS: $obj = new CharClassList($cnd); break;
|
||||
case TYPE_RACE: $obj = new CharRaceList($cnd); break;
|
||||
case TYPE_SKILL: $obj = new SkillList($cnd); break;
|
||||
case TYPE_CURRENCY: $obj = new CurrencyList($cnd); break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
foreach ($obj->iterate() as $id => $__)
|
||||
self::$subjCache[$type][$id] = $obj->getField('name', true);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getCommentPreviews(array $params = [], ?int &$nFound = 0, bool $dateFmt = true) : array
|
||||
public static function getCommentPreviews($params = [], &$nFound = 0)
|
||||
{
|
||||
/*
|
||||
purged:0, <- doesnt seem to be used anymore
|
||||
@@ -160,18 +162,35 @@ class CommunityContent
|
||||
$c['subject'] = self::$subjCache[$c['type']][$c['typeId']];
|
||||
|
||||
// format date
|
||||
$c['date'] = $dateFmt ? date(Util::$dateFormatInternal, $c['date']) : intVal($c['date']);
|
||||
$c['date'] = date(Util::$dateFormatInternal, $c['date']);
|
||||
|
||||
// remove commentid if not looking for replies
|
||||
if (empty($params['replies']))
|
||||
unset($c['commentid']);
|
||||
|
||||
// format text for listview
|
||||
$c['preview'] = Lang::trimTextClean($c['preview']);
|
||||
// remove line breaks
|
||||
$c['preview'] = strtr($c['preview'], ["\n" => ' ', "\r" => ' ']);
|
||||
// limit whitespaces to one at a time
|
||||
$c['preview'] = preg_replace('/\s+/', ' ', $c['preview']);
|
||||
// limit previews to 100 chars + whatever it takes to make the last word full
|
||||
if (strlen($c['preview']) > 100)
|
||||
{
|
||||
$n = 0;
|
||||
$b = [];
|
||||
$parts = explode(' ', $c['preview']);
|
||||
while ($n < 100 && $parts)
|
||||
{
|
||||
$_ = array_shift($parts);
|
||||
$n += strlen($_);
|
||||
$b[] = $_;
|
||||
}
|
||||
|
||||
$c['preview'] = implode(' ', $b).'…';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error('Comment '.$c['id'].' belongs to nonexistant subject.', E_USER_NOTICE);
|
||||
Util::addNote(U_GROUP_STAFF, 'CommunityClass::getCommentPreviews - comment '.$c['id'].' belongs to nonexistant subject');
|
||||
unset($comments[$idx]);
|
||||
}
|
||||
}
|
||||
@@ -179,13 +198,13 @@ class CommunityContent
|
||||
return $comments;
|
||||
}
|
||||
|
||||
public static function getCommentReplies(int $commentId, int $limit = 0, ?int &$nFound = 0) : array
|
||||
public static function getCommentReplies($commentId, $limit = 0, &$nFound = 0)
|
||||
{
|
||||
$replies = [];
|
||||
$query = $limit > 0 ? self::$coQuery.' LIMIT '.$limit : self::$coQuery;
|
||||
$query = $limit > 0 ? self::$commentQuery.' LIMIT '.$limit : self::$commentQuery;
|
||||
|
||||
// get replies
|
||||
$results = DB::Aowow()->selectPage($nFound, $query, User::$id, User::$id, RATING_COMMENT, $commentId, 0, 0, CC_FLAG_DELETED, User::$id, User::isInGroup(U_GROUP_COMMENTS_MODERATOR));
|
||||
$results = DB::Aowow()->selectPage($nFound, $query, User::$id, User::$id, $commentId, 0, 0, CC_FLAG_DELETED, User::$id, User::isInGroup(U_GROUP_COMMENTS_MODERATOR));
|
||||
foreach ($results as $r)
|
||||
{
|
||||
(new Markup($r['body']))->parseGlobalsFromText(self::$jsGlobals);
|
||||
@@ -219,7 +238,7 @@ class CommunityContent
|
||||
{
|
||||
$screenshots = DB::Aowow()->select('
|
||||
SELECT s.id, a.displayName AS user, s.date, s.width, s.height, s.type, s.typeId, s.caption, s.status, s.status AS "flags"
|
||||
FROM ?_screenshots s
|
||||
FROM ?_screenshots s,
|
||||
LEFT JOIN ?_account a ON s.userIdOwner = a.id
|
||||
WHERE
|
||||
{ s.type = ?d}
|
||||
@@ -287,20 +306,21 @@ class CommunityContent
|
||||
|
||||
public static function getScreenshotPagesForManager($all, &$nFound)
|
||||
{
|
||||
// i GUESS .. ss_getALL ? everything : pending
|
||||
// i GUESS .. ss_getALL ? everything : unapproved
|
||||
$nFound = 0;
|
||||
$pages = DB::Aowow()->select('
|
||||
SELECT s.`type`, s.`typeId`, count(1) AS "count", MIN(s.`date`) AS "date"
|
||||
FROM ?_screenshots s
|
||||
{WHERE (s.status & ?d) = 0}
|
||||
GROUP BY s.`type`, s.`typeId`',
|
||||
$all ? DBSIMPLE_SKIP : CC_FLAG_APPROVED | CC_FLAG_DELETED
|
||||
$all ? DBSIMPLE_SKIP : CC_FLAG_APPROVED
|
||||
);
|
||||
|
||||
if ($pages)
|
||||
{
|
||||
// limit to one actually existing type each
|
||||
foreach (array_unique(array_column($pages, 'type')) as $t)
|
||||
$types = array_intersect(array_unique(array_column($pages, 'type')), array_keys(Util::$typeClasses));
|
||||
foreach ($types as $t)
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($pages as $row)
|
||||
@@ -310,21 +330,22 @@ class CommunityContent
|
||||
if (!$ids)
|
||||
continue;
|
||||
|
||||
$obj = Type::newList($t, [CFG_SQL_LIMIT_NONE, ['id', $ids]]);
|
||||
if (!$obj || $obj->error)
|
||||
continue;
|
||||
$cnd = [['id', $ids]];
|
||||
if ($t == TYPE_WORLDEVENT) // FKIN HOLIDAYS
|
||||
array_push($cnd, ['holidayId', $ids], 'OR');
|
||||
|
||||
$tClass = new Util::$typeClasses[$t]($cnd);
|
||||
foreach ($pages as &$p)
|
||||
if ($p['type'] == $t)
|
||||
if ($obj->getEntry($p['typeId']))
|
||||
$p['name'] = $obj->getField('name', true);
|
||||
if ($tClass->getEntry($p['typeId']))
|
||||
$p['name'] = $tClass->getField('name', true);
|
||||
}
|
||||
|
||||
foreach ($pages as &$p)
|
||||
{
|
||||
if (empty($p['name']))
|
||||
{
|
||||
trigger_error('Screenshot linked to nonexistant type/typeId combination: '.$p['type'].'/'.$p['typeId'], E_USER_NOTICE);
|
||||
Util::addNote(U_GROUP_STAFF | U_GROUP_SCREENSHOT, 'AdminPage::handleScreenshots() - Screenshot linked to nonexistant type/typeId combination '.$p['type'].'/'.$p['typeId']);
|
||||
unset($p);
|
||||
}
|
||||
else
|
||||
@@ -338,10 +359,10 @@ class CommunityContent
|
||||
return $pages;
|
||||
}
|
||||
|
||||
public static function getComments(int $type, int $typeId) : array
|
||||
private static function getComments($type, $typeId)
|
||||
{
|
||||
|
||||
$results = DB::Aowow()->query(self::$coQuery, User::$id, User::$id, RATING_COMMENT, 0, $type, $typeId, CC_FLAG_DELETED, User::$id, (int)User::isInGroup(U_GROUP_COMMENTS_MODERATOR));
|
||||
$results = DB::Aowow()->query(self::$commentQuery, User::$id, User::$id, 0, $type, $typeId, CC_FLAG_DELETED, User::$id, (int)User::isInGroup(U_GROUP_COMMENTS_MODERATOR));
|
||||
$comments = [];
|
||||
|
||||
// additional informations
|
||||
@@ -350,7 +371,7 @@ class CommunityContent
|
||||
{
|
||||
(new Markup($r['body']))->parseGlobalsFromText(self::$jsGlobals);
|
||||
|
||||
self::$jsGlobals[Type::USER][$r['userId']] = $r['userId'];
|
||||
self::$jsGlobals[TYPE_USER][$r['userId']] = $r['userId'];
|
||||
|
||||
$c = array(
|
||||
'commentv2' => 1, // always 1.. enables some features i guess..?
|
||||
@@ -396,20 +417,22 @@ class CommunityContent
|
||||
return $comments;
|
||||
}
|
||||
|
||||
public static function getVideos(int $typeOrUser = 0, int $typeId = 0, int &$nFound = 0, bool $dateFmt = true) : array
|
||||
public static function getVideos($typeOrUser, $typeId = 0, &$nFound = 0)
|
||||
{
|
||||
$videos = DB::Aowow()->selectPage($nFound, self::$viQuery,
|
||||
$videos = DB::Aowow()->selectPage($nFound, "
|
||||
SELECT v.id, a.displayName AS user, v.date, v.videoId, v.caption, IF(v.status & ?d, 1, 0) AS 'sticky', v.type, v.typeId
|
||||
FROM ?_videos v
|
||||
LEFT JOIN ?_account a ON v.userIdOwner = a.id
|
||||
WHERE {v.userIdOwner = ?d }{v.type = ? }{AND v.typeId = ? }AND v.status & ?d AND (v.status & ?d) = 0",
|
||||
CC_FLAG_STICKY,
|
||||
$typeOrUser < 0 ? -$typeOrUser : DBSIMPLE_SKIP,
|
||||
$typeOrUser > 0 ? $typeOrUser : DBSIMPLE_SKIP,
|
||||
$typeOrUser > 0 ? $typeId : DBSIMPLE_SKIP,
|
||||
CC_FLAG_APPROVED,
|
||||
CC_FLAG_DELETED,
|
||||
!$typeOrUser ? 'date' : DBSIMPLE_SKIP,
|
||||
!$typeOrUser ? CFG_SQL_LIMIT_SEARCH : DBSIMPLE_SKIP
|
||||
CC_FLAG_DELETED
|
||||
);
|
||||
|
||||
if ($typeOrUser <= 0) // not for search by type/typeId
|
||||
if ($typeOrUser < 0) // only for user page
|
||||
{
|
||||
foreach ($videos as $v)
|
||||
self::addSubject($v['type'], $v['typeId']);
|
||||
@@ -420,7 +443,7 @@ class CommunityContent
|
||||
// format data to meet requirements of the js
|
||||
foreach ($videos as &$v)
|
||||
{
|
||||
if ($typeOrUser <= 0) // not for search by type/typeId
|
||||
if ($typeOrUser < 0) // only for user page
|
||||
{
|
||||
if (!empty(self::$subjCache[$v['type']][$v['typeId']]) && !is_numeric(self::$subjCache[$v['type']][$v['typeId']]))
|
||||
$v['subject'] = self::$subjCache[$v['type']][$v['typeId']];
|
||||
@@ -428,7 +451,7 @@ class CommunityContent
|
||||
$v['subject'] = Lang::user('removed');
|
||||
}
|
||||
|
||||
$v['date'] = $dateFmt ? date(Util::$dateFormatInternal, $v['date']) : intVal($v['date']);
|
||||
$v['date'] = date(Util::$dateFormatInternal, $v['date']);
|
||||
$v['videoType'] = 1; // always youtube
|
||||
|
||||
if (!$v['sticky'])
|
||||
@@ -441,20 +464,22 @@ class CommunityContent
|
||||
return $videos;
|
||||
}
|
||||
|
||||
public static function getScreenshots(int $typeOrUser = 0, int $typeId = 0, int &$nFound = 0, bool $dateFmt = true) : array
|
||||
public static function getScreenshots($typeOrUser, $typeId = 0, &$nFound = 0)
|
||||
{
|
||||
$screenshots = DB::Aowow()->selectPage($nFound, self::$ssQuery,
|
||||
$screenshots = DB::Aowow()->selectPage($nFound, "
|
||||
SELECT s.id, a.displayName AS user, s.date, s.width, s.height, s.caption, IF(s.status & ?d, 1, 0) AS 'sticky', s.type, s.typeId
|
||||
FROM ?_screenshots s
|
||||
LEFT JOIN ?_account a ON s.userIdOwner = a.id
|
||||
WHERE {s.userIdOwner = ?d }{s.type = ? }{AND s.typeId = ? }AND s.status & ?d AND (s.status & ?d) = 0",
|
||||
CC_FLAG_STICKY,
|
||||
$typeOrUser < 0 ? -$typeOrUser : DBSIMPLE_SKIP,
|
||||
$typeOrUser > 0 ? $typeOrUser : DBSIMPLE_SKIP,
|
||||
$typeOrUser > 0 ? $typeId : DBSIMPLE_SKIP,
|
||||
CC_FLAG_APPROVED,
|
||||
CC_FLAG_DELETED,
|
||||
!$typeOrUser ? 'date' : DBSIMPLE_SKIP,
|
||||
!$typeOrUser ? CFG_SQL_LIMIT_SEARCH : DBSIMPLE_SKIP
|
||||
CC_FLAG_DELETED
|
||||
);
|
||||
|
||||
if ($typeOrUser <= 0) // not for search by type/typeId
|
||||
if ($typeOrUser < 0) // only for user page
|
||||
{
|
||||
foreach ($screenshots as $s)
|
||||
self::addSubject($s['type'], $s['typeId']);
|
||||
@@ -465,7 +490,7 @@ class CommunityContent
|
||||
// format data to meet requirements of the js
|
||||
foreach ($screenshots as &$s)
|
||||
{
|
||||
if ($typeOrUser <= 0) // not for search by type/typeId
|
||||
if ($typeOrUser < 0) // only for user page
|
||||
{
|
||||
if (!empty(self::$subjCache[$s['type']][$s['typeId']]) && !is_numeric(self::$subjCache[$s['type']][$s['typeId']]))
|
||||
$s['subject'] = self::$subjCache[$s['type']][$s['typeId']];
|
||||
@@ -473,7 +498,7 @@ class CommunityContent
|
||||
$s['subject'] = Lang::user('removed');
|
||||
}
|
||||
|
||||
$s['date'] = $dateFmt ? date(Util::$dateFormatInternal, $s['date']) : intVal($s['date']);
|
||||
$s['date'] = date(Util::$dateFormatInternal, $s['date']);
|
||||
|
||||
if (!$s['sticky'])
|
||||
unset($s['sticky']);
|
||||
@@ -485,11 +510,11 @@ class CommunityContent
|
||||
return $screenshots;
|
||||
}
|
||||
|
||||
public static function getAll(int $type, int $typeId, array &$jsg) : array
|
||||
public static function getAll($type, $typeId, &$jsg)
|
||||
{
|
||||
$result = array(
|
||||
'vi' => self::getVideos($type, $typeId),
|
||||
'ss' => self::getScreenshots($type, $typeId),
|
||||
'sc' => self::getScreenshots($type, $typeId),
|
||||
'co' => self::getComments($type, $typeId)
|
||||
);
|
||||
|
||||
@@ -497,10 +522,5 @@ class CommunityContent
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function getJSGlobals() : array
|
||||
{
|
||||
return self::$jsGlobals;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -15,8 +15,6 @@ class DB
|
||||
private static $optionsCache = [];
|
||||
private static $connectionCache = [];
|
||||
|
||||
private static $logs = [];
|
||||
|
||||
private static function createConnectSyntax(&$options)
|
||||
{
|
||||
return 'mysqli://'.$options['user'].':'.$options['pass'].'@'.$options['host'].'/'.$options['db'];
|
||||
@@ -31,43 +29,17 @@ class DB
|
||||
$interface = DbSimple_Generic::connect(self::createConnectSyntax($options));
|
||||
|
||||
if (!$interface || $interface->error)
|
||||
die('Failed to connect to database on index #'.$idx.".\n");
|
||||
die('Failed to connect to database.');
|
||||
|
||||
$interface->setErrorHandler(['DB', 'errorHandler']);
|
||||
$interface->query('SET NAMES ?', 'utf8mb4');
|
||||
$interface->query('SET NAMES ?', 'utf8');
|
||||
if ($options['prefix'])
|
||||
$interface->setIdentPrefix($options['prefix']);
|
||||
|
||||
// disable STRICT_TRANS_TABLES and STRICT_ALL_TABLES off. It prevents usage of implicit default values.
|
||||
if ($idx == DB_AOWOW)
|
||||
$interface->query("SET SESSION sql_mode = 'NO_ENGINE_SUBSTITUTION'");
|
||||
// disable ONLY_FULL_GROUP_BY (Allows for non-aggregated selects in a group-by query)
|
||||
else
|
||||
$interface->query("SET SESSION sql_mode = ''");
|
||||
|
||||
self::$interfaceCache[$idx] = &$interface;
|
||||
self::$connectionCache[$idx] = true;
|
||||
}
|
||||
|
||||
public static function test(array $options, ?string &$err = '') : bool
|
||||
{
|
||||
$defPort = ini_get('mysqli.default_port');
|
||||
$port = 0;
|
||||
if (strstr($options['host'], ':'))
|
||||
[$options['host'], $port] = explode(':', $options['host']);
|
||||
|
||||
try {
|
||||
$link = @mysqli_connect($options['host'], $options['user'], $options['pass'], $options['db'], $port ?: $defPort);
|
||||
mysqli_close($link);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
$err = '['.mysqli_connect_errno().'] '.mysqli_connect_error();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function errorHandler($message, $data)
|
||||
{
|
||||
if (!error_reporting())
|
||||
@@ -79,35 +51,6 @@ class DB
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function logger($self, $query, $trace)
|
||||
{
|
||||
if ($trace) // actual query
|
||||
self::$logs[] = [substr(str_replace("\n", ' ', $query), 0, 200)];
|
||||
else // the statistics
|
||||
{
|
||||
end(self::$logs);
|
||||
self::$logs[key(self::$logs)][] = substr(explode(';', $query)[0], 5);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getLogs()
|
||||
{
|
||||
$out = '<pre><table style="font-size:12;"><tr><th></th><th>Time</th><th>Query</th></tr>';
|
||||
foreach (self::$logs as $i => [$l, $t])
|
||||
{
|
||||
$c = 'inherit';
|
||||
preg_match('/(\d+)/', $t, $m);
|
||||
if ($m[1] > 100)
|
||||
$c = '#FFA0A0';
|
||||
else if ($m[1] > 20)
|
||||
$c = '#FFFFA0';
|
||||
|
||||
$out .= '<tr><td>'.$i.'.</td><td style="background-color:'.$c.';">'.$t.'</td><td>'.$l.'</td></tr>';
|
||||
}
|
||||
|
||||
return Util::jsEscape($out).'</table></pre>';
|
||||
}
|
||||
|
||||
public static function getDB($idx)
|
||||
{
|
||||
return self::$interfaceCache[$idx];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,490 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class Game
|
||||
{
|
||||
public static $resistanceFields = array(
|
||||
null, 'resHoly', 'resFire', 'resNature', 'resFrost', 'resShadow', 'resArcane'
|
||||
);
|
||||
|
||||
public static $rarityColorStings = array( // zero-indexed
|
||||
'9d9d9d', 'ffffff', '1eff00', '0070dd', 'a335ee', 'ff8000', 'e5cc80', 'e6cc80'
|
||||
);
|
||||
|
||||
public static $specIconStrings = array(
|
||||
-1 => 'inv_misc_questionmark',
|
||||
0 => 'spell_nature_elementalabsorption',
|
||||
6 => ['spell_deathknight_bloodpresence', 'spell_deathknight_frostpresence', 'spell_deathknight_unholypresence' ],
|
||||
11 => ['spell_nature_starfall', 'ability_racial_bearform', 'spell_nature_healingtouch' ],
|
||||
3 => ['ability_hunter_beasttaming', 'ability_marksmanship', 'ability_hunter_swiftstrike' ],
|
||||
8 => ['spell_holy_magicalsentry', 'spell_fire_firebolt02', 'spell_frost_frostbolt02' ],
|
||||
2 => ['spell_holy_holybolt', 'spell_holy_devotionaura', 'spell_holy_auraoflight' ],
|
||||
5 => ['spell_holy_wordfortitude', 'spell_holy_holybolt', 'spell_shadow_shadowwordpain' ],
|
||||
4 => ['ability_rogue_eviscerate', 'ability_backstab', 'ability_stealth' ],
|
||||
7 => ['spell_nature_lightning', 'spell_nature_lightningshield', 'spell_nature_magicimmunity' ],
|
||||
9 => ['spell_shadow_deathcoil', 'spell_shadow_metamorphosis', 'spell_shadow_rainoffire' ],
|
||||
1 => ['ability_rogue_eviscerate', 'ability_warrior_innerrage', 'ability_warrior_defensivestance' ]
|
||||
);
|
||||
|
||||
public static $classFileStrings = array(
|
||||
null, 'warrior', 'paladin', 'hunter', 'rogue', 'priest', 'deathknight', 'shaman', 'mage', 'warlock', null, 'druid'
|
||||
);
|
||||
|
||||
private static $combatRatingToItemMod = array( // zero-indexed idx:CR; val:Mod
|
||||
null, 12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28,
|
||||
29, 30, null, null, null, 37, 44
|
||||
);
|
||||
|
||||
public static $lvlIndepRating = array( // rating doesn't scale with level
|
||||
ITEM_MOD_MANA, ITEM_MOD_HEALTH, ITEM_MOD_ATTACK_POWER, ITEM_MOD_MANA_REGENERATION, ITEM_MOD_SPELL_POWER,
|
||||
ITEM_MOD_HEALTH_REGEN, ITEM_MOD_SPELL_PENETRATION, ITEM_MOD_BLOCK_VALUE
|
||||
);
|
||||
|
||||
public static $questClasses = array(
|
||||
-2 => [ 0],
|
||||
0 => [ 1, 3, 4, 8, 9, 10, 11, 12, 25, 28, 33, 36, 38, 40, 41, 44, 45, 46, 47, 51, 85, 130, 132, 139, 154, 267, 1497, 1519, 1537, 2257, 3430, 3431, 3433, 3487, 4080, 4298],
|
||||
1 => [ 14, 15, 16, 17, 141, 148, 188, 215, 220, 331, 357, 361, 363, 400, 405, 406, 440, 490, 493, 618, 1377, 1637, 1638, 1657, 1769, 3524, 3525, 3526, 3557],
|
||||
2 => [ 206, 209, 491, 717, 718, 719, 721, 722, 796, 1176, 1196, 1337, 1417, 1581, 1583, 1584, 1941, 2017, 2057, 2100, 2366, 2367, 2437, 2557, 3535, 3562, 3688, 3713, 3714, 3715, 3716, 3717, 3789, 3790, 3791, 3792, 3842, 3847, 3848, 3849, 3905, 4100, 4131, 4196, 4228, 4264, 4265, 4272, 4277, 4415, 4416, 4494, 4522, 4723, 4809, 4813, 4820],
|
||||
3 => [ 1977, 2159, 2677, 2717, 3428, 3429, 3456, 3457, 3606, 3607, 3805, 3836, 3845, 3923, 3959, 4075, 4273, 4493, 4500, 4603, 4722, 4812, 4987],
|
||||
4 => [ -372, -263, -262, -261, -162, -161, -141, -82, -81, -61],
|
||||
5 => [ -373, -371, -324, -304, -264, -201, -182, -181, -121, -101, -24],
|
||||
6 => [ -25, 2597, 3277, 3358, 3820, 4384, 4710],
|
||||
7 => [-1010, -368, -367, -365, -344, -241, -1],
|
||||
8 => [ 3483, 3518, 3519, 3520, 3521, 3522, 3523, 3679, 3703],
|
||||
9 => [-1005, -1003, -1002, -1001, -376, -375, -374, -370, -369, -366, -364, -41, -22], // 22: seasonal
|
||||
10 => [ 65, 66, 67, 210, 394, 495, 2817, 3537, 3711, 4024, 4197, 4395, 4742]
|
||||
);
|
||||
|
||||
/* why:
|
||||
Because petSkills (and ranged weapon skills) are the only ones with more than two skillLines attached. Because Left Joining ?_spell with ?_skillLineability causes more trouble than it has uses.
|
||||
Because this is more or less the only reaonable way to fit all that information into one database field, so..
|
||||
.. the indizes of this array are bits of skillLine2OrMask in ?_spell if skillLineId1 is negative
|
||||
*/
|
||||
public static $skillLineMask = array( // idx => [familyId, skillLineId]
|
||||
-1 => array( // Pets (Hunter)
|
||||
[ 1, 208], [ 2, 209], [ 3, 203], [ 4, 210], [ 5, 211], [ 6, 212], [ 7, 213], // Wolf, Cat, Spider, Bear, Boar, Crocolisk, Carrion Bird
|
||||
[ 8, 214], [ 9, 215], [11, 217], [12, 218], [20, 236], [21, 251], [24, 653], // Crab, Gorilla, Raptor, Tallstrider, Scorpid, Turtle, Bat
|
||||
[25, 654], [26, 655], [27, 656], [30, 763], [31, 767], [32, 766], [33, 765], // Hyena, Bird of Prey, Wind Serpent, Dragonhawk, Ravager, Warp Stalker, Sporebat
|
||||
[34, 764], [35, 768], [37, 775], [38, 780], [39, 781], [41, 783], [42, 784], // Nether Ray, Serpent, Moth, Chimaera, Devilsaur, Silithid, Worm
|
||||
[43, 786], [44, 785], [45, 787], [46, 788] // Rhino, Wasp, Core Hound, Spirit Beast
|
||||
),
|
||||
-2 => array( // Pets (Warlock)
|
||||
[15, 189], [16, 204], [17, 205], [19, 207], [23, 188], [29, 761] // Felhunter, Voidwalker, Succubus, Doomguard, Imp, Felguard
|
||||
),
|
||||
-3 => array( // Ranged Weapons
|
||||
[null, 45], [null, 46], [null, 226] // Bow, Gun, Crossbow
|
||||
)
|
||||
);
|
||||
|
||||
public static $sockets = array( // jsStyle Strings
|
||||
'meta', 'red', 'yellow', 'blue'
|
||||
);
|
||||
|
||||
// 'replicates' $WH.g_statToJson
|
||||
public static $itemMods = array( // zero-indexed; "mastrtng": unused mastery; _[a-z] => taken mods..
|
||||
'dmg', 'mana', 'health', 'agi', 'str', 'int', 'spi',
|
||||
'sta', 'energy', 'rage', 'focus', 'runicpwr', 'defrtng', 'dodgertng',
|
||||
'parryrtng', 'blockrtng', 'mlehitrtng', 'rgdhitrtng', 'splhitrtng', 'mlecritstrkrtng', 'rgdcritstrkrtng',
|
||||
'splcritstrkrtng', '_mlehitrtng', '_rgdhitrtng', '_splhitrtng', '_mlecritstrkrtng', '_rgdcritstrkrtng', '_splcritstrkrtng',
|
||||
'mlehastertng', 'rgdhastertng', 'splhastertng', 'hitrtng', 'critstrkrtng', '_hitrtng', '_critstrkrtng',
|
||||
'resirtng', 'hastertng', 'exprtng', 'atkpwr', 'rgdatkpwr', 'feratkpwr', 'splheal',
|
||||
'spldmg', 'manargn', 'armorpenrtng', 'splpwr', 'healthrgn', 'splpen', 'block', // ITEM_MOD_BLOCK_VALUE
|
||||
'mastrtng', 'armor', 'firres', 'frores', 'holres', 'shares', 'natres',
|
||||
'arcres', 'firsplpwr', 'frosplpwr', 'holsplpwr', 'shasplpwr', 'natsplpwr', 'arcsplpwr'
|
||||
);
|
||||
|
||||
public static $class2SpellFamily = array(
|
||||
// null Warrior Paladin Hunter Rogue Priest DK Shaman Mage Warlock null Druid
|
||||
null, 4, 10, 9, 8, 6, 15, 11, 3, 5, null, 7
|
||||
);
|
||||
|
||||
public static $areaFloors = array(
|
||||
206 => 3, 209 => 7, 719 => 3, 721 => 4, 796 => 4, 1196 => 2, 1337 => 2, 1581 => 2, 1583 => 7, 1584 => 2,
|
||||
2017 => 2, 2057 => 4, 2100 => 2, 2557 => 6, 2677 => 4, 3428 => 3, 3457 => 17, 3790 => 2, 3791 => 2, 3959 => 8,
|
||||
3456 => 6, 3715 => 2, 3848 => 3, 3849 => 2, 4075 => 2, 4100 => 2, 4131 => 2, 4196 => 2, 4228 => 4, 4272 => 2,
|
||||
4273 => 6, 4277 => 3, 4395 => 2, 4494 => 2, 4722 => 2, 4812 => 8
|
||||
);
|
||||
|
||||
public static function itemModByRatingMask($mask)
|
||||
{
|
||||
if (($mask & 0x1C000) == 0x1C000) // special case resilience
|
||||
return ITEM_MOD_RESILIENCE_RATING;
|
||||
|
||||
if (($mask & 0x00E0) == 0x00E0) // hit rating - all subcats (mle, rgd, spl)
|
||||
return ITEM_MOD_HIT_RATING;
|
||||
|
||||
if (($mask & 0x0700) == 0x0700) // crit rating - all subcats (mle, rgd, spl)
|
||||
return ITEM_MOD_CRIT_RATING;
|
||||
|
||||
for ($j = 0; $j < count(self::$combatRatingToItemMod); $j++)
|
||||
{
|
||||
if (!self::$combatRatingToItemMod[$j])
|
||||
continue;
|
||||
|
||||
if (!($mask & (1 << $j)))
|
||||
continue;
|
||||
|
||||
return self::$combatRatingToItemMod[$j];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function sideByRaceMask($race)
|
||||
{
|
||||
// Any
|
||||
if (!$race || ($race & RACE_MASK_ALL) == RACE_MASK_ALL)
|
||||
return SIDE_BOTH;
|
||||
|
||||
// Horde
|
||||
if ($race & RACE_MASK_HORDE && !($race & RACE_MASK_ALLIANCE))
|
||||
return SIDE_HORDE;
|
||||
|
||||
// Alliance
|
||||
if ($race & RACE_MASK_ALLIANCE && !($race & RACE_MASK_HORDE))
|
||||
return SIDE_ALLIANCE;
|
||||
|
||||
return SIDE_BOTH;
|
||||
}
|
||||
|
||||
public static function getReputationLevelForPoints($pts)
|
||||
{
|
||||
if ($pts >= 41999)
|
||||
return REP_EXALTED;
|
||||
else if ($pts >= 20999)
|
||||
return REP_REVERED;
|
||||
else if ($pts >= 8999)
|
||||
return REP_HONORED;
|
||||
else if ($pts >= 2999)
|
||||
return REP_FRIENDLY;
|
||||
else if ($pts >= 0)
|
||||
return REP_NEUTRAL;
|
||||
else if ($pts >= -3000)
|
||||
return REP_UNFRIENDLY;
|
||||
else if ($pts >= -6000)
|
||||
return REP_HOSTILE;
|
||||
else
|
||||
return REP_HATED;
|
||||
}
|
||||
|
||||
public static function getTaughtSpells(&$spell)
|
||||
{
|
||||
$extraIds = [-1]; // init with -1 to prevent empty-array errors
|
||||
$lookup = [-1];
|
||||
switch (gettype($spell))
|
||||
{
|
||||
case 'object':
|
||||
if (get_class($spell) != 'SpellList')
|
||||
return [];
|
||||
|
||||
$lookup[] = $spell->id;
|
||||
foreach ($spell->canTeachSpell() as $idx)
|
||||
$extraIds[] = $spell->getField('effect'.$idx.'TriggerSpell');
|
||||
|
||||
break;
|
||||
case 'integer':
|
||||
$lookup[] = $spell;
|
||||
break;
|
||||
case 'array':
|
||||
$lookup = $spell;
|
||||
break;
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
|
||||
// note: omits required spell and chance in skill_discovery_template
|
||||
$data = array_merge(
|
||||
DB::World()->selectCol('SELECT spellId FROM spell_learn_spell WHERE entry IN (?a)', $lookup),
|
||||
DB::World()->selectCol('SELECT spellId FROM skill_discovery_template WHERE reqSpell IN (?a)', $lookup),
|
||||
$extraIds
|
||||
);
|
||||
|
||||
// return list of integers, not strings
|
||||
$data = array_map('intVal', $data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function getPageText($ptId)
|
||||
{
|
||||
$pages = [];
|
||||
while ($ptId)
|
||||
{
|
||||
if ($row = DB::World()->selectRow('SELECT ptl.Text AS Text_loc?d, pt.* FROM page_text pt LEFT JOIN page_text_locale ptl ON pt.ID = ptl.ID AND locale = ? WHERE pt.ID = ?d', User::$localeId, User::$localeString, $ptId))
|
||||
{
|
||||
$ptId = $row['NextPageID'];
|
||||
$pages[] = Util::parseHtmlText(Util::localizedString($row, 'Text'));
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error('Referenced PageTextId #'.$ptId.' is not in DB', E_USER_WARNING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
|
||||
/*********************/
|
||||
/* World Pos. Checks */
|
||||
/*********************/
|
||||
|
||||
private static $alphaMapCache = [];
|
||||
|
||||
private static function alphaMapCheck(int $areaId, array &$set) : bool
|
||||
{
|
||||
$file = 'setup/generated/alphaMaps/'.$areaId.'.png';
|
||||
if (!file_exists($file)) // file does not exist (probably instanced area)
|
||||
return false;
|
||||
|
||||
// invalid and corner cases (literally)
|
||||
if (!is_array($set) || empty($set['posX']) || empty($set['posY']) || $set['posX'] >= 100 || $set['posY'] >= 100)
|
||||
{
|
||||
$set = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (empty(self::$alphaMapCache[$areaId]))
|
||||
self::$alphaMapCache[$areaId] = imagecreatefrompng($file);
|
||||
|
||||
// alphaMaps are 1000 x 1000, adapt points [black => valid point]
|
||||
if (!imagecolorat(self::$alphaMapCache[$areaId], $set['posX'] * 10, $set['posY'] * 10))
|
||||
$set = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function checkCoords(array $points) : array
|
||||
{
|
||||
$result = [];
|
||||
$capitals = array( // capitals take precedence over their surroundings
|
||||
1497, 1637, 1638, 3487, // Undercity, Ogrimmar, Thunder Bluff, Silvermoon City
|
||||
1519, 1537, 1657, 3557, // Stormwind City, Ironforge, Darnassus, The Exodar
|
||||
3703, 4395 // Shattrath City, Dalaran
|
||||
);
|
||||
|
||||
foreach ($points as $res)
|
||||
{
|
||||
if (self::alphaMapCheck($res['areaId'], $res))
|
||||
{
|
||||
if (!$res)
|
||||
continue;
|
||||
|
||||
// some rough measure how central the spawn is on the map (the lower the number, the better)
|
||||
// 0: perfect center; 1: touches a border
|
||||
$q = abs( (($res['posX'] - 50) / 50) * (($res['posY'] - 50) / 50) );
|
||||
|
||||
if (empty($result) || $result[0] > $q)
|
||||
$result = [$q, $res];
|
||||
}
|
||||
else if (in_array($res['areaId'], $capitals)) // capitals (auto-discovered) and no hand-made alphaMap available
|
||||
return $res;
|
||||
else if (empty($result)) // add with lowest quality if alpha map is missing
|
||||
$result = [1.0, $res];
|
||||
}
|
||||
|
||||
// spawn does not really match on a map, but we need at least one result
|
||||
if (!$result)
|
||||
{
|
||||
usort($points, function ($a, $b) { return ($a['dist'] < $b['dist']) ? -1 : 1; });
|
||||
$result = [1.0, $points[0]];
|
||||
}
|
||||
|
||||
return $result[1];
|
||||
}
|
||||
|
||||
public static function getWorldPosForGUID(int $type, int ...$guids) : array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case Type::NPC:
|
||||
$result = DB::World()->select('SELECT `guid` AS ARRAY_KEY, `id`, `map` AS `mapId`, `position_y` AS `posX`, `position_x` AS `posY` FROM creature WHERE `guid` IN (?a)', $guids);
|
||||
break;
|
||||
case Type::OBJECT:
|
||||
$result = DB::World()->select('SELECT `guid` AS ARRAY_KEY, `id`, `map` AS `mapId`, `position_y` AS `posX`, `position_x` AS `posY` FROM gameobject WHERE `guid` IN (?a)', $guids);
|
||||
break;
|
||||
case Type::SOUND:
|
||||
$result = DB::AoWoW()->select('SELECT `soundId` AS ARRAY_KEY, `soundId` AS `id`, `mapId`, `posX`, `posY` FROM dbc_soundemitters WHERE `soundId` IN (?a)', $guids);
|
||||
break;
|
||||
case Type::AREATRIGGER:
|
||||
$result = DB::AoWoW()->select('SELECT `id` AS ARRAY_KEY, `id`, `mapId`, `posX`, `posY` FROM dbc_areatrigger WHERE `id` IN (?a)', $guids);
|
||||
break;
|
||||
default:
|
||||
trigger_error('Game::getWorldPosForGUID - instanced with unsupported TYPE '.$type, E_USER_WARNING);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function worldPosToZonePos(int $mapId, float $posX, float $posY, int $areaId = 0, int $floor = -1) : array
|
||||
{
|
||||
if (!$mapId < 0)
|
||||
return [];
|
||||
|
||||
$query = 'SELECT
|
||||
dm.id,
|
||||
wma.areaId,
|
||||
IFNULL(dm.floor, 0) AS floor,
|
||||
100 - ROUND(IF(dm.id IS NOT NULL, (?f - dm.minY) * 100 / (dm.maxY - dm.minY), (?f - wma.right) * 100 / (wma.left - wma.right)), 1) AS `posX`,
|
||||
100 - ROUND(IF(dm.id IS NOT NULL, (?f - dm.minX) * 100 / (dm.maxX - dm.minX), (?f - wma.bottom) * 100 / (wma.top - wma.bottom)), 1) AS `posY`,
|
||||
SQRT(POWER(abs(IF(dm.id IS NOT NULL, (?f - dm.minY) * 100 / (dm.maxY - dm.minY), (?f - wma.right) * 100 / (wma.left - wma.right)) - 50), 2) +
|
||||
POWER(abs(IF(dm.id IS NOT NULL, (?f - dm.minX) * 100 / (dm.maxX - dm.minX), (?f - wma.bottom) * 100 / (wma.top - wma.bottom)) - 50), 2)) AS `dist`
|
||||
FROM
|
||||
dbc_worldmaparea wma
|
||||
LEFT JOIN
|
||||
dbc_dungeonmap dm ON dm.mapId = IF(?d AND (wma.mapId NOT IN (0, 1, 530, 571) OR wma.areaId = 4395), wma.mapId, -1)
|
||||
WHERE
|
||||
wma.mapId = ?d AND IF(?d, wma.areaId = ?d, wma.areaId <> 0){ AND IF(dm.floor IS NULL, 1, dm.floor = ?d)}
|
||||
HAVING
|
||||
(`posX` BETWEEN 0.1 AND 99.9 AND `posY` BETWEEN 0.1 AND 99.9)
|
||||
ORDER BY
|
||||
`dist` ASC';
|
||||
|
||||
// dist BETWEEN 0 (center) AND 70.7 (corner)
|
||||
$points = DB::Aowow()->select($query, $posX, $posX, $posY, $posY, $posX, $posX, $posY, $posY, 1, $mapId, $areaId, $areaId, $floor < 0 ? DBSIMPLE_SKIP : $floor);
|
||||
if (!$points) // retry: TC counts pre-instance subareas as instance-maps .. which have no map file
|
||||
$points = DB::Aowow()->select($query, $posX, $posX, $posY, $posY, $posX, $posX, $posY, $posY, 0, $mapId, 0, 0, DBSIMPLE_SKIP);
|
||||
|
||||
if (!is_array($points))
|
||||
{
|
||||
trigger_error('Game::worldPosToZonePos - dbc query failed', E_USER_ERROR);
|
||||
return [];
|
||||
}
|
||||
|
||||
return $points;
|
||||
}
|
||||
|
||||
public static function getQuotesForCreature(int $creatureId, bool $asHTML = false, string $talkSource = '') : array
|
||||
{
|
||||
$nQuotes = 0;
|
||||
$quotes = [];
|
||||
$soundIds = [];
|
||||
|
||||
$quoteSrc = DB::World()->select('
|
||||
SELECT
|
||||
ct.GroupID AS ARRAY_KEY, ct.ID as ARRAY_KEY2,
|
||||
ct.`Type` AS `talkType`,
|
||||
ct.TextRange AS `range`,
|
||||
IFNULL(bct.`LanguageID`, ct.`Language`) AS lang,
|
||||
IFNULL(NULLIF(bct.Text, ""), IFNULL(NULLIF(bct.Text1, ""), IFNULL(ct.`Text`, ""))) AS text_loc0,
|
||||
{IFNULL(NULLIF(bctl.Text, ""), IFNULL(NULLIF(bctl.Text1, ""), IFNULL(ctl.Text, ""))) AS text_loc?d,}
|
||||
IF(bct.SoundEntriesID > 0, bct.SoundEntriesID, ct.Sound) AS soundId
|
||||
FROM
|
||||
creature_text ct
|
||||
{LEFT JOIN
|
||||
creature_text_locale ctl ON ct.CreatureID = ctl.CreatureID AND ct.GroupID = ctl.GroupID AND ct.ID = ctl.ID AND ctl.Locale = ?}
|
||||
LEFT JOIN
|
||||
broadcast_text bct ON ct.BroadcastTextId = bct.ID
|
||||
{LEFT JOIN
|
||||
broadcast_text_locale bctl ON ct.BroadcastTextId = bctl.ID AND bctl.locale = ?}
|
||||
WHERE
|
||||
ct.CreatureID = ?d',
|
||||
User::$localeId ?: DBSIMPLE_SKIP,
|
||||
User::$localeId ? Util::$localeStrings[User::$localeId] : DBSIMPLE_SKIP,
|
||||
User::$localeId ? Util::$localeStrings[User::$localeId] : DBSIMPLE_SKIP,
|
||||
$creatureId
|
||||
);
|
||||
|
||||
foreach ($quoteSrc as $grp => $text)
|
||||
{
|
||||
$group = [];
|
||||
foreach ($text as $t)
|
||||
{
|
||||
if ($t['soundId'])
|
||||
$soundIds[] = $t['soundId'];
|
||||
|
||||
$msg = Util::localizedString($t, 'text');
|
||||
if (!$msg)
|
||||
continue;
|
||||
|
||||
// fixup .. either set %s for emotes or dont >.<
|
||||
if (in_array($t['talkType'], [2, 16]) && strpos($msg, '%s') === false)
|
||||
$msg = '%s '.$msg;
|
||||
|
||||
// fixup: bad case-insensivity
|
||||
$msg = Util::parseHtmlText(str_replace('%S', '%s', htmlentities($msg)), !$asHTML);
|
||||
|
||||
if ($talkSource)
|
||||
$msg = sprintf($msg, $talkSource);
|
||||
|
||||
// make type css compatible
|
||||
switch ($t['talkType'])
|
||||
{
|
||||
case 1: // yell:
|
||||
case 14: $t['talkType'] = 1; break; // - dark red
|
||||
case 2: // emote:
|
||||
case 16: // "
|
||||
case 3: // boss emote:
|
||||
case 41: $t['talkType'] = 4; break; // - orange
|
||||
case 4: // whisper:
|
||||
case 15: // "
|
||||
case 5: // boss whisper:
|
||||
case 42: $t['talkType'] = 3; break; // - pink-ish
|
||||
default: $t['talkType'] = 2; // [type: 0, 12] say: yellow-ish
|
||||
|
||||
}
|
||||
|
||||
// prefix
|
||||
$pre = '';
|
||||
if ($t['talkType'] != 4)
|
||||
$pre = ($talkSource ?: '%s').' '.Lang::npc('textTypes', $t['talkType']).Lang::main('colon').($t['lang'] ? '['.Lang::game('languages', $t['lang']).'] ' : null);
|
||||
|
||||
if ($asHTML)
|
||||
$msg = '<div><span class="s'.$t['talkType'].'">%s'.($t['range'] ? sprintf(Util::$dfnString, Lang::npc('textRanges', $t['range']), $msg) : $msg).'</span></div>';
|
||||
else
|
||||
$msg = '[div][span class=s'.$t['talkType'].']%s'.html_entity_decode($msg).'[/span][/div]';
|
||||
|
||||
$line = array(
|
||||
'range' => $t['range'],
|
||||
'text' => $msg,
|
||||
'prefix' => $pre
|
||||
);
|
||||
|
||||
|
||||
$nQuotes++;
|
||||
$group[] = $line;
|
||||
}
|
||||
|
||||
if ($group)
|
||||
$quotes[$grp] = $group;
|
||||
}
|
||||
|
||||
return [$quotes, $nQuotes, $soundIds];
|
||||
}
|
||||
|
||||
public static function getBreakpointsForSkill(int $skillId, int $reqLevel) : array
|
||||
{
|
||||
switch ($skillId)
|
||||
{
|
||||
case SKILL_HERBALISM:
|
||||
case SKILL_LOCKPICKING:
|
||||
case SKILL_JEWELCRAFTING:
|
||||
case SKILL_INSCRIPTION:
|
||||
case SKILL_SKINNING:
|
||||
case SKILL_MINING:
|
||||
$points = [$reqLevel]; // red/orange
|
||||
|
||||
if ($reqLevel + 25 <= MAX_SKILL) // orange/yellow
|
||||
$points[] = $reqLevel + 25;
|
||||
|
||||
if ($reqLevel + 50 <= MAX_SKILL) // yellow/green
|
||||
$points[] = $reqLevel + 50;
|
||||
|
||||
if ($reqLevel + 100 <= MAX_SKILL) // green/grey
|
||||
$points[] = $reqLevel + 100;
|
||||
|
||||
return $points;
|
||||
default:
|
||||
return [$reqLevel];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -9,31 +9,22 @@ if (file_exists('config/config.php'))
|
||||
else
|
||||
$AoWoWconf = [];
|
||||
|
||||
|
||||
mb_internal_encoding('UTF-8');
|
||||
|
||||
|
||||
define('OS_WIN', substr(PHP_OS, 0, 3) == 'WIN');
|
||||
|
||||
|
||||
require_once 'includes/defines.php';
|
||||
require_once 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using variant: https://github.com/ivan1986/DbSimple/tree/master)
|
||||
require_once 'includes/utilities.php'; // helper functions
|
||||
require_once 'includes/game.php'; // game related data & functions
|
||||
require_once 'includes/profiler.class.php';
|
||||
require_once 'includes/utilities.php'; // misc™ data 'n func
|
||||
require_once 'includes/ajaxHandler.class.php'; // handles ajax and jsonp requests
|
||||
require_once 'includes/user.class.php';
|
||||
require_once 'includes/markup.class.php'; // manipulate markup text
|
||||
require_once 'includes/database.class.php'; // wrap DBSimple
|
||||
require_once 'includes/community.class.php'; // handle comments, screenshots and videos
|
||||
require_once 'includes/loot.class.php'; // build lv-tabs containing loot-information
|
||||
require_once 'includes/smartAI.class.php';
|
||||
require_once 'localization/lang.class.php';
|
||||
require_once 'pages/genericPage.class.php';
|
||||
|
||||
|
||||
// autoload List-classes, associated filters and pages
|
||||
spl_autoload_register(function ($class) {
|
||||
$class = strtolower(str_replace('ListFilter', 'List', $class));
|
||||
$class = strtolower(str_replace('Filter', '', $class));
|
||||
|
||||
if (class_exists($class)) // already registered
|
||||
return;
|
||||
@@ -41,37 +32,18 @@ spl_autoload_register(function ($class) {
|
||||
if (preg_match('/[^\w]/i', $class)) // name should contain only letters
|
||||
return;
|
||||
|
||||
if (stripos($class, 'list'))
|
||||
if (strpos($class, 'list'))
|
||||
{
|
||||
require_once 'includes/basetype.class.php';
|
||||
if (!class_exists('BaseType'))
|
||||
require_once 'includes/types/basetype.class.php';
|
||||
|
||||
$cl = strtr($class, ['list' => '']);
|
||||
if ($cl == 'remoteprofile' || $cl == 'localprofile')
|
||||
$cl = 'profile';
|
||||
if ($cl == 'remotearenateam' || $cl == 'localarenateam')
|
||||
$cl = 'arenateam';
|
||||
if ($cl == 'remoteguild' || $cl == 'localguild')
|
||||
$cl = 'guild';
|
||||
|
||||
if (file_exists('includes/types/'.$cl.'.class.php'))
|
||||
require_once 'includes/types/'.$cl.'.class.php';
|
||||
else
|
||||
throw new Exception('could not register type class: '.$cl);
|
||||
if (file_exists('includes/types/'.strtr($class, ['list' => '']).'.class.php'))
|
||||
require_once 'includes/types/'.strtr($class, ['list' => '']).'.class.php';
|
||||
|
||||
return;
|
||||
}
|
||||
else if (stripos($class, 'ajax') === 0)
|
||||
{
|
||||
require_once 'includes/ajaxHandler.class.php'; // handles ajax and jsonp requests
|
||||
|
||||
if (file_exists('includes/ajaxHandler/'.strtr($class, ['ajax' => '']).'.class.php'))
|
||||
require_once 'includes/ajaxHandler/'.strtr($class, ['ajax' => '']).'.class.php';
|
||||
else
|
||||
throw new Exception('could not register ajaxHandler class: '.$class);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (file_exists('pages/'.strtr($class, ['page' => '']).'.php'))
|
||||
if (file_exists('pages/'.strtr($class, ['page' => '']).'.php'))
|
||||
require_once 'pages/'.strtr($class, ['page' => '']).'.php';
|
||||
});
|
||||
|
||||
@@ -93,21 +65,14 @@ if (!empty($AoWoWconf['characters']))
|
||||
|
||||
|
||||
// load config to constants
|
||||
function loadConfig(bool $noPHP = false) : void
|
||||
{
|
||||
$sets = DB::isConnectable(DB_AOWOW) ? DB::Aowow()->select('SELECT `key` AS ARRAY_KEY, `value`, `flags` FROM ?_config') : [];
|
||||
foreach ($sets as $k => $v)
|
||||
{
|
||||
$php = $v['flags'] & CON_FLAG_PHP;
|
||||
if ($php && $noPHP)
|
||||
// this should not have been possible
|
||||
if (!strlen($v['value']))
|
||||
continue;
|
||||
|
||||
// this should not have been possible
|
||||
if (!strlen($v['value']) && !($v['flags'] & CON_FLAG_TYPE_STRING) && !$php)
|
||||
{
|
||||
trigger_error('Aowow config value CFG_'.strtoupper($k).' is empty - config will not be used!', E_USER_ERROR);
|
||||
continue;
|
||||
}
|
||||
$php = $v['flags'] & CON_FLAG_PHP;
|
||||
|
||||
if ($v['flags'] & CON_FLAG_TYPE_INT)
|
||||
$val = intVal($v['value']);
|
||||
@@ -116,33 +81,25 @@ function loadConfig(bool $noPHP = false) : void
|
||||
else if ($v['flags'] & CON_FLAG_TYPE_BOOL)
|
||||
$val = (bool)$v['value'];
|
||||
else if ($v['flags'] & CON_FLAG_TYPE_STRING)
|
||||
$val = preg_replace("/[\p{C}]/ui", '', $v['value']);
|
||||
else if ($php)
|
||||
$val = preg_replace('/[^\p{L}0-9~\s_\-\'\/\.:,]/ui', '', $v['value']);
|
||||
else
|
||||
{
|
||||
trigger_error('PHP config value '.strtolower($k).' has no type set - config will not be used!', E_USER_ERROR);
|
||||
continue;
|
||||
}
|
||||
else // if (!$php)
|
||||
{
|
||||
trigger_error('Aowow config value CFG_'.strtoupper($k).' has no type set - value forced to 0!', E_USER_ERROR);
|
||||
Util::addNote(U_GROUP_ADMIN | U_GROUP_DEV, 'Kernel: '.($php ? 'PHP' : 'Aowow').' config value '.($php ? strtolower($k) : 'CFG_'.strtoupper($k)).' has no type set. Value forced to 0!');
|
||||
$val = 0;
|
||||
}
|
||||
|
||||
if ($php)
|
||||
ini_set(strtolower($k), $val);
|
||||
else if (!defined('CFG_'.strtoupper($k)))
|
||||
else
|
||||
define('CFG_'.strtoupper($k), $val);
|
||||
}
|
||||
}
|
||||
loadConfig();
|
||||
|
||||
// handle non-fatal errors and notices
|
||||
error_reporting(!empty($AoWoWconf['aowow']) && CFG_DEBUG ? E_AOWOW : 0);
|
||||
set_error_handler(function($errNo, $errStr, $errFile, $errLine)
|
||||
{
|
||||
|
||||
// handle occuring errors
|
||||
error_reporting(!empty($AoWoWconf['aowow']) && CFG_DEBUG ? (E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED | E_STRICT)) : 0);
|
||||
$errHandled = false;
|
||||
set_error_handler(function($errNo, $errStr, $errFile, $errLine) use (&$errHandled) {
|
||||
$errName = 'unknown error'; // errors not in this list can not be handled by set_error_handler (as per documentation) or are ignored
|
||||
$uGroup = U_GROUP_EMPLOYEE;
|
||||
|
||||
if ($errNo == E_WARNING) // 0x0002
|
||||
$errName = 'E_WARNING';
|
||||
else if ($errNo == E_PARSE) // 0x0004
|
||||
@@ -154,60 +111,29 @@ set_error_handler(function($errNo, $errStr, $errFile, $errLine)
|
||||
else if ($errNo == E_USER_WARNING) // 0x0200
|
||||
$errName = 'E_USER_WARNING';
|
||||
else if ($errNo == E_USER_NOTICE) // 0x0400
|
||||
{
|
||||
$errName = 'E_USER_NOTICE';
|
||||
$uGroup = U_GROUP_STAFF;
|
||||
}
|
||||
else if ($errNo == E_RECOVERABLE_ERROR) // 0x1000
|
||||
$errName = 'E_RECOVERABLE_ERROR';
|
||||
|
||||
Util::addNote($uGroup, $errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine);
|
||||
if (CLI)
|
||||
CLI::write($errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine, $errNo & 0x40A ? CLI::LOG_WARN : CLI::LOG_ERROR);
|
||||
|
||||
if (DB::isConnectable(DB_AOWOW))
|
||||
DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
|
||||
AOWOW_REVISION, $errNo, $errFile, $errLine, CLI ? 'CLI' : ($_SERVER['QUERY_STRING'] ?? ''), User::$groups, $errStr
|
||||
);
|
||||
|
||||
return true;
|
||||
}, E_AOWOW);
|
||||
|
||||
// handle exceptions
|
||||
set_exception_handler(function ($ex)
|
||||
if (User::isInGroup(U_GROUP_STAFF))
|
||||
{
|
||||
Util::addNote(U_GROUP_EMPLOYEE, 'Exception - '.$ex->getMessage().' @ '.$ex->getFile(). ':'.$ex->getLine()."\n".$ex->getTraceAsString());
|
||||
|
||||
if (DB::isConnectable(DB_AOWOW))
|
||||
DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
|
||||
AOWOW_REVISION, $ex->getCode(), $ex->getFile(), $ex->getLine(), CLI ? 'CLI' : ($_SERVER['QUERY_STRING'] ?? ''), User::$groups, $ex->getMessage()
|
||||
);
|
||||
|
||||
if (!CLI)
|
||||
(new GenericPage())->error();
|
||||
else
|
||||
echo 'Exception - '.$ex->getMessage()."\n ".$ex->getFile(). '('.$ex->getLine().")\n".$ex->getTraceAsString()."\n";
|
||||
});
|
||||
|
||||
// handle fatal errors
|
||||
register_shutdown_function(function()
|
||||
if (!$errHandled)
|
||||
{
|
||||
if (($e = error_get_last()) && $e['type'] & (E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR))
|
||||
{
|
||||
Util::addNote(U_GROUP_EMPLOYEE, 'Fatal Error - '.$e['message'].' @ '.$e['file']. ':'.$e['line']);
|
||||
|
||||
if (DB::isConnectable(DB_AOWOW))
|
||||
DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
|
||||
AOWOW_REVISION, $e['type'], $e['file'], $e['line'], CLI ? 'CLI' : ($_SERVER['QUERY_STRING'] ?? ''), User::$groups, $e['message']
|
||||
);
|
||||
|
||||
if (CLI)
|
||||
echo 'Fatal Error - '.$e['message'].' @ '.$e['file']. ':'.$e['line']."\n";
|
||||
|
||||
// cant generate a page for web view :(
|
||||
die();
|
||||
Util::addNote(U_GROUP_STAFF, 'one or more php related error occured, while generating this page.');
|
||||
$errHandled = true;
|
||||
}
|
||||
});
|
||||
|
||||
Util::addNote(U_GROUP_STAFF, $errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine);
|
||||
}
|
||||
|
||||
if (DB::isConnectable(DB_AOWOW))
|
||||
DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
|
||||
AOWOW_REVISION, $errNo, $errFile, $errLine, CLI ? 'CLI' : $_SERVER['QUERY_STRING'], User::$groups, $errStr
|
||||
);
|
||||
|
||||
return !((User::isInGroup(U_GROUP_STAFF) && defined('CFG_DEBUG') && CFG_DEBUG) || CLI);
|
||||
}, E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED | E_STRICT));
|
||||
|
||||
|
||||
$secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || (!empty($AoWoWconf['aowow']) && CFG_FORCE_SSL);
|
||||
if (defined('CFG_STATIC_HOST')) // points js to images & scripts
|
||||
@@ -219,54 +145,45 @@ if (defined('CFG_SITE_HOST')) // points js to exec
|
||||
|
||||
if (!CLI)
|
||||
{
|
||||
if (!defined('CFG_SITE_HOST') || !defined('CFG_STATIC_HOST'))
|
||||
die('error: SITE_HOST or STATIC_HOST not configured');
|
||||
|
||||
// Setup Session
|
||||
if (CFG_SESSION_CACHE_DIR && Util::writeDir(CFG_SESSION_CACHE_DIR))
|
||||
session_save_path(getcwd().'/'.CFG_SESSION_CACHE_DIR);
|
||||
|
||||
session_set_cookie_params(15 * YEAR, '/', '', $secure, true);
|
||||
session_cache_limiter('private');
|
||||
if (!session_start())
|
||||
{
|
||||
trigger_error('failed to start session', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
|
||||
session_start();
|
||||
if (!empty($AoWoWconf['aowow']) && User::init())
|
||||
User::save(); // save user-variables in session
|
||||
|
||||
// set up some logging (~10 queries will execute before we init the user and load the config)
|
||||
if (CFG_DEBUG && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
|
||||
// todo: (low) - move to setup web-interface (when it begins its existance)
|
||||
if (!defined('CFG_SITE_HOST') || !defined('CFG_STATIC_HOST'))
|
||||
{
|
||||
DB::Aowow()->setLogger(['DB', 'logger']);
|
||||
DB::World()->setLogger(['DB', 'logger']);
|
||||
if (DB::isConnected(DB_AUTH))
|
||||
DB::Auth()->setLogger(['DB', 'logger']);
|
||||
$host = substr($_SERVER['SERVER_NAME'].strtr($_SERVER['SCRIPT_NAME'], ['index.php' => '']), 0, -1);
|
||||
|
||||
if (!empty($AoWoWconf['characters']))
|
||||
foreach ($AoWoWconf['characters'] as $idx => $__)
|
||||
if (DB::isConnected(DB_CHARACTERS . $idx))
|
||||
DB::Characters($idx)->setLogger(['DB', 'logger']);
|
||||
define('HOST_URL', ($secure ? 'https://' : 'http://').$host);
|
||||
define('STATIC_URL', ($secure ? 'https://' : 'http://').$host.'/static');
|
||||
|
||||
if (User::isInGroup(U_GROUP_ADMIN)) // initial set
|
||||
{
|
||||
DB::Aowow()->query('REPLACE INTO ?_config VALUES (?a)',
|
||||
[['site_host', $host, CON_FLAG_TYPE_STRING | CON_FLAG_PERSISTENT, 'default: '.$host.' - points js to executable files (automaticly set on first run)'],
|
||||
['static_host', $host.'/static', CON_FLAG_TYPE_STRING | CON_FLAG_PERSISTENT, 'default: '.$host.'/static - points js to images & scripts (automaticly set on first run)']]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// hard-override locale for this call (should this be here..?)
|
||||
// all strings attached..
|
||||
if (!empty($AoWoWconf['aowow']))
|
||||
{
|
||||
if (isset($_GET['locale']) && (int)$_GET['locale'] <= MAX_LOCALES && (int)$_GET['locale'] >= 0)
|
||||
if (CFG_LOCALES & (1 << $_GET['locale']))
|
||||
if (isset($_GET['locale']) && (CFG_LOCALES & (1 << (int)$_GET['locale'])))
|
||||
User::useLocale($_GET['locale']);
|
||||
|
||||
Lang::load(User::$localeString);
|
||||
}
|
||||
|
||||
// parse page-parameters .. sanitize before use!
|
||||
$str = explode('&', mb_strtolower($_SERVER['QUERY_STRING'] ?? ''), 2)[0];
|
||||
$str = explode('&', $_SERVER['QUERY_STRING'], 2)[0];
|
||||
$_ = explode('=', $str, 2);
|
||||
$pageCall = $_[0];
|
||||
$pageParam = $_[1] ?? '';
|
||||
$pageParam = isset($_[1]) ? $_[1] : null;
|
||||
|
||||
Util::$wowheadLink = 'http://'.Util::$subDomains[User::$localeId].'.wowhead.com/'.$str;
|
||||
}
|
||||
|
||||
@@ -159,8 +159,9 @@ class DbSimple_Connect
|
||||
*
|
||||
* @param string $query запрос
|
||||
*/
|
||||
public function addInit(...$args)
|
||||
public function addInit($query)
|
||||
{
|
||||
$args = func_get_args();
|
||||
if ($this->DbSimple !== null)
|
||||
return call_user_func_array(array(&$this->DbSimple, 'query'), $args);
|
||||
$this->init[] = $args;
|
||||
|
||||
@@ -144,8 +144,9 @@ abstract class DbSimple_Database extends DbSimple_LastError
|
||||
* mixed select(string $query [, $arg1] [,$arg2] ...)
|
||||
* Execute query and return the result.
|
||||
*/
|
||||
public function select(...$args)
|
||||
public function select($query)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$total = false;
|
||||
return $this->_query($args, $total);
|
||||
}
|
||||
@@ -156,8 +157,10 @@ abstract class DbSimple_Database extends DbSimple_LastError
|
||||
* Total number of found rows (independent to LIMIT) is returned in $total
|
||||
* (in most cases second query is performed to calculate $total).
|
||||
*/
|
||||
public function selectPage(&$total, ...$args)
|
||||
public function selectPage(&$total, $query)
|
||||
{
|
||||
$args = func_get_args();
|
||||
array_shift($args);
|
||||
$total = true;
|
||||
return $this->_query($args, $total);
|
||||
}
|
||||
@@ -170,8 +173,9 @@ abstract class DbSimple_Database extends DbSimple_LastError
|
||||
* because PHP DOES NOT generates notice on $row['abc'] if $row === null
|
||||
* or $row === false (but, if $row is empty array, notice is generated).
|
||||
*/
|
||||
public function selectRow(...$args)
|
||||
public function selectRow()
|
||||
{
|
||||
$args = func_get_args();
|
||||
$total = false;
|
||||
$rows = $this->_query($args, $total);
|
||||
if (!is_array($rows)) return $rows;
|
||||
@@ -184,8 +188,9 @@ abstract class DbSimple_Database extends DbSimple_LastError
|
||||
* array selectCol(string $query [, $arg1] [,$arg2] ...)
|
||||
* Return the first column of query result as array.
|
||||
*/
|
||||
public function selectCol(...$args)
|
||||
public function selectCol()
|
||||
{
|
||||
$args = func_get_args();
|
||||
$total = false;
|
||||
$rows = $this->_query($args, $total);
|
||||
if (!is_array($rows)) return $rows;
|
||||
@@ -198,8 +203,9 @@ abstract class DbSimple_Database extends DbSimple_LastError
|
||||
* Return the first cell of the first column of query result.
|
||||
* If no one row selected, return null.
|
||||
*/
|
||||
public function selectCell(...$args)
|
||||
public function selectCell()
|
||||
{
|
||||
$args = func_get_args();
|
||||
$total = false;
|
||||
$rows = $this->_query($args, $total);
|
||||
if (!is_array($rows)) return $rows;
|
||||
@@ -215,8 +221,9 @@ abstract class DbSimple_Database extends DbSimple_LastError
|
||||
* mixed query(string $query [, $arg1] [,$arg2] ...)
|
||||
* Alias for select(). May be used for INSERT or UPDATE queries.
|
||||
*/
|
||||
public function query(...$args)
|
||||
public function query()
|
||||
{
|
||||
$args = func_get_args();
|
||||
$total = false;
|
||||
return $this->_query($args, $total);
|
||||
}
|
||||
@@ -239,8 +246,9 @@ abstract class DbSimple_Database extends DbSimple_LastError
|
||||
* Нужно для сложных запросов, состоящих из кусков, которые полезно сохранить
|
||||
*
|
||||
*/
|
||||
public function subquery(...$args)
|
||||
public function subquery()
|
||||
{
|
||||
$args = func_get_args();
|
||||
$this->_expandPlaceholders($args,$this->_placeholderNativeArgs !== null);
|
||||
return new DbSimple_SubQuery($args);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class DbSimple_Mysqli extends DbSimple_Database
|
||||
* constructor(string $dsn)
|
||||
* Connect to MySQL server.
|
||||
*/
|
||||
function __construct($dsn)
|
||||
function DbSimple_Mysqli($dsn)
|
||||
{
|
||||
|
||||
if (!is_callable("mysqli_connect"))
|
||||
@@ -159,7 +159,6 @@ class DbSimple_Mysqli extends DbSimple_Database
|
||||
{
|
||||
$this->_lastQuery = $queryMain;
|
||||
$this->_expandPlaceholders($queryMain, false);
|
||||
mysqli_ping($this->link);
|
||||
$result = mysqli_query($this->link, $queryMain[0]);
|
||||
if ($result === false)
|
||||
return $this->_setDbError($queryMain[0]);
|
||||
@@ -179,7 +178,7 @@ class DbSimple_Mysqli extends DbSimple_Database
|
||||
protected function _performFetch($result)
|
||||
{
|
||||
$row = mysqli_fetch_assoc($result);
|
||||
if (mysqli_error($this->link)) return $this->_setDbError($this->_lastQuery);
|
||||
if (mysql_error()) return $this->_setDbError($this->_lastQuery);
|
||||
if ($row === false) return null;
|
||||
return $row;
|
||||
}
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
<?php
|
||||
|
||||
/****************************************
|
||||
Example of how to use this uploader class...
|
||||
You can uncomment the following lines (minus the require) to use these as your defaults.
|
||||
|
||||
// list of valid extensions, ex. array("jpeg", "xml", "bmp")
|
||||
$allowedExtensions = array();
|
||||
// max file size in bytes
|
||||
$sizeLimit = 10 * 1024 * 1024;
|
||||
|
||||
require('valums-file-uploader/server/php.php');
|
||||
$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);
|
||||
|
||||
// Call handleUpload() with the name of the folder, relative to PHP's getcwd()
|
||||
$result = $uploader->handleUpload('uploads/');
|
||||
|
||||
// to pass data through iframe you will need to encode all html tags
|
||||
echo htmlspecialchars(json_encode($result), ENT_NOQUOTES);
|
||||
|
||||
/******************************************/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Handle file uploads via XMLHttpRequest
|
||||
*/
|
||||
class qqUploadedFileXhr
|
||||
{
|
||||
/**
|
||||
* Save the file to the specified path
|
||||
* @return boolean TRUE on success
|
||||
*/
|
||||
function save(string $path) : bool
|
||||
{
|
||||
$input = fopen("php://input", "r");
|
||||
$temp = tmpfile();
|
||||
$realSize = stream_copy_to_stream($input, $temp);
|
||||
fclose($input);
|
||||
|
||||
if ($realSize != $this->getSize())
|
||||
return false;
|
||||
|
||||
$target = fopen($path, "w");
|
||||
fseek($temp, 0, SEEK_SET);
|
||||
stream_copy_to_stream($temp, $target);
|
||||
fclose($target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getName() : string
|
||||
{
|
||||
return $_GET['qqfile'];
|
||||
}
|
||||
|
||||
function getSize(): int
|
||||
{
|
||||
if (isset($_SERVER["CONTENT_LENGTH"]))
|
||||
return (int)$_SERVER["CONTENT_LENGTH"];
|
||||
|
||||
throw new Exception('Getting content length is not supported.');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle file uploads via regular form post (uses the $_FILES array)
|
||||
*/
|
||||
class qqUploadedFileForm
|
||||
{
|
||||
/**
|
||||
* Save the file to the specified path
|
||||
* @return boolean TRUE on success
|
||||
*/
|
||||
function save(string $path) : bool
|
||||
{
|
||||
if(!move_uploaded_file($_FILES['qqfile']['tmp_name'], $path))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getName() : string
|
||||
{
|
||||
return $_FILES['qqfile']['name'];
|
||||
}
|
||||
|
||||
function getSize() : int
|
||||
{
|
||||
return $_FILES['qqfile']['size'];
|
||||
}
|
||||
}
|
||||
|
||||
class qqFileUploader
|
||||
{
|
||||
private $allowedExtensions = array();
|
||||
private $sizeLimit = 10485760;
|
||||
private $file;
|
||||
|
||||
public function __construct(array $allowedExtensions = array(), $sizeLimit = 10485760)
|
||||
{
|
||||
$this->allowedExtensions = array_map("strtolower", $allowedExtensions);
|
||||
$this->sizeLimit = $sizeLimit;
|
||||
|
||||
$this->checkServerSettings();
|
||||
|
||||
if (isset($_GET['qqfile']))
|
||||
$this->file = new qqUploadedFileXhr();
|
||||
else if (isset($_FILES['qqfile']))
|
||||
$this->file = new qqUploadedFileForm();
|
||||
else
|
||||
$this->file = null;
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->file?->getName() ?? '';
|
||||
}
|
||||
|
||||
private function checkServerSettings() : void
|
||||
{
|
||||
$postSize = $this->toBytes(ini_get('post_max_size'));
|
||||
$uploadSize = $this->toBytes(ini_get('upload_max_filesize'));
|
||||
|
||||
if ($postSize < $this->sizeLimit || $uploadSize < $this->sizeLimit)
|
||||
{
|
||||
$size = max(1, $this->sizeLimit / 1024 / 1024) . 'M';
|
||||
die("{'error':'increase post_max_size and upload_max_filesize to $size'}");
|
||||
}
|
||||
}
|
||||
|
||||
private function toBytes(string $str) : int
|
||||
{
|
||||
$val = trim($str);
|
||||
$last = strtolower(substr($str, -1, 1));
|
||||
switch ($last)
|
||||
{
|
||||
case 'g': $val *= 1024;
|
||||
case 'm': $val *= 1024;
|
||||
case 'k': $val *= 1024;
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array('success' => true, 'newFilename' => 'myDoc123.doc') or array('error' => 'error message')
|
||||
*/
|
||||
function handleUpload(string $uploadDirectory, string $newName = '', bool $replaceOldFile = FALSE) : array
|
||||
{
|
||||
if (!is_writable($uploadDirectory))
|
||||
return ['error' => "Server error. Upload directory isn't writable."];
|
||||
|
||||
if (!$this->file)
|
||||
return ['error' => 'No files were uploaded.'];
|
||||
|
||||
$size = $this->file->getSize();
|
||||
|
||||
if ($size == 0)
|
||||
return ['error' => 'File is empty'];
|
||||
|
||||
if ($size > $this->sizeLimit)
|
||||
return ['error' => 'File is too large'];
|
||||
|
||||
$pathinfo = pathinfo($this->getName());
|
||||
$filename = $newName ?: $pathinfo['filename'];
|
||||
//$filename = md5(uniqid());
|
||||
$ext = @$pathinfo['extension']; // hide notices if extension is empty
|
||||
|
||||
if ($this->allowedExtensions && !in_array(strtolower($ext), $this->allowedExtensions))
|
||||
{
|
||||
$these = implode(', ', $this->allowedExtensions);
|
||||
return ['error' => 'File has an invalid extension, it should be one of '. $these . '.'];
|
||||
}
|
||||
|
||||
// don't overwrite previous files that were uploaded
|
||||
if (!$replaceOldFile)
|
||||
while (file_exists($uploadDirectory . $filename . '.' . $ext))
|
||||
$filename .= rand(10, 99);
|
||||
|
||||
if ($this->file->save($uploadDirectory . $filename . '.' . $ext))
|
||||
return ['success' => true, 'newFilename' => $filename . '.' . $ext];
|
||||
else
|
||||
return ['error' => 'Could not save uploaded file. The upload was cancelled, or server error encountered'];
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
die('invalid access');
|
||||
|
||||
|
||||
/* from TC wiki
|
||||
@@ -25,7 +25,6 @@ class Loot
|
||||
|
||||
private $entry = 0; // depending on the lookup itemId oder templateId
|
||||
private $results = [];
|
||||
private $chanceMods = [];
|
||||
private $lootTemplates = array(
|
||||
LOOT_REFERENCE, // internal
|
||||
LOOT_ITEM, // item
|
||||
@@ -41,33 +40,33 @@ class Loot
|
||||
LOOT_SPELL // spell
|
||||
);
|
||||
|
||||
public function &iterate() : iterable
|
||||
public function &iterate()
|
||||
{
|
||||
reset($this->results);
|
||||
|
||||
foreach ($this->results as $k => $__)
|
||||
while (list($k, $__) = each($this->results))
|
||||
yield $k => $this->results[$k];
|
||||
}
|
||||
|
||||
public function getResult() : array
|
||||
public function getResult()
|
||||
{
|
||||
return $this->results;
|
||||
}
|
||||
|
||||
private function createStack(array $l) : string // issue: TC always has an equal distribution between min/max
|
||||
private function createStack($l) // issue: TC always has an equal distribution between min/max
|
||||
{
|
||||
if (empty($l['min']) || empty($l['max']) || $l['max'] <= $l['min'])
|
||||
return '';
|
||||
return null;
|
||||
|
||||
$stack = [];
|
||||
for ($i = $l['min']; $i <= $l['max']; $i++)
|
||||
$stack[$i] = round(100 / (1 + $l['max'] - $l['min']), 3);
|
||||
|
||||
// yes, it wants a string .. how weired is that..
|
||||
return json_encode($stack, JSON_NUMERIC_CHECK); // do not replace with Util::toJSON !
|
||||
return json_encode($stack, JSON_NUMERIC_CHECK);
|
||||
}
|
||||
|
||||
private function storeJSGlobals(array $data) : void
|
||||
private function storeJSGlobals($data)
|
||||
{
|
||||
foreach ($data as $type => $jsData)
|
||||
{
|
||||
@@ -82,62 +81,7 @@ class Loot
|
||||
}
|
||||
}
|
||||
|
||||
private function calcChance(array $refs, array $parents = []) : array
|
||||
{
|
||||
$retData = [];
|
||||
$retKeys = [];
|
||||
|
||||
foreach ($refs as $rId => $ref)
|
||||
{
|
||||
// check for possible database inconsistencies
|
||||
if (!$ref['chance'] && !$ref['isGrouped'])
|
||||
trigger_error('Loot by Item: Ungrouped Item/Ref '.$ref['item'].' has 0% chance assigned!', E_USER_WARNING);
|
||||
|
||||
if ($ref['isGrouped'] && $ref['sumChance'] > 100)
|
||||
trigger_error('Loot by Item: Group with Item/Ref '.$ref['item'].' has '.number_format($ref['sumChance'], 2).'% total chance! Some items cannot drop!', E_USER_WARNING);
|
||||
|
||||
if ($ref['isGrouped'] && $ref['sumChance'] >= 100 && !$ref['chance'])
|
||||
trigger_error('Loot by Item: Item/Ref '.$ref['item'].' with adaptive chance cannot drop. Group already at 100%!', E_USER_WARNING);
|
||||
|
||||
$chance = abs($ref['chance'] ?: (100 - $ref['sumChance']) / $ref['nZeroItems']) / 100;
|
||||
|
||||
// apply inherited chanceMods
|
||||
if (isset($this->chanceMods[$ref['item']]))
|
||||
{
|
||||
$chance *= $this->chanceMods[$ref['item']][0];
|
||||
$chance = 1 - pow(1 - $chance, $this->chanceMods[$ref['item']][1]);
|
||||
}
|
||||
|
||||
// save chance for parent-ref
|
||||
$this->chanceMods[$rId] = [$chance, $ref['multiplier']];
|
||||
|
||||
// refTemplate doesn't point to a new ref -> we are done
|
||||
if (!in_array($rId, $parents))
|
||||
{
|
||||
$data = array(
|
||||
'percent' => $chance,
|
||||
'stack' => [$ref['min'], $ref['max']],
|
||||
'count' => 1 // ..and one for the sort script
|
||||
);
|
||||
|
||||
if ($_ = self::createStack($ref))
|
||||
$data['pctstack'] = $_;
|
||||
|
||||
// sort highest chances first
|
||||
$i = 0;
|
||||
for (; $i < count($retData); $i++)
|
||||
if ($retData[$i]['percent'] < $data['percent'])
|
||||
break;
|
||||
|
||||
array_splice($retData, $i, 0, [$data]);
|
||||
array_splice($retKeys, $i, 0, [$rId]);
|
||||
}
|
||||
}
|
||||
|
||||
return array_combine($retKeys, $retData);
|
||||
}
|
||||
|
||||
private function getByContainerRecursive(string $tableName, int $lootId, array &$handledRefs, int $groupId = 0, float $baseChance = 1.0) : ?array
|
||||
private function getByContainerRecursive($tableName, $lootId, &$handledRefs, $groupId = 0, $baseChance = 1.0)
|
||||
{
|
||||
$loot = [];
|
||||
$rawItems = [];
|
||||
@@ -157,8 +101,7 @@ class Loot
|
||||
'quest' => $entry['QuestRequired'],
|
||||
'group' => $entry['GroupId'],
|
||||
'parentRef' => $tableName == LOOT_REFERENCE ? $lootId : 0,
|
||||
'realChanceMod' => $baseChance,
|
||||
'groupChance' => 0
|
||||
'realChanceMod' => $baseChance
|
||||
);
|
||||
|
||||
// if ($entry['LootMode'] > 1)
|
||||
@@ -191,7 +134,7 @@ class Loot
|
||||
// bandaid.. remove when propperly handling lootmodes
|
||||
if (!in_array($entry['Reference'], $handledRefs))
|
||||
{ // todo (high): find out, why i used this in the first place. (don't do drugs, kids)
|
||||
[$data, $raw] = self::getByContainerRecursive(LOOT_REFERENCE, $entry['Reference'], $handledRefs, /*$entry['GroupId'],*/ 0, $entry['Chance'] / 100);
|
||||
list($data, $raw) = self::getByContainerRecursive(LOOT_REFERENCE, $entry['Reference'], $handledRefs, /*$entry['GroupId'],*/ 0, $entry['Chance'] / 100);
|
||||
|
||||
$handledRefs[] = $entry['Reference'];
|
||||
|
||||
@@ -223,20 +166,16 @@ class Loot
|
||||
$set['groupChance'] = &$groupChances[$entry['GroupId']];
|
||||
}
|
||||
else if ($entry['GroupId'] && $entry['Chance'])
|
||||
{
|
||||
$set['groupChance'] = $entry['Chance'];
|
||||
|
||||
if (!$entry['Reference'])
|
||||
{
|
||||
if (empty($groupChances[$entry['GroupId']]))
|
||||
$groupChances[$entry['GroupId']] = 0;
|
||||
|
||||
$groupChances[$entry['GroupId']] += $entry['Chance'];
|
||||
}
|
||||
$set['groupChance'] = $entry['Chance'];
|
||||
}
|
||||
else // shouldn't have happened
|
||||
{
|
||||
trigger_error('Unhandled case in calculating chance for item '.$entry['Item'].'!', E_USER_WARNING);
|
||||
Util::addNote(U_GROUP_EMPLOYEE, 'Loot::getByContainerRecursive: unhandled case in calculating chance for item '.$entry['Item'].'!');
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -250,22 +189,24 @@ class Loot
|
||||
$sum = 0;
|
||||
else if ($sum >= 100.01)
|
||||
{
|
||||
trigger_error('Loot entry '.$lootId.' / group '.$k.' has a total chance of '.number_format($sum, 2).'%. Some items cannot drop!', E_USER_WARNING);
|
||||
Util::addNote(U_GROUP_EMPLOYEE, 'Loot::getByContainerRecursive: entry '.$lootId.' / group '.$k.' has a total chance of '.number_format($sum, 2).'%. Some items cannot drop!');
|
||||
$sum = 100;
|
||||
}
|
||||
// is applied as backReference to items with 0-chance
|
||||
$groupChances[$k] = (100 - $sum) / ($nGroupEquals[$k] ?: 1);
|
||||
|
||||
$cnt = empty($nGroupEquals[$k]) ? 1 : $nGroupEquals[$k];
|
||||
|
||||
$groupChances[$k] = (100 - $sum) / $cnt; // is applied as backReference to items with 0-chance
|
||||
}
|
||||
|
||||
return [$loot, array_unique($rawItems)];
|
||||
}
|
||||
|
||||
public function getByContainer(string $table, int $entry): bool
|
||||
public function getByContainer($table, $entry)
|
||||
{
|
||||
$this->entry = intVal($entry);
|
||||
|
||||
if (!in_array($table, $this->lootTemplates) || !$this->entry)
|
||||
return false;
|
||||
return null;
|
||||
|
||||
/*
|
||||
todo (high): implement conditions on loot (and conditions in general)
|
||||
@@ -328,7 +269,7 @@ class Loot
|
||||
);
|
||||
$this->results[] = array_merge($base, $data);
|
||||
|
||||
$this->jsGlobals[Type::ITEM][$loot['reference']] = $data;
|
||||
$this->jsGlobals[TYPE_ITEM][$loot['reference']] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,16 +312,16 @@ class Loot
|
||||
break;
|
||||
}
|
||||
|
||||
$this->extraCols[] = "\$Listview.funcBox.createSimpleCol('group', 'Group', '7%', 'group')";
|
||||
$this->extraCols[] = "Listview.funcBox.createSimpleCol('group', 'Group', '7%', 'group')";
|
||||
foreach ($fields as $idx => $field)
|
||||
if ($set & (1 << $idx))
|
||||
$this->extraCols[] = "\$Listview.funcBox.createSimpleCol('".$field."', '".Util::ucFirst($field)."', '7%', '".$field."')";
|
||||
$this->extraCols[] = "Listview.funcBox.createSimpleCol('".$field."', '".Util::ucFirst($field)."', '7%', '".$field."')";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getByItem(int $entry, int $maxResults = CFG_SQL_LIMIT_DEFAULT, array $lootTableList = []) : bool
|
||||
public function getByItem($entry, $maxResults = CFG_SQL_LIMIT_DEFAULT, $lootTableList = [])
|
||||
{
|
||||
$this->entry = intVal($entry);
|
||||
|
||||
@@ -409,12 +350,13 @@ class Loot
|
||||
['achievement', [], '$LANG.tab_rewardfrom', 'reward-from-achievement', [], [], []]
|
||||
);
|
||||
$refResults = [];
|
||||
$chanceMods = [];
|
||||
$query = 'SELECT
|
||||
lt1.entry AS ARRAY_KEY,
|
||||
IF(lt1.reference = 0, lt1.item, lt1.reference) AS item,
|
||||
lt1.chance,
|
||||
SUM(IF(lt2.chance = 0, 1, 0)) AS nZeroItems,
|
||||
SUM(IF(lt2.reference = 0, lt2.chance, 0)) AS sumChance,
|
||||
SUM(lt2.chance) AS sumChance,
|
||||
IF(lt1.groupid > 0, 1, 0) AS isGrouped,
|
||||
IF(lt1.reference = 0, lt1.mincount, 1) AS min,
|
||||
IF(lt1.reference = 0, lt1.maxcount, 1) AS max,
|
||||
@@ -427,6 +369,61 @@ class Loot
|
||||
%s
|
||||
GROUP BY lt2.entry, lt2.groupid';
|
||||
|
||||
$calcChance = function ($refs, $parents = []) use (&$chanceMods)
|
||||
{
|
||||
$retData = [];
|
||||
$retKeys = [];
|
||||
|
||||
foreach ($refs as $rId => $ref)
|
||||
{
|
||||
// check for possible database inconsistencies
|
||||
if (!$ref['chance'] && !$ref['isGrouped'])
|
||||
Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: ungrouped Item/Ref '.$ref['item'].' has 0% chance assigned!');
|
||||
|
||||
if ($ref['isGrouped'] && $ref['sumChance'] > 100)
|
||||
Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: group with Item/Ref '.$ref['item'].' has '.number_format($ref['sumChance'], 2).'% total chance! Some items cannot drop!');
|
||||
|
||||
if ($ref['isGrouped'] && $ref['sumChance'] >= 100 && !$ref['chance'])
|
||||
Util::addNote(U_GROUP_EMPLOYEE, 'Loot by Item: Item/Ref '.$ref['item'].' with adaptive chance cannot drop. Group already at 100%!');
|
||||
|
||||
$chance = abs($ref['chance'] ?: (100 - $ref['sumChance']) / $ref['nZeroItems']) / 100;
|
||||
|
||||
// apply inherited chanceMods
|
||||
if (isset($chanceMods[$ref['item']]))
|
||||
{
|
||||
$chance *= $chanceMods[$ref['item']][0];
|
||||
$chance = 1 - pow(1 - $chance, $chanceMods[$ref['item']][1]);
|
||||
}
|
||||
|
||||
// save chance for parent-ref
|
||||
$chanceMods[$rId] = [$chance, $ref['multiplier']];
|
||||
|
||||
// refTemplate doesn't point to a new ref -> we are done
|
||||
if (!in_array($rId, $parents))
|
||||
{
|
||||
$data = array(
|
||||
'percent' => $chance,
|
||||
'stack' => [$ref['min'], $ref['max']],
|
||||
'count' => 1 // ..and one for the sort script
|
||||
);
|
||||
|
||||
if ($_ = self::createStack($ref))
|
||||
$data['pctstack'] = $_;
|
||||
|
||||
// sort highest chances first
|
||||
$i = 0;
|
||||
for (; $i < count($retData); $i++)
|
||||
if ($retData[$i]['percent'] < $data['percent'])
|
||||
break;
|
||||
|
||||
array_splice($retData, $i, 0, [$data]);
|
||||
array_splice($retKeys, $i, 0, [$rId]);
|
||||
}
|
||||
}
|
||||
|
||||
return array_combine($retKeys, $retData);
|
||||
};
|
||||
|
||||
/*
|
||||
get references containing the item
|
||||
*/
|
||||
@@ -445,7 +442,7 @@ class Loot
|
||||
array_keys($curRefs)
|
||||
);
|
||||
|
||||
$refResults += $this->calcChance($curRefs, array_column($newRefs, 'item'));
|
||||
$refResults += $calcChance($curRefs, array_column($newRefs, 'item'));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -456,7 +453,7 @@ class Loot
|
||||
if ($lootTableList && !in_array($this->lootTemplates[$i], $lootTableList))
|
||||
continue;
|
||||
|
||||
$result = $this->calcChance(DB::World()->select(
|
||||
$result = $calcChance(DB::World()->select(
|
||||
sprintf($query, '{lt1.reference IN (?a) OR }(lt1.reference = 0 AND lt1.item = ?d)'),
|
||||
$this->lootTemplates[$i], $this->lootTemplates[$i],
|
||||
$refResults ? array_keys($refResults) : DBSIMPLE_SKIP,
|
||||
@@ -497,7 +494,7 @@ class Loot
|
||||
|
||||
$srcData = $srcObj->getListviewData();
|
||||
|
||||
foreach ($srcObj->iterate() as $curTpl)
|
||||
foreach ($srcObj->iterate() as $__id => $curTpl)
|
||||
{
|
||||
switch ($curTpl['typeCat'])
|
||||
{
|
||||
@@ -508,7 +505,7 @@ class Loot
|
||||
}
|
||||
|
||||
$tabsFinal[$tabId][1][] = array_merge($srcData[$srcObj->id], $result[$srcObj->getField('lootId')]);
|
||||
$tabsFinal[$tabId][4][] = '$Listview.extraCols.percent';
|
||||
$tabsFinal[$tabId][4][] = 'Listview.extraCols.percent';
|
||||
if ($tabId != 15)
|
||||
$tabsFinal[$tabId][6][] = 'skill';
|
||||
}
|
||||
@@ -533,7 +530,7 @@ class Loot
|
||||
|
||||
// achievement part
|
||||
$conditions = array(['itemExtra', $this->entry]);
|
||||
if ($ar = DB::World()->selectCol('SELECT ID FROM achievement_reward WHERE ItemID = ?d{ OR MailTemplateID IN (?a)}', $this->entry, $ids ?: DBSIMPLE_SKIP))
|
||||
if ($ar = DB::World()->selectCol('SELECT entry FROM achievement_reward WHERE item = ?d{ OR mailTemplate IN (?a)}', $this->entry, $ids ?: DBSIMPLE_SKIP))
|
||||
array_push($conditions, ['id', $ar], 'OR');
|
||||
|
||||
$srcObj = new AchievementList($conditions);
|
||||
@@ -566,7 +563,7 @@ class Loot
|
||||
$srcData = $srcObj->getListviewData();
|
||||
|
||||
if (!empty($result))
|
||||
$tabsFinal[16][4][] = '$Listview.extraCols.percent';
|
||||
$tabsFinal[16][4][] = 'Listview.extraCols.percent';
|
||||
|
||||
if ($srcObj->hasSetFields(['reagent1']))
|
||||
$tabsFinal[16][6][] = 'reagents';
|
||||
@@ -604,32 +601,14 @@ class Loot
|
||||
$tabId = abs($tabId); // general case (skinning)
|
||||
|
||||
$tabsFinal[$tabId][1][] = array_merge($srcData[$srcObj->id], $result[$srcObj->getField($field)]);
|
||||
$tabsFinal[$tabId][4][] = '$Listview.extraCols.percent';
|
||||
$tabsFinal[$tabId][4][] = 'Listview.extraCols.percent';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($tabsFinal as $tabId => $data)
|
||||
{
|
||||
$tabData = array(
|
||||
'data' => $data[1],
|
||||
'name' => $data[2],
|
||||
'id' => $data[3]
|
||||
);
|
||||
|
||||
if ($data[4])
|
||||
$tabData['extraCols'] = array_unique($data[4]);
|
||||
|
||||
if ($data[5])
|
||||
$tabData['hiddenCols'] = array_unique($data[5]);
|
||||
|
||||
if ($data[6])
|
||||
$tabData['visibleCols'] = array_unique($data[6]);
|
||||
|
||||
$this->results[$tabId] = [$data[0], $tabData];
|
||||
}
|
||||
$this->results = $tabsFinal;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
die('invalid access');
|
||||
|
||||
/*
|
||||
this is just a skeleton for now
|
||||
@@ -14,8 +14,6 @@ class Markup
|
||||
private $text = '';
|
||||
private $jsGlobals = [];
|
||||
|
||||
private static $dbTagPattern = '/(?<!\\\\)\[(npc|object|item|itemset|quest|spell|zone|faction|pet|achievement|statistic|title|event|class|race|skill|currency|emote|enchantment|money|sound|icondb)=(-?\d+)[^\]]*\]/i';
|
||||
|
||||
public function __construct($text)
|
||||
{
|
||||
$this->text = $text;
|
||||
@@ -23,38 +21,14 @@ class Markup
|
||||
|
||||
public function parseGlobalsFromText(&$jsg = [])
|
||||
{
|
||||
if (preg_match_all(self::$dbTagPattern, $this->text, $matches, PREG_SET_ORDER))
|
||||
if (preg_match_all('/(?<!\\\\)\[(npc|object|item|itemset|quest|spell|zone|faction|pet|achievement|statistic|title|event|class|race|skill|currency)=(\d+)[^\]]*\]/i', $this->text, $matches, PREG_SET_ORDER))
|
||||
{
|
||||
foreach ($matches as $match)
|
||||
{
|
||||
if ($match[1] == 'statistic')
|
||||
$match[1] = 'achievement';
|
||||
else if ($match[1] == 'icondb')
|
||||
$match[1] = 'icon';
|
||||
|
||||
if ($match[1] == 'money')
|
||||
{
|
||||
if (stripos($match[0], 'items'))
|
||||
{
|
||||
if (preg_match('/items=([0-9,]+)/i', $match[0], $submatch))
|
||||
{
|
||||
$sm = explode(',', $submatch[1]);
|
||||
for ($i = 0; $i < count($sm); $i+=2)
|
||||
$this->jsGlobals[Type::ITEM][$sm[$i]] = $sm[$i];
|
||||
}
|
||||
}
|
||||
|
||||
if (stripos($match[0], 'currency'))
|
||||
{
|
||||
if (preg_match('/currency=([0-9,]+)/i', $match[0], $submatch))
|
||||
{
|
||||
$sm = explode(',', $submatch[1]);
|
||||
for ($i = 0; $i < count($sm); $i+=2)
|
||||
$this->jsGlobals[Type::CURRENCY][$sm[$i]] = $sm[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($type = Type::getIndexFrom(Type::IDX_FILE_STR, $match[1]))
|
||||
if ($type = array_search($match[1], Util::$typeStrings))
|
||||
$this->jsGlobals[$type][$match[2]] = $match[2];
|
||||
}
|
||||
}
|
||||
@@ -64,78 +38,6 @@ class Markup
|
||||
return $this->jsGlobals;
|
||||
}
|
||||
|
||||
public function stripTags($globals = [])
|
||||
{
|
||||
// since this is an article the db-tags should already be parsed
|
||||
$text = preg_replace_callback(self::$dbTagPattern, function ($match) use ($globals) {
|
||||
if ($match[1] == 'statistic')
|
||||
$match[1] = 'achievement';
|
||||
else if ($match[1] == 'icondb')
|
||||
$match[1] = 'icon';
|
||||
else if ($match[1] == 'money')
|
||||
{
|
||||
$moneys = [];
|
||||
if (stripos($match[0], 'items'))
|
||||
{
|
||||
if (preg_match('/items=([0-9,]+)/i', $match[0], $submatch))
|
||||
{
|
||||
$sm = explode(',', $submatch[1]);
|
||||
for ($i = 0; $i < count($sm); $i += 2)
|
||||
{
|
||||
if (!empty($globals[Type::ITEM][1][$sm[$i]]))
|
||||
$moneys[] = $globals[Type::ITEM][1][$sm[$i]]['name'];
|
||||
else
|
||||
$moneys[] = Util::ucFirst(Lang::game('item')).' #'.$sm[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stripos($match[0], 'currency'))
|
||||
{
|
||||
if (preg_match('/currency=([0-9,]+)/i', $match[0], $submatch))
|
||||
{
|
||||
$sm = explode(',', $submatch[1]);
|
||||
for ($i = 0; $i < count($sm); $i += 2)
|
||||
{
|
||||
if (!empty($globals[Type::CURRENCY][1][$sm[$i]]))
|
||||
$moneys[] = $globals[Type::CURRENCY][1][$sm[$i]]['name'];
|
||||
else
|
||||
$moneys[] = Util::ucFirst(Lang::game('curency')).' #'.$sm[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Lang::concat($moneys);
|
||||
}
|
||||
if ($type = Type::getIndexFrom(Type::IDX_FILE_STR, $match[1]))
|
||||
{
|
||||
if (!empty($globals[$type][1][$match[2]]))
|
||||
return $globals[$type][1][$match[2]]['name'];
|
||||
else
|
||||
return Util::ucFirst(Lang::game($match[1])).' #'.$match[2];
|
||||
}
|
||||
|
||||
trigger_error('Markup::stripTags() - encountered unhandled db-tag: '.var_export($match));
|
||||
return '';
|
||||
}, $this->text);
|
||||
|
||||
$text = str_replace('[br]', "\n", $text);
|
||||
$stripped = '';
|
||||
|
||||
$inTag = false;
|
||||
for ($i = 0; $i < strlen($text); $i++)
|
||||
{
|
||||
if ($text[$i] == '[')
|
||||
$inTag = true;
|
||||
if (!$inTag)
|
||||
$stripped .= $text[$i];
|
||||
if ($text[$i] == ']')
|
||||
$inTag = false;
|
||||
}
|
||||
|
||||
return $stripped;
|
||||
}
|
||||
|
||||
public function fromHtml()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,921 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class Profiler
|
||||
{
|
||||
const PID_FILE = 'config/pr-queue-pid';
|
||||
const CHAR_GMFLAGS = 0x1 | 0x8 | 0x10 | 0x20; // PLAYER_EXTRA_ :: GM_ON | TAXICHEAT | GM_INVISIBLE | GM_CHAT
|
||||
|
||||
private static $realms = [];
|
||||
|
||||
public static $slot2InvType = array(
|
||||
1 => [INVTYPE_HEAD], // head
|
||||
2 => [INVTYPE_NECK], // neck
|
||||
3 => [INVTYPE_SHOULDERS], // shoulder
|
||||
4 => [INVTYPE_BODY], // shirt
|
||||
5 => [INVTYPE_CHEST, INVTYPE_ROBE], // chest
|
||||
6 => [INVTYPE_WAIST], // waist
|
||||
7 => [INVTYPE_LEGS], // legs
|
||||
8 => [INVTYPE_FEET], // feet
|
||||
9 => [INVTYPE_WRISTS], // wrists
|
||||
10 => [INVTYPE_HANDS], // hands
|
||||
11 => [INVTYPE_FINGER], // finger1
|
||||
12 => [INVTYPE_FINGER], // finger2
|
||||
13 => [INVTYPE_TRINKET], // trinket1
|
||||
14 => [INVTYPE_TRINKET], // trinket2
|
||||
15 => [INVTYPE_CLOAK], // chest
|
||||
16 => [INVTYPE_WEAPONMAINHAND, INVTYPE_WEAPON, INVTYPE_2HWEAPON], // mainhand
|
||||
17 => [INVTYPE_WEAPONOFFHAND, INVTYPE_WEAPON, INVTYPE_HOLDABLE, INVTYPE_SHIELD], // offhand
|
||||
18 => [INVTYPE_RANGED, INVTYPE_THROWN, INVTYPE_RELIC], // ranged + relic
|
||||
19 => [INVTYPE_TABARD], // tabard
|
||||
);
|
||||
|
||||
public static $raidProgression = array( // statisticAchievement => relevantCriterium ; don't forget to enable this in /js/Profiler.js as well
|
||||
1361 => 5100, 1362 => 5101, 1363 => 5102, 1365 => 5104, 1366 => 5108, 1364 => 5110, 1369 => 5112, 1370 => 5113, 1371 => 5114, 1372 => 5117, 1373 => 5119, 1374 => 5120, 1375 => 7805, 1376 => 5122, 1377 => 5123, // Naxxramas 10
|
||||
1367 => 5103, 1368 => 5111, 1378 => 5124, 1379 => 5125, 1380 => 5126, 1381 => 5127, 1382 => 5128, 1383 => 7806, 1384 => 5130, 1385 => 5131, 1386 => 5132, 1387 => 5133, 1388 => 5134, 1389 => 5135, 1390 => 5136, // Naxxramas 25
|
||||
2856 => 9938, 2857 => 9939, 2858 => 9940, 2859 => 9941, 2861 => 9943, 2865 => 9947, 2866 => 9948, 2868 => 9950, 2869 => 9951, 2870 => 9952, 2863 => 10558, 2864 => 10559, 2862 => 10560, 2867 => 10565, 2860 => 10580, // Ulduar 10
|
||||
2872 => 9954, 2873 => 9955, 2874 => 9956, 2884 => 9957, 2875 => 9959, 2879 => 9963, 2880 => 9964, 2882 => 9966, 2883 => 9967, 3236 => 10542, 3257 => 10561, 3256 => 10562, 3258 => 10563, 2881 => 10566, 2885 => 10581, // Ulduar 25
|
||||
1098 => 3271, // Onyxia's Lair 10
|
||||
1756 => 13345, // Onyxia's Lair 25
|
||||
4031 => 12230, 4034 => 12234, 4038 => 12238, 4042 => 12242, 4046 => 12246, // Trial of the Crusader 25 nh
|
||||
4029 => 12231, 4035 => 12235, 4039 => 12239, 4043 => 12243, 4047 => 12247, // Trial of the Crusader 25 hc
|
||||
4030 => 12229, 4033 => 12233, 4037 => 12237, 4041 => 12241, 4045 => 12245, // Trial of the Crusader 10 hc
|
||||
4028 => 12228, 4032 => 12232, 4036 => 12236, 4040 => 12240, 4044 => 12244, // Trial of the Crusader 10 nh
|
||||
4642 => 13091, 4656 => 13106, 4661 => 13111, 4664 => 13114, 4667 => 13117, 4670 => 13120, 4673 => 13123, 4676 => 13126, 4679 => 13129, 4682 => 13132, 4685 => 13135, 4688 => 13138, // Icecrown Citadel 25 hc
|
||||
4641 => 13092, 4655 => 13105, 4660 => 13109, 4663 => 13112, 4666 => 13115, 4669 => 13118, 4672 => 13121, 4675 => 13124, 4678 => 13127, 4681 => 13130, 4683 => 13133, 4687 => 13136, // Icecrown Citadel 25 nh
|
||||
4640 => 13090, 4654 => 13104, 4659 => 13110, 4662 => 13113, 4665 => 13116, 4668 => 13119, 4671 => 13122, 4674 => 13125, 4677 => 13128, 4680 => 13131, 4684 => 13134, 4686 => 13137, // Icecrown Citadel 10 hc
|
||||
4639 => 13089, 4643 => 13093, 4644 => 13094, 4645 => 13095, 4646 => 13096, 4647 => 13097, 4648 => 13098, 4649 => 13099, 4650 => 13100, 4651 => 13101, 4652 => 13102, 4653 => 13103, // Icecrown Citadel 10 nh
|
||||
4823 => 13467, // Ruby Sanctum 25 hc
|
||||
4820 => 13465, // Ruby Sanctum 25 nh
|
||||
4822 => 13468, // Ruby Sanctum 10 hc
|
||||
4821 => 13466, // Ruby Sanctum 10 nh
|
||||
);
|
||||
|
||||
public static function getBuyoutForItem($itemId)
|
||||
{
|
||||
if (!$itemId)
|
||||
return 0;
|
||||
|
||||
// try, when having filled char-DB at hand
|
||||
// return DB::Characters()->selectCell('SELECT SUM(a.buyoutprice) / SUM(ii.count) FROM auctionhouse a JOIN item_instance ii ON ii.guid = a.itemguid WHERE ii.itemEntry = ?d', $itemId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function queueStart(&$msg = '')
|
||||
{
|
||||
$queuePID = self::queueStatus();
|
||||
|
||||
if ($queuePID)
|
||||
{
|
||||
$msg = 'queue already running';
|
||||
return true;
|
||||
}
|
||||
|
||||
if (OS_WIN) // here be gremlins! .. suggested was "start /B php prQueue" as background process. but that closes itself
|
||||
pclose(popen('start php prQueue --log=cache/profiling.log', 'r'));
|
||||
else
|
||||
exec('php prQueue --log=cache/profiling.log > /dev/null 2>/dev/null &');
|
||||
|
||||
usleep(500000);
|
||||
if (self::queueStatus())
|
||||
return true;
|
||||
else
|
||||
{
|
||||
$msg = 'failed to start queue';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function queueStatus()
|
||||
{
|
||||
if (!file_exists(self::PID_FILE))
|
||||
return 0;
|
||||
|
||||
$pid = file_get_contents(self::PID_FILE);
|
||||
$cmd = OS_WIN ? 'tasklist /NH /FO CSV /FI "PID eq %d"' : 'ps --no-headers p %d';
|
||||
|
||||
exec(sprintf($cmd, $pid), $out);
|
||||
if ($out && stripos($out[0], $pid) !== false)
|
||||
return $pid;
|
||||
|
||||
// have pidFile but no process with this pid
|
||||
self::queueFree();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static function queueLock($pid)
|
||||
{
|
||||
$queuePID = self::queueStatus();
|
||||
if ($queuePID && $queuePID != $pid)
|
||||
{
|
||||
trigger_error('pSync - another queue with PID #'.$queuePID.' is already running', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// no queue running; create or overwrite pidFile
|
||||
$ok = false;
|
||||
if ($fh = fopen(self::PID_FILE, 'w'))
|
||||
{
|
||||
if (fwrite($fh, $pid))
|
||||
$ok = true;
|
||||
|
||||
fclose($fh);
|
||||
}
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
public static function queueFree()
|
||||
{
|
||||
unlink(self::PID_FILE);
|
||||
}
|
||||
|
||||
public static function urlize($str, $allowLocales = false, $profile = false)
|
||||
{
|
||||
$search = ['<', '>', ' / ', "'"];
|
||||
$replace = ['<', '>', '-', '' ];
|
||||
$str = str_replace($search, $replace, $str);
|
||||
|
||||
if ($profile)
|
||||
{
|
||||
$str = str_replace(['(', ')'], ['', ''], $str);
|
||||
$accents = array(
|
||||
"ß" => "ss",
|
||||
"á" => "a", "ä" => "a", "à" => "a", "â" => "a",
|
||||
"è" => "e", "ê" => "e", "é" => "e", "ë" => "e",
|
||||
"í" => "i", "î" => "i", "ì" => "i", "ï" => "i",
|
||||
"ñ" => "n",
|
||||
"ò" => "o", "ó" => "o", "ö" => "o", "ô" => "o",
|
||||
"ú" => "u", "ü" => "u", "û" => "u", "ù" => "u",
|
||||
"œ" => "oe",
|
||||
"Á" => "A", "Ä" => "A", "À" => "A", "Â" => "A",
|
||||
"È" => "E", "Ê" => "E", "É" => "E", "Ë" => "E",
|
||||
"Í" => "I", "Î" => "I", "Ì" => "I", "Ï" => "I",
|
||||
"Ñ" => "N",
|
||||
"Ò" => "O", "Ó" => "O", "Ö" => "O", "Ô" => "O",
|
||||
"Ú" => "U", "Ü" => "U", "Û" => "U", "Ù" => "U",
|
||||
"Œ" => "Oe"
|
||||
);
|
||||
$str = strtr($str, $accents);
|
||||
}
|
||||
|
||||
$str = trim($str);
|
||||
|
||||
if ($allowLocales)
|
||||
$str = str_replace(' ', '-', $str);
|
||||
else
|
||||
$str = preg_replace('/[^a-z0-9]/i', '-', $str);
|
||||
|
||||
$str = str_replace('--', '-', $str);
|
||||
$str = str_replace('--', '-', $str);
|
||||
|
||||
$str = rtrim($str, '-');
|
||||
$str = strtolower($str);
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
public static function getRealms()
|
||||
{
|
||||
if (DB::isConnectable(DB_AUTH) && !self::$realms)
|
||||
{
|
||||
self::$realms = DB::Auth()->select('SELECT
|
||||
id AS ARRAY_KEY,
|
||||
`name`,
|
||||
CASE
|
||||
WHEN timezone IN (2, 3, 4) THEN "us"
|
||||
WHEN timezone IN (8, 9, 10, 11, 12) THEN "eu"
|
||||
WHEN timezone = 6 THEN "kr"
|
||||
WHEN timezone = 14 THEN "tw"
|
||||
WHEN timezone = 16 THEN "cn"
|
||||
END AS region
|
||||
FROM
|
||||
realmlist
|
||||
WHERE
|
||||
allowedSecurityLevel = 0 AND
|
||||
gamebuild = ?d',
|
||||
WOW_BUILD
|
||||
);
|
||||
|
||||
foreach (self::$realms as $rId => $rData)
|
||||
{
|
||||
if (DB::isConnectable(DB_CHARACTERS . $rId))
|
||||
continue;
|
||||
|
||||
// realm in db but no connection info set
|
||||
unset(self::$realms[$rId]);
|
||||
}
|
||||
}
|
||||
|
||||
return self::$realms;
|
||||
}
|
||||
|
||||
private static function queueInsert($realmId, $guid, $type, $localId)
|
||||
{
|
||||
if ($rData = DB::Aowow()->selectRow('SELECT requestTime AS time, status FROM ?_profiler_sync WHERE realm = ?d AND realmGUID = ?d AND `type` = ?d AND typeId = ?d AND status <> ?d', $realmId, $guid, $type, $localId, PR_QUEUE_STATUS_WORKING))
|
||||
{
|
||||
// not on already scheduled - recalc time and set status to PR_QUEUE_STATUS_WAITING
|
||||
if ($rData['status'] != PR_QUEUE_STATUS_WAITING)
|
||||
{
|
||||
$newTime = CFG_DEBUG ? time() : max($rData['time'] + CFG_PROFILER_RESYNC_DELAY, time());
|
||||
DB::Aowow()->query('UPDATE ?_profiler_sync SET requestTime = ?d, status = ?d, errorCode = 0 WHERE realm = ?d AND realmGUID = ?d AND `type` = ?d AND typeId = ?d', $newTime, PR_QUEUE_STATUS_WAITING, $realmId, $guid, $type, $localId);
|
||||
}
|
||||
}
|
||||
else
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_sync (realm, realmGUID, `type`, typeId, requestTime, status, errorCode) VALUES (?d, ?d, ?d, ?d, UNIX_TIMESTAMP(), ?d, 0)', $realmId, $guid, $type, $localId, PR_QUEUE_STATUS_WAITING);
|
||||
}
|
||||
|
||||
public static function scheduleResync($type, $realmId, $guid)
|
||||
{
|
||||
$newId = 0;
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case Type::PROFILE:
|
||||
if ($newId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_profiles WHERE realm = ?d AND realmGUID = ?d', $realmId, $guid))
|
||||
self::queueInsert($realmId, $guid, Type::PROFILE, $newId);
|
||||
|
||||
break;
|
||||
case Type::GUILD:
|
||||
if ($newId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_guild WHERE realm = ?d AND realmGUID = ?d', $realmId, $guid))
|
||||
self::queueInsert($realmId, $guid, Type::GUILD, $newId);
|
||||
|
||||
break;
|
||||
case Type::ARENA_TEAM:
|
||||
if ($newId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_arena_team WHERE realm = ?d AND realmGUID = ?d', $realmId, $guid))
|
||||
self::queueInsert($realmId, $guid, Type::ARENA_TEAM, $newId);
|
||||
|
||||
break;
|
||||
default:
|
||||
trigger_error('scheduling resync for unknown type #'.$type.' omiting..', E_USER_WARNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!$newId)
|
||||
trigger_error('Profiler::scheduleResync() - tried to resync type #'.$type.' guid #'.$guid.' from realm #'.$realmId.' without preloaded data', E_USER_ERROR);
|
||||
else if (!self::queueStart($msg))
|
||||
trigger_error('Profiler::scheduleResync() - '.$msg, E_USER_ERROR);
|
||||
|
||||
return $newId;
|
||||
}
|
||||
|
||||
public static function resyncStatus($type, array $subjectGUIDs)
|
||||
{
|
||||
$response = [CFG_PROFILER_ENABLE ? 2 : 0]; // in theory you could have multiple queues; used as divisor for: (15 / x) + 2
|
||||
if (!$subjectGUIDs)
|
||||
$response[] = [PR_QUEUE_STATUS_ENDED, 0, 0, PR_QUEUE_ERROR_CHAR];
|
||||
else
|
||||
{
|
||||
// error out all profiles with status WORKING, that are older than 60sec
|
||||
DB::Aowow()->query('UPDATE ?_profiler_sync SET status = ?d, errorCode = ?d WHERE status = ?d AND requestTime < ?d', PR_QUEUE_STATUS_ERROR, PR_QUEUE_ERROR_UNK, PR_QUEUE_STATUS_WORKING, time() - MINUTE);
|
||||
|
||||
$subjectStatus = DB::Aowow()->select('SELECT typeId AS ARRAY_KEY, status, realm, errorCode FROM ?_profiler_sync WHERE `type` = ?d AND typeId IN (?a)', $type, $subjectGUIDs);
|
||||
$queue = DB::Aowow()->selectCol('SELECT CONCAT(type, ":", typeId) FROM ?_profiler_sync WHERE status = ?d AND requestTime < UNIX_TIMESTAMP() ORDER BY requestTime ASC', PR_QUEUE_STATUS_WAITING);
|
||||
foreach ($subjectGUIDs as $guid)
|
||||
{
|
||||
if (empty($subjectStatus[$guid])) // whelp, thats some error..
|
||||
$response[] = [PR_QUEUE_STATUS_ERROR, 0, 0, PR_QUEUE_ERROR_UNK];
|
||||
else if ($subjectStatus[$guid]['status'] == PR_QUEUE_STATUS_ERROR)
|
||||
$response[] = [PR_QUEUE_STATUS_ERROR, 0, 0, $subjectStatus[$guid]['errorCode']];
|
||||
else
|
||||
$response[] = array(
|
||||
$subjectStatus[$guid]['status'],
|
||||
$subjectStatus[$guid]['status'] != PR_QUEUE_STATUS_READY ? CFG_PROFILER_RESYNC_PING : 0,
|
||||
array_search($type.':'.$guid, $queue) + 1,
|
||||
0,
|
||||
1 // nResycTries - unsure about this one
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public static function getCharFromRealm($realmId, $charGuid)
|
||||
{
|
||||
$char = DB::Characters($realmId)->selectRow('SELECT c.* FROM characters c WHERE c.guid = ?d', $charGuid);
|
||||
if (!$char)
|
||||
return false;
|
||||
|
||||
// reminder: this query should not fail: a placeholder entry is created as soon as a char listview is created or profile detail page is called
|
||||
$profile = DB::Aowow()->selectRow('SELECT id, lastupdated FROM ?_profiler_profiles WHERE realm = ?d AND realmGUID = ?d', $realmId, $char['guid']);
|
||||
if (!$profile)
|
||||
return false; // well ... it failed
|
||||
|
||||
$profileId = $profile['id'];
|
||||
|
||||
CLI::write('fetching char '.$char['name'].' (#'.$charGuid.') from realm #'.$realmId);
|
||||
|
||||
if (!$char['online'] && $char['logout_time'] <= $profile['lastupdated'])
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET lastupdated = ?d WHERE id = ?d', time(), $profileId);
|
||||
CLI::write('char did not log in since last update. skipping...');
|
||||
return true;
|
||||
}
|
||||
|
||||
CLI::write('writing...');
|
||||
|
||||
$ra = (1 << ($char['race'] - 1));
|
||||
$cl = (1 << ($char['class'] - 1));
|
||||
|
||||
/*************/
|
||||
/* equipment */
|
||||
/*************/
|
||||
|
||||
/* enchantment-Indizes
|
||||
* 0: permEnchant
|
||||
* 3: tempEnchant
|
||||
* 6: gem1
|
||||
* 9: gem2
|
||||
* 12: gem3
|
||||
* 15: socketBonus [not used]
|
||||
* 18: extraSocket [only check existance]
|
||||
* 21 - 30: randomProp enchantments
|
||||
*/
|
||||
|
||||
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_items WHERE id = ?d', $profileId);
|
||||
$items = DB::Characters($realmId)->select('SELECT ci.slot AS ARRAY_KEY, ii.itemEntry, ii.enchantments, ii.randomPropertyId FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ?d AND bag = 0 AND slot BETWEEN 0 AND 18', $char['guid']);
|
||||
|
||||
$gemItems = [];
|
||||
$permEnch = [];
|
||||
$mhItem = 0;
|
||||
$ohItem = 0;
|
||||
|
||||
foreach ($items as $slot => $item)
|
||||
{
|
||||
$ench = explode(' ', $item['enchantments']);
|
||||
$gEnch = [];
|
||||
foreach ([6, 9, 12] as $idx)
|
||||
if ($ench[$idx])
|
||||
$gEnch[$idx] = $ench[$idx];
|
||||
|
||||
if ($gEnch)
|
||||
{
|
||||
$gi = DB::Aowow()->selectCol('SELECT gemEnchantmentId AS ARRAY_KEY, id FROM ?_items WHERE class = 3 AND gemEnchantmentId IN (?a)', $gEnch);
|
||||
foreach ($gEnch as $eId)
|
||||
{
|
||||
if (isset($gemItems[$eId]))
|
||||
$gemItems[$eId][1]++;
|
||||
else
|
||||
$gemItems[$eId] = [$gi[$eId], 1];
|
||||
}
|
||||
}
|
||||
|
||||
if ($slot + 1 == 16)
|
||||
$mhItem = $item['itemEntry'];
|
||||
if ($slot + 1 == 17)
|
||||
$ohItem = $item['itemEntry'];
|
||||
|
||||
if ($ench[0])
|
||||
$permEnch[$slot] = $ench[0];
|
||||
|
||||
$data = array(
|
||||
'id' => $profileId,
|
||||
'slot' => $slot + 1,
|
||||
'item' => $item['itemEntry'],
|
||||
'subItem' => $item['randomPropertyId'],
|
||||
'permEnchant' => $ench[0],
|
||||
'tempEnchant' => $ench[3],
|
||||
'extraSocket' => (int)!!$ench[18],
|
||||
'gem1' => isset($gemItems[$ench[6]]) ? $gemItems[$ench[6]][0] : 0,
|
||||
'gem2' => isset($gemItems[$ench[9]]) ? $gemItems[$ench[9]][0] : 0,
|
||||
'gem3' => isset($gemItems[$ench[12]]) ? $gemItems[$ench[12]][0] : 0,
|
||||
'gem4' => 0 // serverside items cant have more than 3 sockets. (custom profile thing)
|
||||
);
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_items (?#) VALUES (?a)', array_keys($data), array_values($data));
|
||||
}
|
||||
|
||||
CLI::write(' ..inventory');
|
||||
|
||||
|
||||
/**************/
|
||||
/* basic info */
|
||||
/**************/
|
||||
|
||||
$data = array(
|
||||
'realm' => $realmId,
|
||||
'realmGUID' => $charGuid,
|
||||
'name' => $char['name'],
|
||||
'renameItr' => 0,
|
||||
'race' => $char['race'],
|
||||
'class' => $char['class'],
|
||||
'level' => $char['level'],
|
||||
'gender' => $char['gender'],
|
||||
'skincolor' => $char['skin'],
|
||||
'facetype' => $char['face'], // maybe features
|
||||
'hairstyle' => $char['hairStyle'],
|
||||
'haircolor' => $char['hairColor'],
|
||||
'features' => $char['facialStyle'], // maybe facetype
|
||||
'title' => $char['chosenTitle'] ? DB::Aowow()->selectCell('SELECT id FROM ?_titles WHERE bitIdx = ?d', $char['chosenTitle']) : 0,
|
||||
'playedtime' => $char['totaltime'],
|
||||
'nomodelMask' => ($char['playerFlags'] & 0x400 ? (1 << SLOT_HEAD) : 0) | ($char['playerFlags'] & 0x800 ? (1 << SLOT_BACK) : 0),
|
||||
'talenttree1' => 0,
|
||||
'talenttree2' => 0,
|
||||
'talenttree3' => 0,
|
||||
'talentbuild1' => '',
|
||||
'talentbuild2' => '',
|
||||
'glyphs1' => '',
|
||||
'glyphs2' => '',
|
||||
'activespec' => $char['activeTalentGroup'],
|
||||
'guild' => null,
|
||||
'guildRank' => null,
|
||||
'gearscore' => 0,
|
||||
'achievementpoints' => 0
|
||||
);
|
||||
|
||||
// char is flagged for rename
|
||||
if ($char['at_login'] & 0x1)
|
||||
{
|
||||
$ri = DB::Aowow()->selectCell('SELECT MAX(renameItr) FROM ?_profiler_profiles WHERE realm = ?d AND realmGUID = ?d AND name = ?', $realmId, $charGuid, $char['name']);
|
||||
$data['renameItr'] = $ri ? ++$ri : 1;
|
||||
}
|
||||
|
||||
/********************/
|
||||
/* talents + glyphs */
|
||||
/********************/
|
||||
|
||||
$t = DB::Characters($realmId)->selectCol('SELECT talentGroup AS ARRAY_KEY, spell AS ARRAY_KEY2, spell FROM character_talent WHERE guid = ?d', $char['guid']);
|
||||
$g = DB::Characters($realmId)->select('SELECT talentGroup AS ARRAY_KEY, glyph1 AS g1, glyph2 AS g4, glyph3 AS g5, glyph4 AS g2, glyph5 AS g3, glyph6 AS g6 FROM character_glyphs WHERE guid = ?d', $char['guid']);
|
||||
for ($i = 0; $i < 2; $i++)
|
||||
{
|
||||
// talents
|
||||
for ($j = 0; $j < 3; $j++)
|
||||
{
|
||||
$_ = DB::Aowow()->selectCol('SELECT spell AS ARRAY_KEY, MAX(IF(spell IN (?a), `rank`, 0)) FROM ?_talents WHERE class = ?d AND tab = ?d GROUP BY id ORDER BY `row`, `col` ASC', !empty($t[$i]) ? $t[$i] : [0], $char['class'], $j);
|
||||
$data['talentbuild'.($i + 1)] .= implode('', $_);
|
||||
if ($data['activespec'] == $i)
|
||||
$data['talenttree'.($j + 1)] = array_sum($_);
|
||||
}
|
||||
|
||||
// glyphs
|
||||
if (isset($g[$i]))
|
||||
{
|
||||
$gProps = [];
|
||||
for ($j = 1; $j <= 6; $j++)
|
||||
if ($g[$i]['g'.$j])
|
||||
$gProps[$j] = $g[$i]['g'.$j];
|
||||
|
||||
if ($gProps)
|
||||
if ($gItems = DB::Aowow()->selectCol('SELECT i.id FROM ?_glyphproperties gp JOIN ?_spell s ON s.effect1MiscValue = gp.id AND s.effect1Id = 74 JOIN ?_items i ON i.class = 16 AND i.spellId1 = s.id WHERE gp.id IN (?a)', $gProps))
|
||||
$data['glyphs'.($i + 1)] = implode(':', $gItems);
|
||||
}
|
||||
}
|
||||
|
||||
$t = array(
|
||||
'spent' => [$data['talenttree1'], $data['talenttree2'], $data['talenttree3']],
|
||||
'spec' => 0
|
||||
);
|
||||
if ($t['spent'][0] > $t['spent'][1] && $t['spent'][0] > $t['spent'][2])
|
||||
$t['spec'] = 1;
|
||||
else if ($t['spent'][1] > $t['spent'][0] && $t['spent'][1] > $t['spent'][2])
|
||||
$t['spec'] = 2;
|
||||
else if ($t['spent'][2] > $t['spent'][1] && $t['spent'][2] > $t['spent'][0])
|
||||
$t['spec'] = 3;
|
||||
|
||||
// calc gearscore
|
||||
if ($items)
|
||||
$data['gearscore'] += (new ItemList(array(['id', array_column($items, 'itemEntry')])))->getScoreTotal($data['class'], $t, $mhItem, $ohItem);
|
||||
|
||||
if ($gemItems)
|
||||
{
|
||||
$gemScores = new ItemList(array(['id', array_column($gemItems, 0)]));
|
||||
foreach ($gemItems as [$itemId, $mult])
|
||||
if (isset($gemScores->json[$itemId]['gearscore']))
|
||||
$data['gearscore'] += $gemScores->json[$itemId]['gearscore'] * $mult;
|
||||
}
|
||||
|
||||
if ($permEnch) // fuck this shit .. we are guestimating this!
|
||||
{
|
||||
// enchantId => multiple spells => multiple items with varying itemlevels, quality, whatevs
|
||||
// cant reasonably get to the castItem from enchantId and slot
|
||||
|
||||
$profSpec = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, skillLevel AS "1", skillLine AS "0" FROM ?_itemenchantment WHERE id IN (?a)', $permEnch);
|
||||
foreach ($permEnch as $eId)
|
||||
{
|
||||
if ($x = Util::getEnchantmentScore(0, 0, !!$profSpec[$eId][1], $eId))
|
||||
$data['gearscore'] += $x;
|
||||
else if ($profSpec[$eId][0] != 776) // not runeforging
|
||||
$data['gearscore'] += 17; // assume high quality enchantment for unknown cases
|
||||
}
|
||||
}
|
||||
|
||||
$data['lastupdated'] = time();
|
||||
|
||||
CLI::write(' ..basic info');
|
||||
|
||||
|
||||
/***************/
|
||||
/* hunter pets */
|
||||
/***************/
|
||||
|
||||
if ($cl == CLASS_HUNTER)
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_pets WHERE owner = ?d', $profileId);
|
||||
$pets = DB::Characters($realmId)->select('SELECT id AS ARRAY_KEY, id, entry, modelId, name FROM character_pet WHERE owner = ?d', $charGuid);
|
||||
foreach ($pets as $petGuid => $petData)
|
||||
{
|
||||
$morePet = DB::Aowow()->selectRow('SELECT p.`type`, c.family FROM ?_pet p JOIN ?_creature c ON c.family = p.id WHERE c.id = ?d', $petData['entry']);
|
||||
$petSpells = DB::Characters($realmId)->selectCol('SELECT spell FROM pet_spell WHERE guid = ?d', $petGuid);
|
||||
|
||||
$_ = DB::Aowow()->selectCol('SELECT spell AS ARRAY_KEY, MAX(IF(spell IN (?a), `rank`, 0)) FROM ?_talents WHERE class = 0 AND petTypeMask = ?d GROUP BY id ORDER BY row, col ASC', $petSpells ?: [0], 1 << $morePet['type']);
|
||||
$pet = array(
|
||||
'id' => $petGuid,
|
||||
'owner' => $profileId,
|
||||
'name' => $petData['name'],
|
||||
'family' => $morePet['family'],
|
||||
'npc' => $petData['entry'],
|
||||
'displayId' => $petData['modelId'],
|
||||
'talents' => implode('', $_)
|
||||
);
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_pets (?#) VALUES (?a)', array_keys($pet), array_values($pet));
|
||||
}
|
||||
|
||||
CLI::write(' ..hunter pets');
|
||||
}
|
||||
|
||||
|
||||
/*******************/
|
||||
/* completion data */
|
||||
/*******************/
|
||||
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_completion WHERE id = ?d', $profileId);
|
||||
|
||||
// done quests
|
||||
if ($quests = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, quest AS typeId FROM character_queststatus_rewarded WHERE guid = ?d', $profileId, Type::QUEST, $char['guid']))
|
||||
foreach (Util::createSqlBatchInsert($quests) as $q)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$q, array_keys($quests[0]));
|
||||
|
||||
CLI::write(' ..quests');
|
||||
|
||||
|
||||
// known skills (professions only)
|
||||
$skAllowed = DB::Aowow()->selectCol('SELECT id FROM ?_skillline WHERE typeCat IN (9, 11) AND (cuFlags & ?d) = 0', CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
$skills = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, skill AS typeId, `value` AS cur, max FROM character_skills WHERE guid = ?d AND skill IN (?a)', $profileId, Type::SKILL, $char['guid'], $skAllowed);
|
||||
|
||||
// manually apply racial profession bonuses
|
||||
foreach ($skills as &$sk)
|
||||
{
|
||||
// Blood Elves - Arcane Affinity
|
||||
if ($sk['typeId'] == 333 && $char['race'] == 10)
|
||||
{
|
||||
$sk['cur'] += 10;
|
||||
$sk['max'] += 10;
|
||||
}
|
||||
// Draenei - Gemcutting
|
||||
if ($sk['typeId'] == 755 && $char['race'] == 11)
|
||||
{
|
||||
$sk['cur'] += 5;
|
||||
$sk['max'] += 5;
|
||||
}
|
||||
// Tauren - Cultivation
|
||||
// Gnomes - Engineering Specialization
|
||||
if (($sk['typeId'] == 182 && $char['race'] == 6) ||
|
||||
($sk['typeId'] == 202 && $char['race'] == 7))
|
||||
{
|
||||
$sk['cur'] += 15;
|
||||
$sk['max'] += 15;
|
||||
}
|
||||
}
|
||||
unset($sk);
|
||||
|
||||
if ($skills)
|
||||
{
|
||||
// apply auto-learned trade skills
|
||||
DB::Aowow()->query('
|
||||
INSERT INTO ?_profiler_completion
|
||||
SELECT ?d, ?d, spellId, NULL, NULL
|
||||
FROM dbc_skilllineability
|
||||
WHERE skillLineId IN (?a) AND
|
||||
acquireMethod = 1 AND
|
||||
(reqRaceMask = 0 OR reqRaceMask & ?d) AND
|
||||
(reqClassMask = 0 OR reqClassMask & ?d)',
|
||||
$profileId, Type::SPELL,
|
||||
array_column($skills, 'typeId'),
|
||||
1 << ($char['race'] - 1),
|
||||
1 << ($char['class'] - 1)
|
||||
);
|
||||
|
||||
foreach (Util::createSqlBatchInsert($skills) as $sk)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$sk, array_keys($skills[0]));
|
||||
}
|
||||
|
||||
CLI::write(' ..professions');
|
||||
|
||||
|
||||
// reputation
|
||||
|
||||
// get base values for this race/class
|
||||
$reputation = [];
|
||||
$baseRep = DB::Aowow()->selectCol('
|
||||
SELECT id AS ARRAY_KEY, baseRepValue1 FROM aowow_factions WHERE baseRepValue1 && (baseRepRaceMask1 & ?d || (!baseRepRaceMask1 AND baseRepClassMask1)) &&
|
||||
((baseRepClassMask1 & ?d) || !baseRepClassMask1) UNION
|
||||
SELECT id AS ARRAY_KEY, baseRepValue2 FROM aowow_factions WHERE baseRepValue2 && (baseRepRaceMask2 & ?d || (!baseRepRaceMask2 AND baseRepClassMask2)) &&
|
||||
((baseRepClassMask2 & ?d) || !baseRepClassMask2) UNION
|
||||
SELECT id AS ARRAY_KEY, baseRepValue3 FROM aowow_factions WHERE baseRepValue3 && (baseRepRaceMask3 & ?d || (!baseRepRaceMask3 AND baseRepClassMask3)) &&
|
||||
((baseRepClassMask3 & ?d) || !baseRepClassMask3) UNION
|
||||
SELECT id AS ARRAY_KEY, baseRepValue4 FROM aowow_factions WHERE baseRepValue4 && (baseRepRaceMask4 & ?d || (!baseRepRaceMask4 AND baseRepClassMask4)) &&
|
||||
((baseRepClassMask4 & ?d) || !baseRepClassMask4)
|
||||
', $ra, $cl, $ra, $cl, $ra, $cl, $ra, $cl);
|
||||
|
||||
if ($reputation = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, faction AS typeId, standing AS cur FROM character_reputation WHERE guid = ?d AND (flags & 0x4) = 0', $profileId, Type::FACTION, $char['guid']))
|
||||
{
|
||||
// merge back base values for encountered factions
|
||||
foreach ($reputation as &$set)
|
||||
{
|
||||
if (empty($baseRep[$set['typeId']]))
|
||||
continue;
|
||||
|
||||
$set['cur'] += $baseRep[$set['typeId']];
|
||||
unset($baseRep[$set['typeId']]);
|
||||
}
|
||||
}
|
||||
|
||||
// insert base values for not yet encountered factions
|
||||
foreach ($baseRep as $id => $val)
|
||||
$reputation[] = array(
|
||||
'id' => $profileId,
|
||||
'type' => Type::FACTION,
|
||||
'typeId' => $id,
|
||||
'cur' => $val
|
||||
);
|
||||
|
||||
foreach (Util::createSqlBatchInsert($reputation) as $rep)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$rep, array_keys($reputation[0]));
|
||||
|
||||
CLI::write(' ..reputation');
|
||||
|
||||
|
||||
// known titles
|
||||
$tBlocks = explode(' ', $char['knownTitles']);
|
||||
$indizes = [];
|
||||
for ($i = 0; $i < 6; $i++)
|
||||
for ($j = 0; $j < 32; $j++)
|
||||
if ($tBlocks[$i] & (1 << $j))
|
||||
$indizes[] = $j + ($i * 32);
|
||||
|
||||
if ($indizes)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion SELECT ?d, ?d, id, NULL, NULL FROM ?_titles WHERE bitIdx IN (?a)', $profileId, Type::TITLE, $indizes);
|
||||
|
||||
CLI::write(' ..titles');
|
||||
|
||||
|
||||
// achievements
|
||||
if ($achievements = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, achievement AS typeId, date AS cur FROM character_achievement WHERE guid = ?d', $profileId, Type::ACHIEVEMENT, $char['guid']))
|
||||
{
|
||||
foreach (Util::createSqlBatchInsert($achievements) as $a)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$a, array_keys($achievements[0]));
|
||||
|
||||
$data['achievementpoints'] = DB::Aowow()->selectCell('SELECT SUM(points) FROM ?_achievement WHERE id IN (?a)', array_column($achievements, 'typeId'));
|
||||
}
|
||||
|
||||
CLI::write(' ..achievements');
|
||||
|
||||
|
||||
// raid progression
|
||||
if ($progress = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, criteria AS typeId, date AS cur, counter AS `max` FROM character_achievement_progress WHERE guid = ?d AND criteria IN (?a)', $profileId, Type::ACHIEVEMENT, $char['guid'], self::$raidProgression))
|
||||
{
|
||||
array_walk($progress, function (&$val) { $val['typeId'] = array_search($val['typeId'], self::$raidProgression); });
|
||||
foreach (Util::createSqlBatchInsert($progress) as $p)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$p, array_keys($progress[0]));
|
||||
}
|
||||
|
||||
CLI::write(' ..raid progression');
|
||||
|
||||
|
||||
// known spells
|
||||
if ($spells = DB::Characters($realmId)->select('SELECT ?d AS id, ?d AS `type`, spell AS typeId FROM character_spell WHERE guid = ?d AND disabled = 0', $profileId, Type::SPELL, $char['guid']))
|
||||
foreach (Util::createSqlBatchInsert($spells) as $s)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_completion (?#) VALUES '.$s, array_keys($spells[0]));
|
||||
|
||||
CLI::write(' ..known spells (vanity pets & mounts)');
|
||||
|
||||
|
||||
/****************/
|
||||
/* related data */
|
||||
/****************/
|
||||
|
||||
// guilds
|
||||
if ($guild = DB::Characters($realmId)->selectRow('SELECT g.name AS name, g.guildid AS id, gm.rank FROM guild_member gm JOIN guild g ON g.guildid = gm.guildid WHERE gm.guid = ?d', $char['guid']))
|
||||
{
|
||||
$guildId = 0;
|
||||
if (!($guildId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_guild WHERE realm = ?d AND realmGUID = ?d', $realmId, $guild['id'])))
|
||||
{
|
||||
$gData = array( // only most basic data
|
||||
'realm' => $realmId,
|
||||
'realmGUID' => $guild['id'],
|
||||
'name' => $guild['name'],
|
||||
'nameUrl' => self::urlize($guild['name']),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
|
||||
$guildId = DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_guild (?#) VALUES (?a)', array_keys($gData), array_values($gData));
|
||||
}
|
||||
|
||||
$data['guild'] = $guildId;
|
||||
$data['guildRank'] = $guild['rank'];
|
||||
}
|
||||
|
||||
|
||||
// arena teams
|
||||
$teams = DB::Characters($realmId)->select('SELECT at.arenaTeamId AS ARRAY_KEY, at.name, at.type, IF(at.captainGuid = atm.guid, 1, 0) AS captain, atm.* FROM arena_team at JOIN arena_team_member atm ON atm.arenaTeamId = at.arenaTeamId WHERE atm.guid = ?d', $char['guid']);
|
||||
foreach ($teams as $rGuid => $t)
|
||||
{
|
||||
$teamId = 0;
|
||||
if (!($teamId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_arena_team WHERE realm = ?d AND realmGUID = ?d', $realmId, $rGuid)))
|
||||
{
|
||||
$team = array( // only most basic data
|
||||
'realm' => $realmId,
|
||||
'realmGUID' => $rGuid,
|
||||
'name' => $t['name'],
|
||||
'nameUrl' => self::urlize($t['name']),
|
||||
'type' => $t['type'],
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
|
||||
$teamId = DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team (?#) VALUES (?a)', array_keys($team), array_values($team));
|
||||
}
|
||||
|
||||
$member = array(
|
||||
'arenaTeamId' => $teamId,
|
||||
'profileId' => $profileId,
|
||||
'captain' => $t['captain'],
|
||||
'weekGames' => $t['weekGames'],
|
||||
'weekWins' => $t['weekWins'],
|
||||
'seasonGames' => $t['seasonGames'],
|
||||
'seasonWins' => $t['seasonWins'],
|
||||
'personalRating' => $t['personalRating']
|
||||
);
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_arena_team_member (?#) VALUES (?a) ON DUPLICATE KEY UPDATE ?a', array_keys($member), array_values($member), array_slice($member, 2));
|
||||
}
|
||||
|
||||
CLI::write(' ..associated arena teams');
|
||||
|
||||
/*********************/
|
||||
/* mark char as done */
|
||||
/*********************/
|
||||
|
||||
if (DB::Aowow()->query('UPDATE ?_profiler_profiles SET ?a WHERE realm = ?d AND realmGUID = ?d', $data, $realmId, $charGuid) !== null)
|
||||
DB::Aowow()->query('UPDATE ?_profiler_profiles SET cuFlags = cuFlags & ?d WHERE id = ?d', ~PROFILER_CU_NEEDS_RESYNC, $profileId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getGuildFromRealm($realmId, $guildGuid)
|
||||
{
|
||||
$guild = DB::Characters($realmId)->selectRow('SELECT guildId, name, createDate, info, backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor FROM guild WHERE guildId = ?d', $guildGuid);
|
||||
if (!$guild)
|
||||
return false;
|
||||
|
||||
// reminder: this query should not fail: a placeholder entry is created as soon as a team listview is created or team detail page is called
|
||||
$guildId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_guild WHERE realm = ?d AND realmGUID = ?d', $realmId, $guild['guildId']);
|
||||
|
||||
CLI::write('fetching guild #'.$guildGuid.' from realm #'.$realmId);
|
||||
CLI::write('writing...');
|
||||
|
||||
|
||||
/**************/
|
||||
/* Guild Data */
|
||||
/**************/
|
||||
|
||||
unset($guild['guildId']);
|
||||
$guild['nameUrl'] = self::urlize($guild['name']);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_guild SET ?a WHERE realm = ?d AND realmGUID = ?d', $guild, $realmId, $guildGuid);
|
||||
|
||||
// ranks
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_guild_rank WHERE guildId = ?d', $guildId);
|
||||
if ($ranks = DB::Characters($realmId)->select('SELECT ?d AS guildId, rid AS `rank`, rname AS name FROM guild_rank WHERE guildid = ?d', $guildId, $guildGuid))
|
||||
foreach (Util::createSqlBatchInsert($ranks) as $r)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_guild_rank (?#) VALUES '.$r, array_keys(reset($ranks)));
|
||||
|
||||
CLI::write(' ..guild data');
|
||||
|
||||
|
||||
/***************/
|
||||
/* Member Data */
|
||||
/***************/
|
||||
|
||||
$conditions = array(
|
||||
['g.guildid', $guildGuid],
|
||||
['deleteInfos_Account', null],
|
||||
['level', MAX_LEVEL, '<='], // prevents JS errors
|
||||
[['extra_flags', self::CHAR_GMFLAGS, '&'], 0] // not a staff char
|
||||
);
|
||||
|
||||
// this here should all happen within ProfileList
|
||||
$members = new RemoteProfileList($conditions, ['sv' => $realmId]);
|
||||
if (!$members->error)
|
||||
$members->initializeLocalEntries();
|
||||
else
|
||||
return false;
|
||||
|
||||
CLI::write(' ..guild members');
|
||||
|
||||
|
||||
/*********************/
|
||||
/* mark guild as done */
|
||||
/*********************/
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_guild SET cuFlags = cuFlags & ?d WHERE id = ?d', ~PROFILER_CU_NEEDS_RESYNC, $guildId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getArenaTeamFromRealm($realmId, $teamGuid)
|
||||
{
|
||||
$team = DB::Characters($realmId)->selectRow('SELECT arenaTeamId, name, type, captainGuid, rating, seasonGames, seasonWins, weekGames, weekWins, `rank`, backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor FROM arena_team WHERE arenaTeamId = ?d', $teamGuid);
|
||||
if (!$team)
|
||||
return false;
|
||||
|
||||
// reminder: this query should not fail: a placeholder entry is created as soon as a team listview is created or team detail page is called
|
||||
$teamId = DB::Aowow()->selectCell('SELECT id FROM ?_profiler_arena_team WHERE realm = ?d AND realmGUID = ?d', $realmId, $team['arenaTeamId']);
|
||||
|
||||
CLI::write('fetching arena team #'.$teamGuid.' from realm #'.$realmId);
|
||||
CLI::write('writing...');
|
||||
|
||||
|
||||
/*************/
|
||||
/* Team Data */
|
||||
/*************/
|
||||
|
||||
$captain = $team['captainGuid'];
|
||||
unset($team['captainGuid']);
|
||||
unset($team['arenaTeamId']);
|
||||
$team['nameUrl'] = self::urlize($team['name']);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_arena_team SET ?a WHERE realm = ?d AND realmGUID = ?d', $team, $realmId, $teamGuid);
|
||||
|
||||
CLI::write(' ..team data');
|
||||
|
||||
|
||||
/***************/
|
||||
/* Member Data */
|
||||
/***************/
|
||||
|
||||
$members = DB::Characters($realmId)->select('
|
||||
SELECT
|
||||
atm.guid AS ARRAY_KEY, atm.arenaTeamId, atm.weekGames, atm.weekWins, atm.seasonGames, atm.seasonWins, atm.personalrating
|
||||
FROM
|
||||
arena_team_member atm
|
||||
JOIN
|
||||
characters c ON c.guid = atm.guid AND
|
||||
c.deleteInfos_Account IS NULL AND
|
||||
c.level <= ?d AND
|
||||
(c.extra_flags & ?d) = 0
|
||||
WHERE
|
||||
arenaTeamId = ?d',
|
||||
MAX_LEVEL,
|
||||
self::CHAR_GMFLAGS,
|
||||
$teamGuid
|
||||
);
|
||||
|
||||
$conditions = array(
|
||||
['c.guid', array_keys($members)],
|
||||
['deleteInfos_Account', null],
|
||||
['level', MAX_LEVEL, '<='], // prevents JS errors
|
||||
[['extra_flags', self::CHAR_GMFLAGS, '&'], 0] // not a staff char
|
||||
);
|
||||
|
||||
$mProfiles = new RemoteProfileList($conditions, ['sv' => $realmId]);
|
||||
if (!$mProfiles->error)
|
||||
{
|
||||
$mProfiles->initializeLocalEntries();
|
||||
foreach ($mProfiles->iterate() as $__)
|
||||
{
|
||||
|
||||
$mGuid = $mProfiles->getField('guid');
|
||||
|
||||
$members[$mGuid]['arenaTeamId'] = $teamId;
|
||||
$members[$mGuid]['captain'] = (int)($mGuid == $captain);
|
||||
$members[$mGuid]['profileId'] = $mProfiles->getField('id');
|
||||
}
|
||||
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_arena_team_member WHERE arenaTeamId = ?d', $teamId);
|
||||
|
||||
foreach (Util::createSqlBatchInsert($members) as $m)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_arena_team_member (?#) VALUES '.$m, array_keys(reset($members)));
|
||||
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
CLI::write(' ..team members');
|
||||
|
||||
/*********************/
|
||||
/* mark team as done */
|
||||
/*********************/
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_profiler_arena_team SET cuFlags = cuFlags & ?d WHERE id = ?d', ~PROFILER_CU_NEEDS_RESYNC, $teamId);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,17 +1,17 @@
|
||||
<?php
|
||||
|
||||
define('AOWOW_REVISION', 33);
|
||||
define('AOWOW_REVISION', 1);
|
||||
define('CLI', PHP_SAPI === 'cli');
|
||||
|
||||
|
||||
$reqExt = ['SimpleXML', 'gd', 'mysqli', 'mbstring', 'fileinfo'/*, 'gmp'*/];
|
||||
$reqExt = ['SimpleXML', 'gd', 'mysqli', 'mbstring'];
|
||||
$error = '';
|
||||
foreach ($reqExt as $r)
|
||||
if (!extension_loaded($r))
|
||||
$error .= 'Required Extension <b>'.$r."</b> was not found. Please check if it should exist, using \"<i>php -m</i>\"\n\n";
|
||||
|
||||
if (version_compare(PHP_VERSION, '7.4.0') < 0)
|
||||
$error .= 'PHP Version <b>7.4</b> or higher required! Your version is <b>'.PHP_VERSION."</b>.\nCore functions are unavailable!\n";
|
||||
if (version_compare(PHP_VERSION, '5.5.0') < 0)
|
||||
$error .= 'PHP Version <b>5.5.0</b> or higher required! Your version is <b>'.PHP_VERSION."</b>.\nCore functions are unavailable!\n";
|
||||
|
||||
if ($error)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1
includes/tools/BLPConverter
Submodule
1
includes/tools/BLPConverter
Submodule
Submodule includes/tools/BLPConverter added at 7217e13598
1
includes/tools/MPQExtractor
Submodule
1
includes/tools/MPQExtractor
Submodule
Submodule includes/tools/MPQExtractor added at 32c72bb5f0
@@ -8,16 +8,15 @@ class AchievementList extends BaseType
|
||||
{
|
||||
use listviewHelper;
|
||||
|
||||
public static $type = Type::ACHIEVEMENT;
|
||||
public static $type = TYPE_ACHIEVEMENT;
|
||||
public static $brickFile = 'achievement';
|
||||
public static $dataTable = '?_achievement';
|
||||
|
||||
public $criteria = [];
|
||||
|
||||
protected $queryBase = 'SELECT `a`.*, `a`.`id` AS ARRAY_KEY FROM ?_achievement a';
|
||||
protected $queryOpts = array(
|
||||
'a' => [['ic'], 'o' => 'orderInGroup ASC'],
|
||||
'ic' => ['j' => ['?_icons ic ON ic.id = a.iconId', true], 's' => ', ic.name AS iconString'],
|
||||
'a' => [['si'], 'o' => 'orderInGroup ASC'],
|
||||
'si' => ['j' => ['?_icons si ON si.id = a.iconId', true], 's' => ', si.iconString'],
|
||||
'ac' => ['j' => ['?_achievementcriteria AS `ac` ON `ac`.`refAchievementId` = `a`.`id`', true], 'g' => '`a`.`id`']
|
||||
);
|
||||
|
||||
@@ -34,24 +33,7 @@ class AchievementList extends BaseType
|
||||
|
||||
// post processing
|
||||
$rewards = DB::World()->select('
|
||||
SELECT
|
||||
ar.ID AS ARRAY_KEY, ar.TitleA, ar.TitleH, ar.ItemID, ar.Sender AS sender, ar.MailTemplateID,
|
||||
ar.Subject AS subject_loc0, IFNULL(arl2.Subject, "") AS subject_loc2, IFNULL(arl3.Subject, "") AS subject_loc3, IFNULL(arl4.Subject, "") AS subject_loc4, IFNULL(arl6.Subject, "") AS subject_loc6, IFNULL(arl8.Subject, "") AS subject_loc8,
|
||||
ar.Body AS text_loc0, IFNULL(arl2.Body, "") AS text_loc2, IFNULL(arl3.Body, "") AS text_loc3, IFNULL(arl4.Body, "") AS text_loc4, IFNULL(arl6.Body, "") AS text_loc6, IFNULL(arl8.Body, "") AS text_loc8
|
||||
FROM
|
||||
achievement_reward ar
|
||||
LEFT JOIN
|
||||
achievement_reward_locale arl2 ON arl2.ID = ar.ID AND arl2.Locale = "frFR"
|
||||
LEFT JOIN
|
||||
achievement_reward_locale arl3 ON arl3.ID = ar.ID AND arl3.Locale = "deDE"
|
||||
LEFT JOIN
|
||||
achievement_reward_locale arl4 ON arl4.ID = ar.ID AND arl4.Locale = "zhCN"
|
||||
LEFT JOIN
|
||||
achievement_reward_locale arl6 ON arl6.ID = ar.ID AND arl6.Locale = "esES"
|
||||
LEFT JOIN
|
||||
achievement_reward_locale arl8 ON arl8.ID = ar.ID AND arl8.Locale = "ruRU"
|
||||
WHERE
|
||||
ar.ID IN (?a)',
|
||||
SELECT ar.entry AS ARRAY_KEY, ar.*, lar.* FROM achievement_reward ar LEFT JOIN locales_achievement_reward lar ON lar.entry = ar.entry WHERE ar.entry IN (?a)',
|
||||
$this->getFoundIDs()
|
||||
);
|
||||
|
||||
@@ -63,33 +45,31 @@ class AchievementList extends BaseType
|
||||
{
|
||||
$_curTpl = array_merge($rewards[$_id], $_curTpl);
|
||||
|
||||
$_curTpl['mailTemplate'] = $rewards[$_id]['MailTemplateID'];
|
||||
|
||||
if ($rewards[$_id]['MailTemplateID'])
|
||||
if ($rewards[$_id]['mailTemplate'])
|
||||
{
|
||||
// using class Loot creates an inifinite loop cirling between Loot, ItemList and SpellList or something
|
||||
// $mailSrc = new Loot();
|
||||
// $mailSrc->getByContainer(LOOT_MAIL, $rewards[$_id]['MailTemplateID']);
|
||||
// $mailSrc->getByContainer(LOOT_MAIL, $rewards[$_id]['mailTemplate']);
|
||||
// foreach ($mailSrc->iterate() as $loot)
|
||||
// $_curTpl['rewards'][] = [Type::ITEM, $loot['id']];
|
||||
// $_curTpl['rewards'][] = [TYPE_ITEM, $loot['id']];
|
||||
|
||||
// lets just assume for now, that mailRewards for achievements do not contain references
|
||||
$mailRew = DB::World()->selectCol('SELECT Item FROM mail_loot_template WHERE Reference <= 0 AND entry = ?d', $rewards[$_id]['MailTemplateID']);
|
||||
$mailRew = DB::World()->selectCol('SELECT Item FROM mail_loot_template WHERE Reference <= 0 AND entry = ?d', $rewards[$_id]['mailTemplate']);
|
||||
foreach ($mailRew AS $mr)
|
||||
$_curTpl['rewards'][] = [Type::ITEM, $mr];
|
||||
$_curTpl['rewards'][] = [TYPE_ITEM, $mr];
|
||||
}
|
||||
}
|
||||
|
||||
//"rewards":[[11,137],[3,138]] [type, typeId]
|
||||
if (!empty($_curTpl['ItemID']))
|
||||
$_curTpl['rewards'][] = [Type::ITEM, $_curTpl['ItemID']];
|
||||
if (!empty($_curTpl['item']))
|
||||
$_curTpl['rewards'][] = [TYPE_ITEM, $_curTpl['item']];
|
||||
if (!empty($_curTpl['itemExtra']))
|
||||
$_curTpl['rewards'][] = [Type::ITEM, $_curTpl['itemExtra']];
|
||||
if (!empty($_curTpl['TitleA']))
|
||||
$_curTpl['rewards'][] = [Type::TITLE, $_curTpl['TitleA']];
|
||||
if (!empty($_curTpl['TitleH']))
|
||||
if (empty($_curTpl['TitleA']) || $_curTpl['TitleA'] != $_curTpl['TitleH'])
|
||||
$_curTpl['rewards'][] = [Type::TITLE, $_curTpl['TitleH']];
|
||||
$_curTpl['rewards'][] = [TYPE_ITEM, $_curTpl['itemExtra']];
|
||||
if (!empty($_curTpl['title_A']))
|
||||
$_curTpl['rewards'][] = [TYPE_TITLE, $_curTpl['title_A']];
|
||||
if (!empty($_curTpl['title_H']))
|
||||
if (empty($_curTpl['title_A']) || $_curTpl['title_A'] != $_curTpl['title_H'])
|
||||
$_curTpl['rewards'][] = [TYPE_TITLE, $_curTpl['title_H']];
|
||||
|
||||
// icon
|
||||
$_curTpl['iconString'] = $_curTpl['iconString'] ?: 'trade_engineering';
|
||||
@@ -103,7 +83,7 @@ class AchievementList extends BaseType
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
if ($addMask & GLOBALINFO_SELF)
|
||||
$data[Type::ACHIEVEMENT][$this->id] = ['icon' => $this->curTpl['iconString'], 'name' => $this->getField('name', true)];
|
||||
$data[TYPE_ACHIEVEMENT][$this->id] = ['icon' => $this->curTpl['iconString'], 'name' => $this->getField('name', true)];
|
||||
|
||||
if ($addMask & GLOBALINFO_REWARDS)
|
||||
foreach ($this->curTpl['rewards'] as $_)
|
||||
@@ -151,7 +131,7 @@ class AchievementList extends BaseType
|
||||
if (isset($this->criteria[$this->id]))
|
||||
return $this->criteria[$this->id];
|
||||
|
||||
$result = DB::Aowow()->Select('SELECT * FROM ?_achievementcriteria WHERE `refAchievementId` = ?d ORDER BY `order` ASC', $this->curTpl['refAchievement'] ?: $this->id);
|
||||
$result = DB::Aowow()->Select('SELECT * FROM ?_achievementcriteria WHERE `refAchievementId` = ?d ORDER BY `order` ASC', $this->id);
|
||||
if (!$result)
|
||||
return [];
|
||||
|
||||
@@ -226,25 +206,23 @@ class AchievementList extends BaseType
|
||||
break;
|
||||
}
|
||||
|
||||
$criteria .= '<!--cr'.$crt['id'].':'.$crt['type'].':'.$crt['value1'].'-->- '.$crtName;
|
||||
|
||||
if ($crt['completionFlags'] & ACHIEVEMENT_CRITERIA_FLAG_MONEY_COUNTER)
|
||||
$criteria .= ' <span class="moneygold">'.Lang::nf($crt['value2' ] / 10000).'</span>';
|
||||
|
||||
$criteria .= '<br />';
|
||||
$criteria .= '- '.Util::jsEscape($crtName).' <span class="moneygold">'.number_format($crt['value2' ] / 10000).'</span><br />';
|
||||
else
|
||||
$criteria .= '- '.Util::jsEscape($crtName).'<br />';
|
||||
|
||||
if (++$i == round(count($rows)/2))
|
||||
$criteria .= '</small></td><th class="q0" style="white-space: nowrap; text-align: left"><small>';
|
||||
}
|
||||
|
||||
$x = '<table><tr><td><b class="q">';
|
||||
$x .= $name;
|
||||
$x .= Util::jsEscape($name);
|
||||
$x .= '</b></td></tr></table>';
|
||||
if ($description || $criteria)
|
||||
$x .= '<table><tr><td>';
|
||||
|
||||
if ($description)
|
||||
$x .= '<br />'.$description.'<br />';
|
||||
$x .= '<br />'.Util::jsEscape($description).'<br />';
|
||||
|
||||
if ($criteria)
|
||||
{
|
||||
@@ -266,7 +244,7 @@ class AchievementList extends BaseType
|
||||
$data[$this->id] = array(
|
||||
"n" => $this->getField('name', true),
|
||||
"s" => $this->curTpl['faction'],
|
||||
"t" => Type::ACHIEVEMENT,
|
||||
"t" => TYPE_ACHIEVEMENT,
|
||||
"ti" => $this->id
|
||||
);
|
||||
}
|
||||
@@ -300,39 +278,22 @@ class AchievementListFilter extends Filter
|
||||
321 => -1, 424 => -1, 301 => -1
|
||||
)
|
||||
);
|
||||
|
||||
protected $genericFilter = array( // misc (bool): _NUMERIC => useFloat; _STRING => localized; _FLAG => match Value; _BOOLEAN => stringSet
|
||||
2 => [FILTER_CR_BOOLEAN, 'reward_loc0', true ], // givesreward
|
||||
3 => [FILTER_CR_STRING, 'reward', STR_LOCALIZED ], // rewardtext
|
||||
4 => [FILTER_CR_NYI_PH, null, 1, ], // location [enum]
|
||||
5 => [FILTER_CR_CALLBACK, 'cbSeries', ACHIEVEMENT_CU_FIRST_SERIES, null], // first in series [yn]
|
||||
6 => [FILTER_CR_CALLBACK, 'cbSeries', ACHIEVEMENT_CU_LAST_SERIES, null], // last in series [yn]
|
||||
3 => [FILTER_CR_STRING, 'reward', true ], // rewardtext
|
||||
7 => [FILTER_CR_BOOLEAN, 'chainId', ], // partseries
|
||||
9 => [FILTER_CR_NUMERIC, 'id', NUM_CAST_INT, true], // id
|
||||
10 => [FILTER_CR_STRING, 'ic.name', ], // icon
|
||||
11 => [FILTER_CR_CALLBACK, 'cbRelEvent', null, null], // related event [enum]
|
||||
9 => [FILTER_CR_NUMERIC, 'id', null, true], // id
|
||||
10 => [FILTER_CR_STRING, 'si.iconString', ], // icon
|
||||
18 => [FILTER_CR_STAFFFLAG, 'flags', ], // flags
|
||||
14 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_COMMENT ], // hascomments
|
||||
15 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT ], // hasscreenshots
|
||||
16 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_VIDEO ], // hasvideos
|
||||
18 => [FILTER_CR_STAFFFLAG, 'flags', ] // flags
|
||||
);
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'cr' => [FILTER_V_RANGE, [2, 18], true ], // criteria ids
|
||||
'crs' => [FILTER_V_LIST, [FILTER_ENUM_NONE, FILTER_ENUM_ANY, [0, 99999]], true ], // criteria operators
|
||||
'crv' => [FILTER_V_REGEX, '/[\p{C};:%\\\\]/ui', true ], // criteria values - only printable chars, no delimiters
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name / description - only printable chars, no delimiter
|
||||
'ex' => [FILTER_V_EQUAL, 'on', false], // extended name search
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'si' => [FILTER_V_LIST, [1, 2, 3, -1, -2], false], // side
|
||||
'minpt' => [FILTER_V_RANGE, [1, 99], false], // required level min
|
||||
'maxpt' => [FILTER_V_RANGE, [1, 99], false] // required level max
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
if (in_array($cr[0], array_keys($this->genericFilter)))
|
||||
{
|
||||
if ($genCr = $this->genericCriterion($cr))
|
||||
return $genCr;
|
||||
|
||||
@@ -341,6 +302,43 @@ class AchievementListFilter extends Filter
|
||||
return [1];
|
||||
}
|
||||
|
||||
switch ($cr[0])
|
||||
{
|
||||
case 4: // location [enum]
|
||||
/* todo */ return [1]; // no plausible locations parsed yet
|
||||
case 5: // first in series [yn]
|
||||
if ($this->int2Bool($cr[1]))
|
||||
return $cr[1] ? ['AND', ['chainId', 0, '!'], ['cuFlags', ACHIEVEMENT_CU_FIRST_SERIES, '&']] : ['AND', ['chainId', 0, '!'], [['cuFlags', ACHIEVEMENT_CU_FIRST_SERIES, '&'], 0]];
|
||||
|
||||
break;
|
||||
case 6: // last in series [yn]
|
||||
if ($this->int2Bool($cr[1]))
|
||||
return $cr[1] ? ['AND', ['chainId', 0, '!'], ['cuFlags', ACHIEVEMENT_CU_LAST_SERIES, '&']] : ['AND', ['chainId', 0, '!'], [['cuFlags', ACHIEVEMENT_CU_LAST_SERIES, '&'], 0]];
|
||||
|
||||
break;
|
||||
case 11: // Related Event [enum]
|
||||
$_ = isset($this->enums[$cr[0]][$cr[1]]) ? $this->enums[$cr[0]][$cr[1]] : null;
|
||||
if ($_ !== null)
|
||||
{
|
||||
if (is_int($_))
|
||||
return ($_ > 0) ? ['category', $_] : ['id', abs($_)];
|
||||
else
|
||||
{
|
||||
$ids = array_filter($this->enums[$cr[0]], function($x) {
|
||||
return is_int($x) && $x > 0;
|
||||
});
|
||||
|
||||
return ['category', $ids, $_ ? null : '!'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
unset($cr);
|
||||
$this->error = true;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
@@ -361,57 +359,45 @@ class AchievementListFilter extends Filter
|
||||
|
||||
// points min
|
||||
if (isset($_v['minpt']))
|
||||
{
|
||||
if ($this->isSaneNumeric($_v['minpt']))
|
||||
$parts[] = ['points', $_v['minpt'], '>='];
|
||||
else
|
||||
unset($_v['minpt']);
|
||||
}
|
||||
|
||||
// points max
|
||||
if (isset($_v['maxpt']))
|
||||
{
|
||||
if ($this->isSaneNumeric($_v['maxpt']))
|
||||
$parts[] = ['points', $_v['maxpt'], '<='];
|
||||
else
|
||||
unset($_v['maxpt']);
|
||||
}
|
||||
|
||||
// faction (side)
|
||||
if (isset($_v['si']))
|
||||
{
|
||||
switch ($_v['si'])
|
||||
{
|
||||
case 3: // both
|
||||
$parts[] = ['faction', 0];
|
||||
break;
|
||||
case -1: // faction, exclusive both
|
||||
case -2:
|
||||
$parts[] = ['faction', -$_v['si']];
|
||||
break;
|
||||
case 1: // faction, inclusive both
|
||||
case 2:
|
||||
case 3: // both
|
||||
$parts[] = ['faction', $_v['si'], '&'];
|
||||
$parts[] = ['OR', ['faction', 0], ['faction', $_v['si']]];
|
||||
break;
|
||||
default:
|
||||
unset($_v['si']);
|
||||
}
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbRelEvent($cr, $value)
|
||||
{
|
||||
if (!isset($this->enums[$cr[0]][$cr[1]]))
|
||||
return false;
|
||||
|
||||
$_ = $this->enums[$cr[0]][$cr[1]];
|
||||
if (is_int($_))
|
||||
return ($_ > 0) ? ['category', $_] : ['id', abs($_)];
|
||||
else
|
||||
{
|
||||
$ids = array_filter($this->enums[$cr[0]], function($x) { return is_int($x) && $x > 0; });
|
||||
|
||||
return ['category', $ids, $_ ? null : '!'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbSeries($cr, $value)
|
||||
{
|
||||
if ($this->int2Bool($cr[1]))
|
||||
return $cr[1] ? ['AND', ['chainId', 0, '!'], ['cuFlags', $value, '&']] : ['AND', ['chainId', 0, '!'], [['cuFlags', $value, '&'], 0]];
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AreaTriggerList extends BaseType
|
||||
{
|
||||
use spawnHelper;
|
||||
|
||||
public static $type = Type::AREATRIGGER;
|
||||
public static $brickFile = 'areatrigger';
|
||||
public static $dataTable = '?_areatrigger';
|
||||
|
||||
protected $queryBase = 'SELECT a.*, a.id AS ARRAY_KEY FROM ?_areatrigger a';
|
||||
protected $queryOpts = array(
|
||||
'a' => [['s']],
|
||||
's' => ['j' => ['?_spawns s ON s.type = 503 AND s.typeId = a.id', true], 's' => ', s.areaId']
|
||||
);
|
||||
|
||||
public function __construct($conditions)
|
||||
{
|
||||
parent::__construct($conditions);
|
||||
|
||||
foreach ($this->iterate() as $id => &$_curTpl)
|
||||
if (!$_curTpl['name'])
|
||||
$_curTpl['name'] = 'Unnamed Areatrigger #' . $id;
|
||||
}
|
||||
|
||||
public function getListviewData() : array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'id' => $this->curTpl['id'],
|
||||
'type' => $this->curTpl['type'],
|
||||
'name' => $this->curTpl['name'],
|
||||
);
|
||||
|
||||
if ($_ = $this->curTpl['areaId'])
|
||||
$data[$this->id]['location'] = [$_];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getJSGlobals($addMask = GLOBALINFO_ANY)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function renderTooltip() { }
|
||||
}
|
||||
|
||||
class AreaTriggerListFilter extends Filter
|
||||
{
|
||||
protected $genericFilter = array(
|
||||
2 => [FILTER_CR_NUMERIC, 'id', NUM_CAST_INT] // id
|
||||
);
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'cr' => [FILTER_V_LIST, [2], true ], // criteria ids
|
||||
'crs' => [FILTER_V_RANGE, [1, 6], true ], // criteria operators
|
||||
'crv' => [FILTER_V_RANGE, [0, 99999], true ], // criteria values - all criteria are numeric here
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};\\\\]/ui', false], // name - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'ty' => [FILTER_V_RANGE, [0, 5], true ] // types
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
if (in_array($cr[0], array_keys($this->genericFilter)))
|
||||
if ($genCr = $this->genericCriterion($cr))
|
||||
return $genCr;
|
||||
|
||||
unset($cr);
|
||||
$this->error = true;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
$_v = &$this->fiData['v'];
|
||||
|
||||
// name [str]
|
||||
if (isset($_v['na']))
|
||||
if ($_ = $this->modularizeString(['name']))
|
||||
$parts[] = $_;
|
||||
|
||||
// type [list]
|
||||
if (isset($_v['ty']))
|
||||
$parts[] = ['type', $_v['ty']];
|
||||
|
||||
return $parts;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,346 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ArenaTeamList extends BaseType
|
||||
{
|
||||
use profilerHelper, listviewHelper;
|
||||
|
||||
private $rankOrder = [];
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
$data = [];
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'name' => $this->curTpl['name'],
|
||||
'realm' => Profiler::urlize($this->curTpl['realmName'], true),
|
||||
'realmname' => $this->curTpl['realmName'],
|
||||
// 'battlegroup' => Profiler::urlize($this->curTpl['battlegroup']), // was renamed to subregion somewhere around cata release
|
||||
// 'battlegroupname' => $this->curTpl['battlegroup'],
|
||||
'region' => Profiler::urlize($this->curTpl['region']),
|
||||
'faction' => $this->curTpl['faction'],
|
||||
'size' => $this->curTpl['type'],
|
||||
'rank' => $this->curTpl['rank'],
|
||||
'wins' => $this->curTpl['seasonWins'],
|
||||
'games' => $this->curTpl['seasonGames'],
|
||||
'rating' => $this->curTpl['rating'],
|
||||
'members' => $this->curTpl['members']
|
||||
);
|
||||
}
|
||||
|
||||
return array_values($data);
|
||||
}
|
||||
|
||||
public function renderTooltip() {}
|
||||
public function getJSGlobals($addMask = 0) {}
|
||||
}
|
||||
|
||||
|
||||
class ArenaTeamListFilter extends Filter
|
||||
{
|
||||
public $extraOpts = [];
|
||||
protected $genericFilter = [];
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'ex' => [FILTER_V_EQUAL, 'on', false], // only match exact
|
||||
'si' => [FILTER_V_LIST, [1, 2], false], // side
|
||||
'sz' => [FILTER_V_LIST, [2, 3, 5], false], // tema size
|
||||
'rg' => [FILTER_V_CALLBACK, 'cbRegionCheck', false], // region
|
||||
'sv' => [FILTER_V_CALLBACK, 'cbServerCheck', false], // server
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr) { }
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
$_v = $this->fiData['v'];
|
||||
|
||||
// region (rg), battlegroup (bg) and server (sv) are passed to ArenaTeamList as miscData and handled there
|
||||
|
||||
// name [str]
|
||||
if (!empty($_v['na']))
|
||||
if ($_ = $this->modularizeString(['at.name'], $_v['na'], !empty($_v['ex']) && $_v['ex'] == 'on'))
|
||||
$parts[] = $_;
|
||||
|
||||
// side [list]
|
||||
if (!empty($_v['si']))
|
||||
{
|
||||
if ($_v['si'] == 1)
|
||||
$parts[] = ['c.race', [1, 3, 4, 7, 11]];
|
||||
else if ($_v['si'] == 2)
|
||||
$parts[] = ['c.race', [2, 5, 6, 8, 10]];
|
||||
}
|
||||
|
||||
// size [int]
|
||||
if (!empty($_v['sz']))
|
||||
$parts[] = ['at.type', $_v['sz']];
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbRegionCheck(&$v)
|
||||
{
|
||||
if (in_array($v, Util::$regions))
|
||||
{
|
||||
$this->parentCats[0] = $v; // directly redirect onto this region
|
||||
$v = ''; // remove from filter
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbServerCheck(&$v)
|
||||
{
|
||||
foreach (Profiler::getRealms() as $realm)
|
||||
if ($realm['name'] == $v)
|
||||
{
|
||||
$this->parentCats[1] = Profiler::urlize($v);// directly redirect onto this server
|
||||
$v = ''; // remove from filter
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RemoteArenaTeamList extends ArenaTeamList
|
||||
{
|
||||
protected $queryBase = 'SELECT `at`.*, `at`.`arenaTeamId` AS ARRAY_KEY FROM arena_team at';
|
||||
protected $queryOpts = array(
|
||||
'at' => [['atm', 'c'], 'g' => 'ARRAY_KEY', 'o' => 'rating DESC'],
|
||||
'atm' => ['j' => 'arena_team_member atm ON atm.arenaTeamId = at.arenaTeamId'],
|
||||
'c' => ['j' => 'characters c ON c.guid = atm.guid AND c.deleteInfos_Account IS NULL AND c.level <= 80 AND (c.extra_flags & '.Profiler::CHAR_GMFLAGS.') = 0', 's' => ', BIT_OR(IF(c.race IN (1, 3, 4, 7, 11), 1, 2)) - 1 AS faction']
|
||||
);
|
||||
|
||||
private $members = [];
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
// select DB by realm
|
||||
if (!$this->selectRealms($miscData))
|
||||
{
|
||||
trigger_error('no access to auth-db or table realmlist is empty', E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
parent::__construct($conditions, $miscData);
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
// ranks in DB are inaccurate. recalculate from rating (fetched as DESC from DB)
|
||||
foreach ($this->dbNames as $rId => $__)
|
||||
foreach ([2, 3, 5] as $type)
|
||||
$this->rankOrder[$rId][$type] = DB::Characters($rId)->selectCol('SELECT arenaTeamId FROM arena_team WHERE `type` = ?d ORDER BY rating DESC', $type);
|
||||
|
||||
reset($this->dbNames); // only use when querying single realm
|
||||
$realmId = key($this->dbNames);
|
||||
$realms = Profiler::getRealms();
|
||||
$distrib = [];
|
||||
|
||||
// post processing
|
||||
foreach ($this->iterate() as $guid => &$curTpl)
|
||||
{
|
||||
// battlegroup
|
||||
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
|
||||
|
||||
// realm, rank
|
||||
$r = explode(':', $guid);
|
||||
if (!empty($realms[$r[0]]))
|
||||
{
|
||||
$curTpl['realm'] = $r[0];
|
||||
$curTpl['realmName'] = $realms[$r[0]]['name'];
|
||||
$curTpl['region'] = $realms[$r[0]]['region'];
|
||||
$curTpl['rank'] = array_search($curTpl['arenaTeamId'], $this->rankOrder[$r[0]][$curTpl['type']]) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error('arena team "'.$curTpl['name'].'" belongs to nonexistant realm #'.$r, E_USER_WARNING);
|
||||
unset($this->templates[$guid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// team members
|
||||
$this->members[$r[0]][$r[1]] = $r[1];
|
||||
|
||||
// equalize distribution
|
||||
if (empty($distrib[$curTpl['realm']]))
|
||||
$distrib[$curTpl['realm']] = 1;
|
||||
else
|
||||
$distrib[$curTpl['realm']]++;
|
||||
}
|
||||
|
||||
// get team members
|
||||
foreach ($this->members as $realmId => &$teams)
|
||||
$teams = DB::Characters($realmId)->select('
|
||||
SELECT
|
||||
at.arenaTeamId AS ARRAY_KEY, c.guid AS ARRAY_KEY2, c.name AS "0", c.class AS "1", IF(at.captainguid = c.guid, 1, 0) AS "2"
|
||||
FROM
|
||||
arena_team at
|
||||
JOIN
|
||||
arena_team_member atm ON atm.arenaTeamId = at.arenaTeamId JOIN characters c ON c.guid = atm.guid
|
||||
WHERE
|
||||
at.arenaTeamId IN (?a) AND
|
||||
c.deleteInfos_Account IS NULL AND
|
||||
c.level <= ?d AND
|
||||
(c.extra_flags & ?d) = 0',
|
||||
$teams,
|
||||
MAX_LEVEL,
|
||||
Profiler::CHAR_GMFLAGS
|
||||
);
|
||||
|
||||
// equalize subject distribution across realms
|
||||
$limit = CFG_SQL_LIMIT_DEFAULT;
|
||||
foreach ($conditions as $c)
|
||||
if (is_int($c))
|
||||
$limit = $c;
|
||||
|
||||
$total = array_sum($distrib);
|
||||
foreach ($distrib as &$d)
|
||||
$d = ceil($limit * $d / $total);
|
||||
|
||||
foreach ($this->iterate() as $guid => &$curTpl)
|
||||
{
|
||||
if ($limit <= 0 || $distrib[$curTpl['realm']] <= 0)
|
||||
{
|
||||
unset($this->templates[$guid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$r = explode(':', $guid);
|
||||
if (isset($this->members[$r[0]][$r[1]]))
|
||||
$curTpl['members'] = array_values($this->members[$r[0]][$r[1]]); // [name, classId, isCaptain]
|
||||
|
||||
$distrib[$curTpl['realm']]--;
|
||||
$limit--;
|
||||
}
|
||||
}
|
||||
|
||||
public function initializeLocalEntries()
|
||||
{
|
||||
$profiles = [];
|
||||
// init members for tooltips
|
||||
foreach ($this->members as $realmId => $teams)
|
||||
{
|
||||
$gladiators = [];
|
||||
foreach ($teams as $team)
|
||||
$gladiators = array_merge($gladiators, array_keys($team));
|
||||
|
||||
$profiles[$realmId] = new RemoteProfileList(array(['c.guid', $gladiators], CFG_SQL_LIMIT_NONE), ['sv' => $realmId]);
|
||||
|
||||
if (!$profiles[$realmId]->error)
|
||||
$profiles[$realmId]->initializeLocalEntries();
|
||||
}
|
||||
|
||||
$data = [];
|
||||
foreach ($this->iterate() as $guid => $__)
|
||||
{
|
||||
$data[$guid] = array(
|
||||
'realm' => $this->getField('realm'),
|
||||
'realmGUID' => $this->getField('arenaTeamId'),
|
||||
'name' => $this->getField('name'),
|
||||
'nameUrl' => Profiler::urlize($this->getField('name')),
|
||||
'type' => $this->getField('type'),
|
||||
'rating' => $this->getField('rating'),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
}
|
||||
|
||||
// basic arena team data
|
||||
foreach (Util::createSqlBatchInsert($data) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team (?#) VALUES '.$ins, array_keys(reset($data)));
|
||||
|
||||
// merge back local ids
|
||||
$localIds = DB::Aowow()->selectCol(
|
||||
'SELECT CONCAT(realm, ":", realmGUID) AS ARRAY_KEY, id FROM ?_profiler_arena_team WHERE realm IN (?a) AND realmGUID IN (?a)',
|
||||
array_column($data, 'realm'),
|
||||
array_column($data, 'realmGUID')
|
||||
);
|
||||
|
||||
foreach ($this->iterate() as $guid => &$_curTpl)
|
||||
if (isset($localIds[$guid]))
|
||||
$_curTpl['id'] = $localIds[$guid];
|
||||
|
||||
|
||||
// profiler_arena_team_member requires profiles and arena teams to be filled
|
||||
foreach ($this->members as $realmId => $teams)
|
||||
{
|
||||
if (empty($profiles[$realmId]))
|
||||
continue;
|
||||
|
||||
$memberData = [];
|
||||
foreach ($teams as $teamId => $team)
|
||||
foreach ($team as $memberId => $member)
|
||||
$memberData[] = array(
|
||||
'arenaTeamId' => $localIds[$realmId.':'.$teamId],
|
||||
'profileId' => $profiles[$realmId]->getEntry($realmId.':'.$memberId)['id'],
|
||||
'captain' => $member[2]
|
||||
);
|
||||
|
||||
foreach (Util::createSqlBatchInsert($memberData) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team_member (?#) VALUES '.$ins, array_keys(reset($memberData)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LocalArenaTeamList extends ArenaTeamList
|
||||
{
|
||||
protected $queryBase = 'SELECT at.*, at.id AS ARRAY_KEY FROM ?_profiler_arena_team at';
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
parent::__construct($conditions, $miscData);
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
$realms = Profiler::getRealms();
|
||||
|
||||
// post processing
|
||||
$members = DB::Aowow()->selectCol('SELECT *, arenaTeamId AS ARRAY_KEY, profileId AS ARRAY_KEY2 FROM ?_profiler_arena_team_member WHERE arenaTeamId IN (?a)', $this->getFoundIDs());
|
||||
|
||||
foreach ($this->iterate() as $id => &$curTpl)
|
||||
{
|
||||
if ($curTpl['realm'] && !isset($realms[$curTpl['realm']]))
|
||||
continue;
|
||||
|
||||
if (isset($realms[$curTpl['realm']]))
|
||||
{
|
||||
$curTpl['realmName'] = $realms[$curTpl['realm']]['name'];
|
||||
$curTpl['region'] = $realms[$curTpl['realm']]['region'];
|
||||
}
|
||||
|
||||
// battlegroup
|
||||
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
|
||||
|
||||
$curTpl['members'] = $members[$id];
|
||||
}
|
||||
}
|
||||
|
||||
public function getProfileUrl()
|
||||
{
|
||||
$url = '?arena-team=';
|
||||
|
||||
return $url.implode('.', array(
|
||||
Profiler::urlize($this->getField('region')),
|
||||
Profiler::urlize($this->getField('realmName')),
|
||||
Profiler::urlize($this->getField('name'))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,11 +6,10 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class CharClassList extends BaseType
|
||||
{
|
||||
public static $type = Type::CHR_CLASS;
|
||||
public static $type = TYPE_CLASS;
|
||||
public static $brickFile = 'class';
|
||||
public static $dataTable = '?_classes';
|
||||
|
||||
protected $queryBase = 'SELECT c.*, id AS ARRAY_KEY FROM ?_classes c';
|
||||
protected $queryBase = 'SELECT *, id AS ARRAY_KEY FROM ?_classes c';
|
||||
|
||||
public function __construct($conditions = [])
|
||||
{
|
||||
|
||||
@@ -6,11 +6,10 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class CharRaceList extends BaseType
|
||||
{
|
||||
public static $type = Type::CHR_RACE;
|
||||
public static $type = TYPE_RACE;
|
||||
public static $brickFile = 'race';
|
||||
public static $dataTable = '?_races';
|
||||
|
||||
protected $queryBase = 'SELECT r.*, id AS ARRAY_KEY FROM ?_races r';
|
||||
protected $queryBase = 'SELECT *, id AS ARRAY_KEY FROM ?_races r';
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
@@ -40,7 +39,7 @@ class CharRaceList extends BaseType
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[Type::CHR_RACE][$this->id] = ['name' => $this->getField('name', true)];
|
||||
$data[TYPE_RACE][$this->id] = ['name' => $this->getField('name', true)];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -8,13 +8,12 @@ class CreatureList extends BaseType
|
||||
{
|
||||
use spawnHelper;
|
||||
|
||||
public static $type = Type::NPC;
|
||||
public static $type = TYPE_NPC;
|
||||
public static $brickFile = 'creature';
|
||||
public static $dataTable = '?_creature';
|
||||
|
||||
protected $queryBase = 'SELECT ct.*, ct.id AS ARRAY_KEY FROM ?_creature ct';
|
||||
public $queryOpts = array(
|
||||
'ct' => [['ft', 'qse', 'dct1', 'dct2', 'dct3'], 's' => ', IFNULL(dct1.id, IFNULL(dct2.id, IFNULL(dct3.id, 0))) AS parentId, IFNULL(dct1.name_loc0, IFNULL(dct2.name_loc0, IFNULL(dct3.name_loc0, ""))) AS parent_loc0, IFNULL(dct1.name_loc2, IFNULL(dct2.name_loc2, IFNULL(dct3.name_loc2, ""))) AS parent_loc2, IFNULL(dct1.name_loc3, IFNULL(dct2.name_loc3, IFNULL(dct3.name_loc3, ""))) AS parent_loc3, IFNULL(dct1.name_loc4, IFNULL(dct2.name_loc4, IFNULL(dct3.name_loc4, ""))) AS parent_loc4, IFNULL(dct1.name_loc6, IFNULL(dct2.name_loc6, IFNULL(dct3.name_loc6, ""))) AS parent_loc6, IFNULL(dct1.name_loc8, IFNULL(dct2.name_loc8, IFNULL(dct3.name_loc8, ""))) AS parent_loc8, IF(dct1.difficultyEntry1 = ct.id, 1, IF(dct2.difficultyEntry2 = ct.id, 2, IF(dct3.difficultyEntry3 = ct.id, 3, 0))) AS difficultyMode'],
|
||||
'ct' => [['ft', 'qse', 'dct1', 'dct2', 'dct3'], 's' => ', IFNULL(dct1.id, IFNULL(dct2.id, IFNULL(dct3.id, 0))) AS parentId, IFNULL(dct1.name_loc0, IFNULL(dct2.name_loc0, IFNULL(dct3.name_loc0, ""))) AS parent_loc0, IFNULL(dct1.name_loc2, IFNULL(dct2.name_loc2, IFNULL(dct3.name_loc2, ""))) AS parent_loc2, IFNULL(dct1.name_loc3, IFNULL(dct2.name_loc3, IFNULL(dct3.name_loc3, ""))) AS parent_loc3, IFNULL(dct1.name_loc6, IFNULL(dct2.name_loc6, IFNULL(dct3.name_loc6, ""))) AS parent_loc6, IFNULL(dct1.name_loc8, IFNULL(dct2.name_loc8, IFNULL(dct3.name_loc8, ""))) AS parent_loc8, IF(dct1.difficultyEntry1 = ct.id, 1, IF(dct2.difficultyEntry2 = ct.id, 2, IF(dct3.difficultyEntry3 = ct.id, 3, 0))) AS difficultyMode'],
|
||||
'dct1' => ['j' => ['?_creature dct1 ON ct.cuFlags & 0x02 AND dct1.difficultyEntry1 = ct.id', true]],
|
||||
'dct2' => ['j' => ['?_creature dct2 ON ct.cuFlags & 0x02 AND dct2.difficultyEntry2 = ct.id', true]],
|
||||
'dct3' => ['j' => ['?_creature dct3 ON ct.cuFlags & 0x02 AND dct3.difficultyEntry3 = ct.id', true]],
|
||||
@@ -49,7 +48,7 @@ class CreatureList extends BaseType
|
||||
|
||||
public static function getName($id)
|
||||
{
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8 FROM ?_creature WHERE id = ?d', $id);
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc6, name_loc8 FROM ?_creature WHERE id = ?d', $id);
|
||||
return Util::localizedString($n, 'name');
|
||||
}
|
||||
|
||||
@@ -77,14 +76,13 @@ class CreatureList extends BaseType
|
||||
if ($type)
|
||||
$row3[] = Lang::game('ct', $type);
|
||||
|
||||
if ($_ = Lang::npc('rank', $this->curTpl['rank']))
|
||||
$row3[] = '('.$_.')';
|
||||
$row3[] = '('.Lang::npc('rank', $this->curTpl['rank']).')';
|
||||
|
||||
$x = '<table>';
|
||||
$x .= '<tr><td><b class="q">'.Util::htmlEscape($this->getField('name', true)).'</b></td></tr>';
|
||||
$x .= '<tr><td><b class="q">'.$this->getField('name', true).'</b></td></tr>';
|
||||
|
||||
if ($sn = $this->getField('subname', true))
|
||||
$x .= '<tr><td>'.Util::htmlEscape($sn).'</td></tr>';
|
||||
$x .= '<tr><td>'.$sn.'</td></tr>';
|
||||
|
||||
$x .= '<tr><td>'.implode(' ', $row3).'</td></tr>';
|
||||
|
||||
@@ -102,22 +100,27 @@ class CreatureList extends BaseType
|
||||
|
||||
public function getRandomModelId()
|
||||
{
|
||||
// dwarf?? [null, 30754, 30753, 30755, 30736]
|
||||
// totems use hardcoded models, tauren model is base
|
||||
$totems = [null, 4589, 4588, 4587, 4590]; // slot => modelId
|
||||
$totems = array( // tauren => [orc, dwarf(?!), troll, tauren, draenei]
|
||||
4589 => [30758, 30754, 30762, 4589, 19074], // fire
|
||||
4588 => [30757, 30753, 30761, 4588, 19073], // earth
|
||||
4587 => [30759, 30755, 30763, 4587, 19075], // water
|
||||
4590 => [30756, 30736, 30760, 4590, 19071], // air
|
||||
);
|
||||
|
||||
$data = [];
|
||||
|
||||
for ($i = 1; $i < 5; $i++)
|
||||
if ($_ = $this->curTpl['displayId'.$i])
|
||||
$data[] = $_;
|
||||
|
||||
if (count($data) == 1 && ($slotId = array_search($data[0], $totems)))
|
||||
$data = DB::World()->selectCol('SELECT DisplayId FROM player_totem_model WHERE TotemSlot = ?d', $slotId);
|
||||
if (count($data) == 1 && in_array($data[0], array_keys($totems)))
|
||||
$data = $totems[$data[0]];
|
||||
|
||||
return !$data ? 0 : $data[array_rand($data)];
|
||||
}
|
||||
|
||||
public function getBaseStats(string $type) : array
|
||||
public function getBaseStats($type)
|
||||
{
|
||||
// i'm aware of the BaseVariance/RangedVariance fields ... i'm just totaly unsure about the whole damage calculation
|
||||
switch ($type)
|
||||
@@ -142,14 +145,8 @@ class CreatureList extends BaseType
|
||||
$rngMin = ($this->getField('dmgMin') + ($this->getField('rngAtkPwrMin') / 14)) * $this->getField('dmgMultiplier') * $this->getField('rngAtkSpeed');
|
||||
$rngMax = ($this->getField('dmgMax') * 1.5 + ($this->getField('rngAtkPwrMax') / 14)) * $this->getField('dmgMultiplier') * $this->getField('rngAtkSpeed');
|
||||
return [$rngMin, $rngMax];
|
||||
case 'resistance':
|
||||
$r = [];
|
||||
for ($i = SPELL_SCHOOL_HOLY; $i < SPELL_SCHOOL_ARCANE+1; $i++)
|
||||
$r[$i] = $this->getField('resistance'.$i);
|
||||
|
||||
return $r;
|
||||
default:
|
||||
return [];
|
||||
return [0, 0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,22 +161,9 @@ class CreatureList extends BaseType
|
||||
*
|
||||
* NPCINFO_TAMEABLE (0x1): include texture & react
|
||||
* NPCINFO_MODEL (0x2):
|
||||
* NPCINFO_REP (0x4): include repreward
|
||||
*/
|
||||
|
||||
$data = [];
|
||||
$rewRep = [];
|
||||
|
||||
if ($addInfoMask & NPCINFO_REP && $this->getFoundIDs())
|
||||
{
|
||||
$rewRep = DB::World()->selectCol('
|
||||
SELECT creature_id AS ARRAY_KEY, RewOnKillRepFaction1 AS ARRAY_KEY2, RewOnKillRepValue1 FROM creature_onkill_reputation WHERE creature_id IN (?a) AND RewOnKillRepFaction1 > 0 UNION
|
||||
SELECT creature_id AS ARRAY_KEY, RewOnKillRepFaction2 AS ARRAY_KEY2, RewOnKillRepValue2 FROM creature_onkill_reputation WHERE creature_id IN (?a) AND RewOnKillRepFaction2 > 0',
|
||||
$this->getFoundIDs(),
|
||||
$this->getFoundIDs()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
@@ -223,7 +207,6 @@ class CreatureList extends BaseType
|
||||
'react' => [$this->curTpl['A'], $this->curTpl['H']],
|
||||
);
|
||||
|
||||
|
||||
if ($this->getField('startsQuests'))
|
||||
$data[$this->id]['hasQuests'] = 1;
|
||||
|
||||
@@ -232,14 +215,6 @@ class CreatureList extends BaseType
|
||||
|
||||
if ($addInfoMask & NPCINFO_TAMEABLE) // only first skin of first model ... we're omitting potentially 11 skins here .. but the lv accepts only one .. w/e
|
||||
$data[$this->id]['skin'] = $this->curTpl['textureString'];
|
||||
|
||||
if ($addInfoMask & NPCINFO_REP)
|
||||
{
|
||||
$data[$this->id]['reprewards'] = [];
|
||||
if ($rewRep[$this->id])
|
||||
foreach ($rewRep[$this->id] as $fac => $val)
|
||||
$data[$this->id]['reprewards'][] = [$fac, $val];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +227,7 @@ class CreatureList extends BaseType
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[Type::NPC][$this->id] = ['name' => $this->getField('name', true)];
|
||||
$data[TYPE_NPC][$this->id] = ['name' => $this->getField('name', true)];
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -265,7 +240,7 @@ class CreatureList extends BaseType
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'n' => $this->getField('parentId') ? $this->getField('parent', true) : $this->getField('name', true),
|
||||
't' => Type::NPC,
|
||||
't' => TYPE_NPC,
|
||||
'ti' => $this->getField('parentId') ?: $this->id,
|
||||
// 'bd' => (int)($this->curTpl['cuFlags'] & NPC_CU_INSTANCE_BOSS || ($this->curTpl['typeFlags'] & 0x4 && $this->curTpl['rank']))
|
||||
// 'z' where am i spawned
|
||||
@@ -278,7 +253,6 @@ class CreatureList extends BaseType
|
||||
|
||||
public function addRewardsToJScript(&$refs) { }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -294,19 +268,10 @@ class CreatureListFilter extends Filter
|
||||
|
||||
// cr => [type, field, misc, extraCol]
|
||||
protected $genericFilter = array( // misc (bool): _NUMERIC => useFloat; _STRING => localized; _FLAG => match Value; _BOOLEAN => stringSet
|
||||
1 => [FILTER_CR_CALLBACK, 'cbHealthMana', 'healthMax', 'healthMin'], // health [num]
|
||||
2 => [FILTER_CR_CALLBACK, 'cbHealthMana', 'manaMin', 'manaMax' ], // mana [num]
|
||||
3 => [FILTER_CR_CALLBACK, 'cbFaction', null, null ], // faction [enum]
|
||||
5 => [FILTER_CR_FLAG, 'npcflag', NPC_FLAG_REPAIRER ], // canrepair
|
||||
6 => [FILTER_CR_ENUM, 's.areaId', null ], // foundin
|
||||
7 => [FILTER_CR_CALLBACK, 'cbQuestRelation', 'startsQuests', 0x1 ], // startsquest [enum]
|
||||
8 => [FILTER_CR_CALLBACK, 'cbQuestRelation', 'endsQuests', 0x2 ], // endsquest [enum]
|
||||
9 => [FILTER_CR_BOOLEAN, 'lootId', ], // lootable
|
||||
10 => [FILTER_CR_CALLBACK, 'cbRegularSkinLoot', NPC_TYPEFLAG_SPECIALLOOT ], // skinnable [yn]
|
||||
11 => [FILTER_CR_BOOLEAN, 'pickpocketLootId', ], // pickpocketable
|
||||
12 => [FILTER_CR_CALLBACK, 'cbMoneyDrop', null, null ], // averagemoneydropped [op] [int]
|
||||
15 => [FILTER_CR_CALLBACK, 'cbSpecialSkinLoot', NPC_TYPEFLAG_HERBLOOT, null ], // gatherable [yn]
|
||||
16 => [FILTER_CR_CALLBACK, 'cbSpecialSkinLoot', NPC_TYPEFLAG_MININGLOOT, null ], // minable [yn]
|
||||
18 => [FILTER_CR_FLAG, 'npcflag', NPC_FLAG_AUCTIONEER ], // auctioneer
|
||||
19 => [FILTER_CR_FLAG, 'npcflag', NPC_FLAG_BANKER ], // banker
|
||||
20 => [FILTER_CR_FLAG, 'npcflag', NPC_FLAG_BATTLEMASTER ], // battlemaster
|
||||
@@ -318,39 +283,19 @@ class CreatureListFilter extends Filter
|
||||
27 => [FILTER_CR_FLAG, 'npcflag', NPC_FLAG_STABLE_MASTER ], // stablemaster
|
||||
28 => [FILTER_CR_FLAG, 'npcflag', NPC_FLAG_TRAINER ], // trainer
|
||||
29 => [FILTER_CR_FLAG, 'npcflag', NPC_FLAG_VENDOR ], // vendor
|
||||
31 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT ], // hasscreenshots
|
||||
19 => [FILTER_CR_FLAG, 'npcflag', NPC_FLAG_BANKER ], // banker
|
||||
37 => [FILTER_CR_NUMERIC, 'id', null, true], // id
|
||||
35 => [FILTER_CR_STRING, 'textureString' ], // useskin
|
||||
32 => [FILTER_CR_FLAG, 'cuFlags', NPC_CU_INSTANCE_BOSS ], // instanceboss
|
||||
33 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_COMMENT ], // hascomments
|
||||
34 => [FILTER_CR_NYI_PH, 1, null ], // usemodel [str] - displayId -> id:creatureDisplayInfo.dbc/model -> id:cratureModelData.dbc/modelPath
|
||||
35 => [FILTER_CR_STRING, 'textureString' ], // useskin
|
||||
37 => [FILTER_CR_NUMERIC, 'id', NUM_CAST_INT, true ], // id
|
||||
38 => [FILTER_CR_CALLBACK, 'cbRelEvent', null, null ], // relatedevent [enum]
|
||||
31 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT ], // hasscreenshots
|
||||
40 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_VIDEO ], // hasvideos
|
||||
41 => [FILTER_CR_NYI_PH, 1, null ], // haslocation [yn] [staff]
|
||||
42 => [FILTER_CR_CALLBACK, 'cbReputation', '>', null ], // increasesrepwith [enum]
|
||||
43 => [FILTER_CR_CALLBACK, 'cbReputation', '<', null ], // decreasesrepwith [enum]
|
||||
44 => [FILTER_CR_CALLBACK, 'cbSpecialSkinLoot', NPC_TYPEFLAG_ENGINEERLOOT, null ] // salvageable [yn]
|
||||
);
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'cr' => [FILTER_V_LIST, [[1, 3],[5, 12], 15, 16, [18, 25], [27, 29], [31, 35], 37, 38, [40, 44]], true ], // criteria ids
|
||||
'crs' => [FILTER_V_LIST, [FILTER_ENUM_NONE, FILTER_ENUM_ANY, [0, 9999]], true ], // criteria operators
|
||||
'crv' => [FILTER_V_REGEX, '/[\p{C}:;%\\\\]/ui', true ], // criteria values - only printable chars, no delimiter
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name / subname - only printable chars, no delimiter
|
||||
'ex' => [FILTER_V_EQUAL, 'on', false], // also match subname
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'fa' => [FILTER_V_CALLBACK, 'cbPetFamily', true ], // pet family [list] - cat[0] == 1
|
||||
'minle' => [FILTER_V_RANGE, [1, 99], false], // min level [int]
|
||||
'maxle' => [FILTER_V_RANGE, [1, 99], false], // max level [int]
|
||||
'cl' => [FILTER_V_RANGE, [0, 4], true ], // classification [list]
|
||||
'ra' => [FILTER_V_LIST, [-1, 0, 1], false], // react alliance [int]
|
||||
'rh' => [FILTER_V_LIST, [-1, 0, 1], false] // react horde [int]
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
if (in_array($cr[0], array_keys($this->genericFilter)))
|
||||
{
|
||||
if ($genCr = $this->genericCriterion($cr))
|
||||
return $genCr;
|
||||
|
||||
@@ -359,6 +304,197 @@ class CreatureListFilter extends Filter
|
||||
return [1];
|
||||
}
|
||||
|
||||
switch ($cr[0])
|
||||
{
|
||||
case 1: // health [num]
|
||||
if (!$this->isSaneNumeric($cr[2]) || !$this->int2Op($cr[1]))
|
||||
break;
|
||||
|
||||
// remap OP for this special case
|
||||
switch ($cr[1])
|
||||
{
|
||||
case '=': // min > max is totally possible
|
||||
$this->extraOpts['ct']['h'][] = 'healthMin = healthMax AND healthMin = '.$cr[2];
|
||||
break;
|
||||
case '>':
|
||||
$this->extraOpts['ct']['h'][] = 'IF(healthMin > healthMax, healthMax, healthMin) > '.$cr[2];
|
||||
break;
|
||||
case '>=':
|
||||
$this->extraOpts['ct']['h'][] = 'IF(healthMin > healthMax, healthMax, healthMin) >= '.$cr[2];
|
||||
break;
|
||||
case '<':
|
||||
$this->extraOpts['ct']['h'][] = 'IF(healthMin > healthMax, healthMin, healthMax) < '.$cr[2];
|
||||
break;
|
||||
case '<=':
|
||||
$this->extraOpts['ct']['h'][] = 'IF(healthMin > healthMax, healthMin, healthMax) <= '.$cr[2];
|
||||
break;
|
||||
}
|
||||
return [1]; // always true, use post-filter
|
||||
case 2: // mana [num]
|
||||
if (!$this->isSaneNumeric($cr[2]) || !$this->int2Op($cr[1]))
|
||||
break;
|
||||
|
||||
// remap OP for this special case
|
||||
switch ($cr[1])
|
||||
{
|
||||
case '=':
|
||||
$this->extraOpts['ct']['h'][] = 'manaMin = manaMax AND manaMin = '.$cr[2];
|
||||
break;
|
||||
case '>':
|
||||
$this->extraOpts['ct']['h'][] = 'IF(manaMin > manaMax, manaMin, manaMax) > '.$cr[2];
|
||||
break;
|
||||
case '>=':
|
||||
$this->extraOpts['ct']['h'][] = 'IF(manaMin > manaMax, manaMin, manaMax) >= '.$cr[2];
|
||||
break;
|
||||
case '<':
|
||||
$this->extraOpts['ct']['h'][] = 'IF(manaMin > manaMax, manaMax, manaMin) < '.$cr[2];
|
||||
break;
|
||||
case '<=':
|
||||
$this->extraOpts['ct']['h'][] = 'IF(manaMin > manaMax, manaMax, manaMin) <= '.$cr[2];
|
||||
break;
|
||||
}
|
||||
return [1]; // always true, use post-filter
|
||||
case 7: // startsquest [enum]
|
||||
switch ($cr[1])
|
||||
{
|
||||
case 1: // any
|
||||
return ['AND', ['qse.method', 0x1, '&'], ['qse.questId', null, '!']];
|
||||
case 2: // alliance
|
||||
return ['AND', ['qse.method', 0x1, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_HORDE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&']];
|
||||
case 3: // horde
|
||||
return ['AND', ['qse.method', 0x1, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']];
|
||||
case 4: // both
|
||||
return ['AND', ['qse.method', 0x1, '&'], ['qse.questId', null, '!'], ['OR', ['AND', ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']], ['qt.reqRaceMask', 0]]];
|
||||
case 5: // none
|
||||
$this->extraOpts['ct']['h'][] = 'startsQuests = 0';
|
||||
return [1];
|
||||
}
|
||||
break;
|
||||
case 8: // endsquest [enum]
|
||||
switch ($cr[1])
|
||||
{
|
||||
case 1: // any
|
||||
return ['AND', ['qse.method', 0x2, '&'], ['qse.questId', null, '!']];
|
||||
case 2: // alliance
|
||||
return ['AND', ['qse.method', 0x2, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_HORDE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&']];
|
||||
case 3: // horde
|
||||
return ['AND', ['qse.method', 0x2, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']];
|
||||
case 4: // both
|
||||
return ['AND', ['qse.method', 0x2, '&'], ['qse.questId', null, '!'], ['OR', ['AND', ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']], ['qt.reqRaceMask', 0]]];
|
||||
case 5: // none
|
||||
$this->extraOpts['ct']['h'][] = 'endsQuests = 0';
|
||||
return [1];
|
||||
}
|
||||
break;
|
||||
case 3: // faction [enum]
|
||||
if (in_array($cr[1], $this->enums[$cr[0]]))
|
||||
{
|
||||
$facTpls = [];
|
||||
$facs = new FactionList(array('OR', ['parentFactionId', $cr[1]], ['id', $cr[1]]));
|
||||
foreach ($facs->iterate() as $__)
|
||||
$facTpls = array_merge($facTpls, $facs->getField('templateIds'));
|
||||
|
||||
if (!$facTpls)
|
||||
return [0];
|
||||
|
||||
return ['faction', $facTpls];
|
||||
}
|
||||
break;
|
||||
case 38; // relatedevent
|
||||
if (!$this->isSaneNumeric($cr[1]))
|
||||
break;
|
||||
|
||||
if ($cr[1] == FILTER_ENUM_ANY)
|
||||
{
|
||||
$eventIds = DB::Aowow()->selectCol('SELECT id FROM ?_events WHERE holidayId <> 0');
|
||||
$cGuids = DB::World()->selectCol('SELECT DISTINCT guid FROM game_event_creature WHERE eventEntry IN (?a)', $eventIds);
|
||||
return ['s.guid', $cGuids];
|
||||
}
|
||||
else if ($cr[1] == FILTER_ENUM_NONE)
|
||||
{
|
||||
$eventIds = DB::Aowow()->selectCol('SELECT id FROM ?_events WHERE holidayId <> 0');
|
||||
$cGuids = DB::World()->selectCol('SELECT DISTINCT guid FROM game_event_creature WHERE eventEntry IN (?a)', $eventIds);
|
||||
return ['s.guid', $cGuids, '!'];
|
||||
}
|
||||
else if ($cr[1])
|
||||
{
|
||||
$eventIds = DB::Aowow()->selectCol('SELECT id FROM ?_events WHERE holidayId = ?d', $cr[1]);
|
||||
$cGuids = DB::World()->selectCol('SELECT DISTINCT guid FROM game_event_creature WHERE eventEntry IN (?a)', $eventIds);
|
||||
return ['s.guid', $cGuids];
|
||||
}
|
||||
|
||||
break;
|
||||
case 42: // increasesrepwith [enum]
|
||||
if (in_array($cr[1], $this->enums[3])) // reuse
|
||||
{
|
||||
if ($cIds = DB::World()->selectCol('SELECT creature_id FROM creature_onkill_reputation WHERE (RewOnKillRepFaction1 = ?d AND RewOnKillRepValue1 > 0) OR (RewOnKillRepFaction2 = ?d AND RewOnKillRepValue2 > 0)', $cr[1], $cr[1]))
|
||||
return ['id', $cIds];
|
||||
else
|
||||
return [0];
|
||||
}
|
||||
|
||||
break;
|
||||
case 43: // decreasesrepwith [enum]
|
||||
if (in_array($cr[1], $this->enums[3])) // reuse
|
||||
{
|
||||
if ($cIds = DB::World()->selectCol('SELECT creature_id FROM creature_onkill_reputation WHERE (RewOnKillRepFaction1 = ?d AND RewOnKillRepValue1 < 0) OR (RewOnKillRepFaction2 = ?d AND RewOnKillRepValue2 < 0)', $cr[1], $cr[1]))
|
||||
return ['id', $cIds];
|
||||
else
|
||||
return [0];
|
||||
}
|
||||
|
||||
break;
|
||||
case 12: // averagemoneydropped [op] [int]
|
||||
if (!$this->isSaneNumeric($cr[2]) || !$this->int2Op($cr[1]))
|
||||
break;
|
||||
|
||||
return ['AND', ['((minGold + maxGold) / 2)', $cr[2], $cr[1]]];
|
||||
case 15: // gatherable [yn]
|
||||
if ($this->int2Bool($cr[1]))
|
||||
{
|
||||
if ($cr[1])
|
||||
return ['AND', ['skinLootId', 0, '>'], ['typeFlags', NPC_TYPEFLAG_HERBLOOT, '&']];
|
||||
else
|
||||
return ['OR', ['skinLootId', 0], [['typeFlags', NPC_TYPEFLAG_HERBLOOT, '&'], 0]];
|
||||
}
|
||||
break;
|
||||
case 44: // salvageable [yn]
|
||||
if ($this->int2Bool($cr[1]))
|
||||
{
|
||||
if ($cr[1])
|
||||
return ['AND', ['skinLootId', 0, '>'], ['typeFlags', NPC_TYPEFLAG_ENGINEERLOOT, '&']];
|
||||
else
|
||||
return ['OR', ['skinLootId', 0], [['typeFlags', NPC_TYPEFLAG_ENGINEERLOOT, '&'], 0]];
|
||||
}
|
||||
break;
|
||||
case 16: // minable [yn]
|
||||
if ($this->int2Bool($cr[1]))
|
||||
{
|
||||
if ($cr[1])
|
||||
return ['AND', ['skinLootId', 0, '>'], ['typeFlags', NPC_TYPEFLAG_MININGLOOT, '&']];
|
||||
else
|
||||
return ['OR', ['skinLootId', 0], [['typeFlags', NPC_TYPEFLAG_MININGLOOT, '&'], 0]];
|
||||
}
|
||||
break;
|
||||
case 10: // skinnable [yn]
|
||||
if ($this->int2Bool($cr[1]))
|
||||
{
|
||||
if ($cr[1])
|
||||
return ['AND', ['skinLootId', 0, '>'], [['typeFlags', NPC_TYPEFLAG_SPECIALLOOT, '&'], 0]];
|
||||
else
|
||||
return ['OR', ['skinLootId', 0], [['typeFlags', NPC_TYPEFLAG_SPECIALLOOT, '&'], 0, '!']];
|
||||
}
|
||||
break;
|
||||
case 34: // usemodel [str] // displayId -> id:creatureDisplayInfo.dbc/model -> id:cratureModelData.dbc/modelPath
|
||||
case 41: // haslocation [yn] [staff]
|
||||
/* todo */ return [1];
|
||||
}
|
||||
|
||||
unset($cr);
|
||||
$this->error = true;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
@@ -379,176 +515,65 @@ class CreatureListFilter extends Filter
|
||||
|
||||
// pet family [list]
|
||||
if (isset($_v['fa']))
|
||||
$parts[] = ['family', $_v['fa']];
|
||||
{
|
||||
$_ = (array)$_v['fa'];
|
||||
if (!array_diff($_, [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 20, 21, 24, 25, 26, 27, 30, 31, 32, 33, 34, 35, 37, 38, 39, 41, 42, 43, 44, 45, 46]))
|
||||
$parts[] = ['family', $_];
|
||||
else
|
||||
unset($_v['cl']);
|
||||
}
|
||||
|
||||
// creatureLevel min [int]
|
||||
if (isset($_v['minle']))
|
||||
{
|
||||
if (is_int($_v['minle']) && $_v['minle'] > 0)
|
||||
$parts[] = ['minLevel', $_v['minle'], '>='];
|
||||
else
|
||||
unset($_v['minle']);
|
||||
}
|
||||
|
||||
// creatureLevel max [int]
|
||||
if (isset($_v['maxle']))
|
||||
{
|
||||
if (is_int($_v['maxle']) && $_v['maxle'] > 0)
|
||||
$parts[] = ['maxLevel', $_v['maxle'], '<='];
|
||||
else
|
||||
unset($_v['maxle']);
|
||||
}
|
||||
|
||||
// classification [list]
|
||||
if (isset($_v['cl']))
|
||||
$parts[] = ['rank', $_v['cl']];
|
||||
{
|
||||
$_ = (array)$_v['cl'];
|
||||
if (!array_diff($_, [0, 1, 2, 3, 4]))
|
||||
$parts[] = ['rank', $_];
|
||||
else
|
||||
unset($_v['cl']);
|
||||
}
|
||||
|
||||
// react Alliance [int]
|
||||
if (isset($_v['ra']))
|
||||
$parts[] = ['ft.A', $_v['ra']];
|
||||
{
|
||||
$_ = (int)$_v['ra'];
|
||||
if (in_array($_, [-1, 0, 1]))
|
||||
$parts[] = ['ft.A', $_];
|
||||
else
|
||||
unset($_v['ra']);
|
||||
}
|
||||
|
||||
// react Horde [int]
|
||||
if (isset($_v['rh']))
|
||||
$parts[] = ['ft.H', $_v['rh']];
|
||||
{
|
||||
$_ = (int)$_v['rh'];
|
||||
if (in_array($_, [-1, 0, 1]))
|
||||
$parts[] = ['ft.H', $_];
|
||||
else
|
||||
unset($_v['rh']);
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbPetFamily(&$val)
|
||||
{
|
||||
if (!$this->parentCats || $this->parentCats[0] != 1)
|
||||
return false;
|
||||
|
||||
if (!Util::checkNumeric($val, NUM_REQ_INT))
|
||||
return false;
|
||||
|
||||
$type = FILTER_V_LIST;
|
||||
$valid = [[1, 9], 11, 12, 20, 21, [24, 27], [30, 35], [37, 39], [41, 46]];
|
||||
|
||||
return $this->checkInput($type, $valid, $val);
|
||||
}
|
||||
|
||||
protected function cbRelEvent($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[1], NUM_REQ_INT))
|
||||
return false;
|
||||
|
||||
if ($cr[1] == FILTER_ENUM_ANY)
|
||||
{
|
||||
$eventIds = DB::Aowow()->selectCol('SELECT id FROM ?_events WHERE holidayId <> 0');
|
||||
$cGuids = DB::World()->selectCol('SELECT DISTINCT guid FROM game_event_creature WHERE eventEntry IN (?a)', $eventIds);
|
||||
return ['s.guid', $cGuids];
|
||||
}
|
||||
else if ($cr[1] == FILTER_ENUM_NONE)
|
||||
{
|
||||
$eventIds = DB::Aowow()->selectCol('SELECT id FROM ?_events WHERE holidayId <> 0');
|
||||
$cGuids = DB::World()->selectCol('SELECT DISTINCT guid FROM game_event_creature WHERE eventEntry IN (?a)', $eventIds);
|
||||
return ['s.guid', $cGuids, '!'];
|
||||
}
|
||||
else if ($cr[1])
|
||||
{
|
||||
$eventIds = DB::Aowow()->selectCol('SELECT id FROM ?_events WHERE holidayId = ?d', $cr[1]);
|
||||
$cGuids = DB::World()->selectCol('SELECT DISTINCT guid FROM game_event_creature WHERE eventEntry IN (?a)', $eventIds);
|
||||
return ['s.guid', $cGuids];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbMoneyDrop($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
return ['AND', ['((minGold + maxGold) / 2)', $cr[2], $cr[1]]];
|
||||
}
|
||||
|
||||
protected function cbQuestRelation($cr, $field, $val)
|
||||
{
|
||||
switch ($cr[1])
|
||||
{
|
||||
case 1: // any
|
||||
return ['AND', ['qse.method', $val, '&'], ['qse.questId', null, '!']];
|
||||
case 2: // alliance
|
||||
return ['AND', ['qse.method', $val, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_HORDE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&']];
|
||||
case 3: // horde
|
||||
return ['AND', ['qse.method', $val, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']];
|
||||
case 4: // both
|
||||
return ['AND', ['qse.method', $val, '&'], ['qse.questId', null, '!'], ['OR', ['AND', ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']], ['qt.reqRaceMask', 0]]];
|
||||
case 5: // none
|
||||
$this->extraOpts['ct']['h'][] = $field.' = 0';
|
||||
return [1];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbHealthMana($cr, $minField, $maxField)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
// remap OP for this special case
|
||||
switch ($cr[1])
|
||||
{
|
||||
case '=': // min > max is totally possible
|
||||
$this->extraOpts['ct']['h'][] = $minField.' = '.$maxField.' AND '.$minField.' = '.$cr[2];
|
||||
break;
|
||||
case '>':
|
||||
case '>=':
|
||||
case '<':
|
||||
case '<=':
|
||||
$this->extraOpts['ct']['h'][] = 'IF('.$minField.' > '.$maxField.', '.$maxField.', '.$minField.') '.$cr[1].' '.$cr[2];
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return [1]; // always true, use post-filter
|
||||
}
|
||||
|
||||
protected function cbSpecialSkinLoot($cr, $typeFlag)
|
||||
{
|
||||
if (!$this->int2Bool($cr[1]))
|
||||
return false;
|
||||
|
||||
|
||||
if ($cr[1])
|
||||
return ['AND', ['skinLootId', 0, '>'], ['typeFlags', $typeFlag, '&']];
|
||||
else
|
||||
return ['OR', ['skinLootId', 0], [['typeFlags', $typeFlag, '&'], 0]];
|
||||
}
|
||||
|
||||
protected function cbRegularSkinLoot($cr, $typeFlag)
|
||||
{
|
||||
if (!$this->int2Bool($cr[1]))
|
||||
return false;
|
||||
|
||||
if ($cr[1])
|
||||
return ['AND', ['skinLootId', 0, '>'], [['typeFlags', $typeFlag, '&'], 0]];
|
||||
else
|
||||
return ['OR', ['skinLootId', 0], ['typeFlags', $typeFlag, '&']];
|
||||
}
|
||||
|
||||
protected function cbReputation($cr, $op)
|
||||
{
|
||||
if (!in_array($cr[1], $this->enums[3])) // reuse
|
||||
return false;
|
||||
|
||||
if ($_ = DB::Aowow()->selectRow('SELECT * FROM ?_factions WHERE id = ?d', $cr[1]))
|
||||
$this->formData['reputationCols'][] = [$cr[1], Util::localizedString($_, 'name')];
|
||||
|
||||
if ($cIds = DB::World()->selectCol('SELECT creature_id FROM creature_onkill_reputation WHERE (RewOnKillRepFaction1 = ?d AND RewOnKillRepValue1 '.$op.' 0) OR (RewOnKillRepFaction2 = ?d AND RewOnKillRepValue2 '.$op.' 0)', $cr[1], $cr[1]))
|
||||
return ['id', $cIds];
|
||||
else
|
||||
return [0];
|
||||
}
|
||||
|
||||
protected function cbFaction($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[1], NUM_REQ_INT))
|
||||
return false;
|
||||
|
||||
if (!in_array($cr[1], $this->enums[$cr[0]]))
|
||||
return false;
|
||||
|
||||
|
||||
$facTpls = [];
|
||||
$facs = new FactionList(array('OR', ['parentFactionId', $cr[1]], ['id', $cr[1]]));
|
||||
foreach ($facs->iterate() as $__)
|
||||
$facTpls = array_merge($facTpls, $facs->getField('templateIds'));
|
||||
|
||||
return $facTpls ? ['faction', $facTpls] : [0];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -6,26 +6,15 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class CurrencyList extends BaseType
|
||||
{
|
||||
public static $type = Type::CURRENCY;
|
||||
public static $type = TYPE_CURRENCY;
|
||||
public static $brickFile = 'currency';
|
||||
public static $dataTable = '?_currencies';
|
||||
|
||||
protected $queryBase = 'SELECT c.*, c.id AS ARRAY_KEY FROM ?_currencies c';
|
||||
protected $queryBase = 'SELECT *, c.id AS ARRAY_KEY FROM ?_currencies c';
|
||||
protected $queryOpts = array(
|
||||
'c' => [['ic']],
|
||||
'ic' => ['j' => ['?_icons ic ON ic.id = c.iconId', true], 's' => ', ic.name AS iconString']
|
||||
'ic' => ['j' => ['?_icons ic ON ic.id = c.iconId', true], 's' => ', ic.iconString']
|
||||
);
|
||||
|
||||
public function __construct($conditions = [])
|
||||
{
|
||||
parent::__construct($conditions);
|
||||
|
||||
foreach ($this->iterate() as &$_curTpl)
|
||||
if (!$_curTpl['iconString'])
|
||||
$_curTpl['iconString'] = 'inv_misc_questionmark';
|
||||
}
|
||||
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
$data = [];
|
||||
@@ -57,31 +46,13 @@ class CurrencyList extends BaseType
|
||||
else
|
||||
$icon = [$this->curTpl['iconString'], $this->curTpl['iconString']];
|
||||
|
||||
$data[Type::CURRENCY][$this->id] = ['name' => $this->getField('name', true), 'icon' => $icon];
|
||||
$data[TYPE_CURRENCY][$this->id] = ['name' => $this->getField('name', true), 'icon' => $icon];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function renderTooltip()
|
||||
{
|
||||
if (!$this->curTpl)
|
||||
return array();
|
||||
|
||||
$x = '<table><tr><td>';
|
||||
$x .= '<b>'.$this->getField('name', true).'</b><br>';
|
||||
|
||||
// cata+ (or go fill it by hand)
|
||||
if ($_ = $this->getField('description', true))
|
||||
$x .= '<div style="max-width: 300px" class="q">'.$_.'</div>';
|
||||
|
||||
if ($_ = $this->getField('cap'))
|
||||
$x .= '<br><span class="q">'.Lang::currency('cap').Lang::main('colon').'</span>'.Lang::nf($_).'<br>';
|
||||
|
||||
$x .= '</td></tr></table>';
|
||||
|
||||
return $x;
|
||||
}
|
||||
public function renderTooltip() { }
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class EmoteList extends BaseType
|
||||
{
|
||||
public static $type = Type::EMOTE;
|
||||
public static $brickFile = 'emote';
|
||||
public static $dataTable = '?_emotes';
|
||||
|
||||
protected $queryBase = 'SELECT e.*, e.id AS ARRAY_KEY FROM ?_emotes e';
|
||||
|
||||
public function __construct($conditions = [])
|
||||
{
|
||||
parent::__construct($conditions);
|
||||
|
||||
// post processing
|
||||
foreach ($this->iterate() as &$curTpl)
|
||||
{
|
||||
// remap for generic access
|
||||
$curTpl['name'] = $curTpl['cmd'];
|
||||
}
|
||||
}
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'id' => $this->curTpl['id'],
|
||||
'name' => $this->curTpl['cmd'],
|
||||
'preview' => $this->getField('self', true) ?: ($this->getField('noTarget', true) ?: $this->getField('target', true))
|
||||
);
|
||||
|
||||
// [nyi] sounds
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getJSGlobals($addMask = GLOBALINFO_ANY)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[Type::EMOTE][$this->id] = ['name' => $this->getField('cmd')];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function renderTooltip() { }
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,347 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class EnchantmentList extends BaseType
|
||||
{
|
||||
use listviewHelper;
|
||||
|
||||
public static $type = Type::ENCHANTMENT;
|
||||
public static $brickFile = 'enchantment';
|
||||
public static $dataTable = '?_itemenchantment';
|
||||
|
||||
private $jsonStats = [];
|
||||
private $relSpells = [];
|
||||
private $triggerIds = [];
|
||||
|
||||
protected $queryBase = 'SELECT ie.*, ie.id AS ARRAY_KEY FROM ?_itemenchantment ie';
|
||||
protected $queryOpts = array( // 502 => Type::ENCHANTMENT
|
||||
'ie' => [['is']],
|
||||
'is' => ['j' => ['?_item_stats `is` ON `is`.`type` = 502 AND `is`.`typeId` = `ie`.`id`', true], 's' => ', `is`.*'],
|
||||
);
|
||||
|
||||
public function __construct($conditions = [])
|
||||
{
|
||||
parent::__construct($conditions);
|
||||
|
||||
// post processing
|
||||
foreach ($this->iterate() as &$curTpl)
|
||||
{
|
||||
$curTpl['spells'] = []; // [spellId, triggerType, charges, chanceOrPpm]
|
||||
for ($i = 1; $i <=3; $i++)
|
||||
{
|
||||
if ($curTpl['object'.$i] <= 0)
|
||||
continue;
|
||||
|
||||
switch ($curTpl['type'.$i])
|
||||
{
|
||||
case 1:
|
||||
$proc = -$this->getField('ppmRate') ?: ($this->getField('procChance') ?: $this->getField('amount'.$i));
|
||||
$curTpl['spells'][$i] = [$curTpl['object'.$i], 2, $curTpl['charges'], $proc];
|
||||
$this->relSpells[] = $curTpl['object'.$i];
|
||||
break;
|
||||
case 3:
|
||||
$curTpl['spells'][$i] = [$curTpl['object'.$i], 1, $curTpl['charges'], 0];
|
||||
$this->relSpells[] = $curTpl['object'.$i];
|
||||
break;
|
||||
case 7:
|
||||
$curTpl['spells'][$i] = [$curTpl['object'.$i], 0, $curTpl['charges'], 0];
|
||||
$this->relSpells[] = $curTpl['object'.$i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// floats are fetched as string from db :<
|
||||
$curTpl['dmg'] = floatVal($curTpl['dmg']);
|
||||
$curTpl['dps'] = floatVal($curTpl['dps']);
|
||||
|
||||
// remove zero-stats
|
||||
foreach (Game::$itemMods as $str)
|
||||
if ($curTpl[$str] == 0) // empty(0.0f) => true .. yeah, sure
|
||||
unset($curTpl[$str]);
|
||||
|
||||
if ($curTpl['dps'] == 0)
|
||||
unset($curTpl['dps']);
|
||||
}
|
||||
|
||||
if ($this->relSpells)
|
||||
$this->relSpells = new SpellList(array(['id', $this->relSpells]));
|
||||
}
|
||||
|
||||
// use if you JUST need the name
|
||||
public static function getName($id)
|
||||
{
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8 FROM ?_itemenchantment WHERE id = ?d', $id );
|
||||
return Util::localizedString($n, 'name');
|
||||
}
|
||||
// end static use
|
||||
|
||||
public function getListviewData($addInfoMask = 0x0)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'id' => $this->id,
|
||||
'name' => $this->getField('name', true),
|
||||
'spells' => []
|
||||
);
|
||||
|
||||
if ($this->curTpl['skillLine'] > 0)
|
||||
$data[$this->id]['reqskill'] = $this->curTpl['skillLine'];
|
||||
|
||||
if ($this->curTpl['skillLevel'] > 0)
|
||||
$data[$this->id]['reqskillrank'] = $this->curTpl['skillLevel'];
|
||||
|
||||
if ($this->curTpl['requiredLevel'] > 0)
|
||||
$data[$this->id]['reqlevel'] = $this->curTpl['requiredLevel'];
|
||||
|
||||
foreach ($this->curTpl['spells'] as $s)
|
||||
{
|
||||
// enchant is procing or onUse
|
||||
if ($s[1] == 2 || $s[1] == 0)
|
||||
$data[$this->id]['spells'][$s[0]] = $s[2];
|
||||
// spell is procing
|
||||
else if ($this->relSpells && $this->relSpells->getEntry($s[0]) && ($_ = $this->relSpells->canTriggerSpell()))
|
||||
{
|
||||
foreach ($_ as $idx)
|
||||
{
|
||||
$this->triggerIds[] = $this->relSpells->getField('effect'.$idx.'TriggerSpell');
|
||||
$data[$this->id]['spells'][$this->relSpells->getField('effect'.$idx.'TriggerSpell')] = $s[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$data[$this->id]['spells'])
|
||||
unset($data[$this->id]['spells']);
|
||||
|
||||
Util::arraySumByKey($data[$this->id], $this->getStatGain());
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getStatGain($addScalingKeys = false)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach (Game::$itemMods as $str)
|
||||
if (isset($this->curTpl[$str]))
|
||||
$data[$str] = $this->curTpl[$str];
|
||||
|
||||
if (isset($this->curTpl['dps']))
|
||||
$data['dps'] = $this->curTpl['dps'];
|
||||
|
||||
// scaling enchantments are saved as 0 to item_stats, thus return empty
|
||||
if ($addScalingKeys)
|
||||
{
|
||||
$spellStats = [];
|
||||
if ($this->relSpells)
|
||||
$spellStats = $this->relSpells->getStatGain();
|
||||
|
||||
for ($h = 1; $h <= 3; $h++)
|
||||
{
|
||||
$obj = (int)$this->curTpl['object'.$h];
|
||||
|
||||
switch ($this->curTpl['type'.$h])
|
||||
{
|
||||
case 3: // TYPE_EQUIP_SPELL Spells from ObjectX (use of amountX?)
|
||||
if (!empty($spellStats[$obj]))
|
||||
foreach ($spellStats[$obj] as $mod => $_)
|
||||
if ($str = Game::$itemMods[$mod])
|
||||
Util::arraySumByKey($data, [$str => 0]);
|
||||
|
||||
$obj = null;
|
||||
break;
|
||||
case 4: // TYPE_RESISTANCE +AmountX resistance for ObjectX School
|
||||
switch ($obj)
|
||||
{
|
||||
case 0: // Physical
|
||||
$obj = ITEM_MOD_ARMOR;
|
||||
break;
|
||||
case 1: // Holy
|
||||
$obj = ITEM_MOD_HOLY_RESISTANCE;
|
||||
break;
|
||||
case 2: // Fire
|
||||
$obj = ITEM_MOD_FIRE_RESISTANCE;
|
||||
break;
|
||||
case 3: // Nature
|
||||
$obj = ITEM_MOD_NATURE_RESISTANCE;
|
||||
break;
|
||||
case 4: // Frost
|
||||
$obj = ITEM_MOD_FROST_RESISTANCE;
|
||||
break;
|
||||
case 5: // Shadow
|
||||
$obj = ITEM_MOD_SHADOW_RESISTANCE;
|
||||
break;
|
||||
case 6: // Arcane
|
||||
$obj = ITEM_MOD_ARCANE_RESISTANCE;
|
||||
break;
|
||||
default:
|
||||
$obj = null;
|
||||
}
|
||||
break;
|
||||
case 5: // TYPE_STAT +AmountX for Statistic by type of ObjectX
|
||||
if ($obj < 2) // [mana, health] are on [0, 1] respectively and are expected on [1, 2] ..
|
||||
$obj++; // 0 is weaponDmg .. ehh .. i messed up somewhere
|
||||
|
||||
break; // stats are directly assigned below
|
||||
default: // TYPE_NONE dnd stuff; skip assignment below
|
||||
$obj = null;
|
||||
}
|
||||
|
||||
if ($obj !== null)
|
||||
if ($str = Game::$itemMods[$obj]) // check if we use these mods
|
||||
Util::arraySumByKey($data, [$str => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getRelSpell($id)
|
||||
{
|
||||
if ($this->relSpells)
|
||||
return $this->relSpells->getEntry($id);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getJSGlobals($addMask = GLOBALINFO_ANY)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
if ($addMask & GLOBALINFO_SELF)
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[Type::ENCHANTMENT][$this->id] = ['name' => $this->getField('name', true)];
|
||||
|
||||
if ($addMask & GLOBALINFO_RELATED)
|
||||
{
|
||||
if ($this->relSpells)
|
||||
$data = $this->relSpells->getJSGlobals(GLOBALINFO_SELF);
|
||||
|
||||
foreach ($this->triggerIds as $tId)
|
||||
if (empty($data[Type::SPELL][$tId]))
|
||||
$data[Type::SPELL][$tId] = $tId;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function renderTooltip() { }
|
||||
}
|
||||
|
||||
|
||||
class EnchantmentListFilter extends Filter
|
||||
{
|
||||
protected $enums = array(
|
||||
3 => array( // requiresprof
|
||||
null, 171, 164, 185, 333, 202, 129, 755, 165, 186, 197, true, false, 356, 182, 773
|
||||
)
|
||||
);
|
||||
|
||||
protected $genericFilter = array( // misc (bool): _NUMERIC => useFloat; _STRING => localized; _FLAG => match Value; _BOOLEAN => stringSet
|
||||
2 => [FILTER_CR_NUMERIC, 'id', NUM_CAST_INT, true], // id
|
||||
3 => [FILTER_CR_ENUM, 'skillLine' ], // requiresprof
|
||||
4 => [FILTER_CR_NUMERIC, 'skillLevel', NUM_CAST_INT ], // reqskillrank
|
||||
5 => [FILTER_CR_BOOLEAN, 'conditionId' ], // hascondition
|
||||
10 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_COMMENT ], // hascomments
|
||||
11 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT ], // hasscreenshots
|
||||
12 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_VIDEO ], // hasvideos
|
||||
20 => [FILTER_CR_NUMERIC, 'is.str', NUM_CAST_INT, true], // str
|
||||
21 => [FILTER_CR_NUMERIC, 'is.agi', NUM_CAST_INT, true], // agi
|
||||
22 => [FILTER_CR_NUMERIC, 'is.sta', NUM_CAST_INT, true], // sta
|
||||
23 => [FILTER_CR_NUMERIC, 'is.int', NUM_CAST_INT, true], // int
|
||||
24 => [FILTER_CR_NUMERIC, 'is.spi', NUM_CAST_INT, true], // spi
|
||||
25 => [FILTER_CR_NUMERIC, 'is.arcres', NUM_CAST_INT, true], // arcres
|
||||
26 => [FILTER_CR_NUMERIC, 'is.firres', NUM_CAST_INT, true], // firres
|
||||
27 => [FILTER_CR_NUMERIC, 'is.natres', NUM_CAST_INT, true], // natres
|
||||
28 => [FILTER_CR_NUMERIC, 'is.frores', NUM_CAST_INT, true], // frores
|
||||
29 => [FILTER_CR_NUMERIC, 'is.shares', NUM_CAST_INT, true], // shares
|
||||
30 => [FILTER_CR_NUMERIC, 'is.holres', NUM_CAST_INT, true], // holres
|
||||
32 => [FILTER_CR_NUMERIC, 'is.dps', NUM_CAST_FLOAT, true], // dps
|
||||
34 => [FILTER_CR_NUMERIC, 'is.dmg', NUM_CAST_FLOAT, true], // dmg
|
||||
37 => [FILTER_CR_NUMERIC, 'is.mleatkpwr', NUM_CAST_INT, true], // mleatkpwr
|
||||
38 => [FILTER_CR_NUMERIC, 'is.rgdatkpwr', NUM_CAST_INT, true], // rgdatkpwr
|
||||
39 => [FILTER_CR_NUMERIC, 'is.rgdhitrtng', NUM_CAST_INT, true], // rgdhitrtng
|
||||
40 => [FILTER_CR_NUMERIC, 'is.rgdcritstrkrtng', NUM_CAST_INT, true], // rgdcritstrkrtng
|
||||
41 => [FILTER_CR_NUMERIC, 'is.armor' , NUM_CAST_INT, true], // armor
|
||||
42 => [FILTER_CR_NUMERIC, 'is.defrtng', NUM_CAST_INT, true], // defrtng
|
||||
43 => [FILTER_CR_NUMERIC, 'is.block', NUM_CAST_INT, true], // block
|
||||
44 => [FILTER_CR_NUMERIC, 'is.blockrtng', NUM_CAST_INT, true], // blockrtng
|
||||
45 => [FILTER_CR_NUMERIC, 'is.dodgertng', NUM_CAST_INT, true], // dodgertng
|
||||
46 => [FILTER_CR_NUMERIC, 'is.parryrtng', NUM_CAST_INT, true], // parryrtng
|
||||
48 => [FILTER_CR_NUMERIC, 'is.splhitrtng', NUM_CAST_INT, true], // splhitrtng
|
||||
49 => [FILTER_CR_NUMERIC, 'is.splcritstrkrtng', NUM_CAST_INT, true], // splcritstrkrtng
|
||||
50 => [FILTER_CR_NUMERIC, 'is.splheal', NUM_CAST_INT, true], // splheal
|
||||
51 => [FILTER_CR_NUMERIC, 'is.spldmg', NUM_CAST_INT, true], // spldmg
|
||||
52 => [FILTER_CR_NUMERIC, 'is.arcsplpwr', NUM_CAST_INT, true], // arcsplpwr
|
||||
53 => [FILTER_CR_NUMERIC, 'is.firsplpwr', NUM_CAST_INT, true], // firsplpwr
|
||||
54 => [FILTER_CR_NUMERIC, 'is.frosplpwr', NUM_CAST_INT, true], // frosplpwr
|
||||
55 => [FILTER_CR_NUMERIC, 'is.holsplpwr', NUM_CAST_INT, true], // holsplpwr
|
||||
56 => [FILTER_CR_NUMERIC, 'is.natsplpwr', NUM_CAST_INT, true], // natsplpwr
|
||||
57 => [FILTER_CR_NUMERIC, 'is.shasplpwr', NUM_CAST_INT, true], // shasplpwr
|
||||
60 => [FILTER_CR_NUMERIC, 'is.healthrgn', NUM_CAST_INT, true], // healthrgn
|
||||
61 => [FILTER_CR_NUMERIC, 'is.manargn', NUM_CAST_INT, true], // manargn
|
||||
77 => [FILTER_CR_NUMERIC, 'is.atkpwr', NUM_CAST_INT, true], // atkpwr
|
||||
78 => [FILTER_CR_NUMERIC, 'is.mlehastertng', NUM_CAST_INT, true], // mlehastertng
|
||||
79 => [FILTER_CR_NUMERIC, 'is.resirtng', NUM_CAST_INT, true], // resirtng
|
||||
84 => [FILTER_CR_NUMERIC, 'is.mlecritstrkrtng', NUM_CAST_INT, true], // mlecritstrkrtng
|
||||
94 => [FILTER_CR_NUMERIC, 'is.splpen', NUM_CAST_INT, true], // splpen
|
||||
95 => [FILTER_CR_NUMERIC, 'is.mlehitrtng', NUM_CAST_INT, true], // mlehitrtng
|
||||
96 => [FILTER_CR_NUMERIC, 'is.critstrkrtng', NUM_CAST_INT, true], // critstrkrtng
|
||||
97 => [FILTER_CR_NUMERIC, 'is.feratkpwr', NUM_CAST_INT, true], // feratkpwr
|
||||
101 => [FILTER_CR_NUMERIC, 'is.rgdhastertng', NUM_CAST_INT, true], // rgdhastertng
|
||||
102 => [FILTER_CR_NUMERIC, 'is.splhastertng', NUM_CAST_INT, true], // splhastertng
|
||||
103 => [FILTER_CR_NUMERIC, 'is.hastertng', NUM_CAST_INT, true], // hastertng
|
||||
114 => [FILTER_CR_NUMERIC, 'is.armorpenrtng', NUM_CAST_INT, true], // armorpenrtng
|
||||
115 => [FILTER_CR_NUMERIC, 'is.health', NUM_CAST_INT, true], // health
|
||||
116 => [FILTER_CR_NUMERIC, 'is.mana', NUM_CAST_INT, true], // mana
|
||||
117 => [FILTER_CR_NUMERIC, 'is.exprtng', NUM_CAST_INT, true], // exprtng
|
||||
119 => [FILTER_CR_NUMERIC, 'is.hitrtng', NUM_CAST_INT, true], // hitrtng
|
||||
123 => [FILTER_CR_NUMERIC, 'is.splpwr', NUM_CAST_INT, true] // splpwr
|
||||
);
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'cr' => [FILTER_V_RANGE, [2, 123], true ], // criteria ids
|
||||
'crs' => [FILTER_V_RANGE, [1, 15], true ], // criteria operators
|
||||
'crv' => [FILTER_V_RANGE, [0, 99999], true ], // criteria values - only numerals
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'ty' => [FILTER_V_RANGE, [1, 8], true ] // types
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
if (in_array($cr[0], array_keys($this->genericFilter)))
|
||||
if ($genCr = $this->genericCriterion($cr))
|
||||
return $genCr;
|
||||
|
||||
unset($cr);
|
||||
$this->error = true;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
$_v = &$this->fiData['v'];
|
||||
|
||||
//string
|
||||
if (isset($_v['na']))
|
||||
if ($_ = $this->modularizeString(['name_loc'.User::$localeId]))
|
||||
$parts[] = $_;
|
||||
|
||||
// type
|
||||
if (isset($_v['ty']))
|
||||
$parts[] = ['OR', ['type1', $_v['ty']], ['type2', $_v['ty']], ['type3', $_v['ty']]];
|
||||
|
||||
return $parts;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -6,9 +6,8 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class FactionList extends BaseType
|
||||
{
|
||||
public static $type = Type::FACTION;
|
||||
public static $type = TYPE_FACTION;
|
||||
public static $brickFile = 'faction';
|
||||
public static $dataTable = '?_factions';
|
||||
|
||||
protected $queryBase = 'SELECT f.*, f.parentFactionId AS cat, f.id AS ARRAY_KEY FROM ?_factions f';
|
||||
protected $queryOpts = array(
|
||||
@@ -37,7 +36,7 @@ class FactionList extends BaseType
|
||||
|
||||
public static function getName($id)
|
||||
{
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8 FROM ?_factions WHERE id = ?d', $id);
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc6, name_loc8 FROM ?_factions WHERE id = ?d', $id);
|
||||
return Util::localizedString($n, 'name');
|
||||
}
|
||||
|
||||
@@ -75,7 +74,7 @@ class FactionList extends BaseType
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[Type::FACTION][$this->id] = ['name' => $this->getField('name', true)];
|
||||
$data[TYPE_FACTION][$this->id] = ['name' => $this->getField('name', true)];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ class GameObjectList extends BaseType
|
||||
{
|
||||
use listviewHelper, spawnHelper;
|
||||
|
||||
public static $type = Type::OBJECT;
|
||||
public static $type = TYPE_OBJECT;
|
||||
public static $brickFile = 'object';
|
||||
public static $dataTable = '?_objects';
|
||||
|
||||
protected $queryBase = 'SELECT o.*, o.id AS ARRAY_KEY FROM ?_objects o';
|
||||
protected $queryOpts = array(
|
||||
@@ -31,9 +30,6 @@ class GameObjectList extends BaseType
|
||||
// post processing
|
||||
foreach ($this->iterate() as $_id => &$curTpl)
|
||||
{
|
||||
if (!$curTpl['name_loc0'])
|
||||
$curTpl['name_loc0'] = 'Unnamed Object #' . $_id;
|
||||
|
||||
// unpack miscInfo
|
||||
$curTpl['lootStack'] = [];
|
||||
$curTpl['spells'] = [];
|
||||
@@ -62,7 +58,7 @@ class GameObjectList extends BaseType
|
||||
|
||||
public static function getName($id)
|
||||
{
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8 FROM ?_objects WHERE id = ?d', $id);
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc6, name_loc8 FROM ?_objects WHERE id = ?d', $id);
|
||||
return Util::localizedString($n, 'name');
|
||||
}
|
||||
|
||||
@@ -96,14 +92,13 @@ class GameObjectList extends BaseType
|
||||
|
||||
$x = '<table>';
|
||||
$x .= '<tr><td><b class="q">'.$this->getField('name', true).'</b></td></tr>';
|
||||
if ($this->curTpl['typeCat'])
|
||||
if ($_ = Lang::gameObject('type', $this->curTpl['typeCat']))
|
||||
$x .= '<tr><td>'.$_.'</td></tr>';
|
||||
|
||||
if (isset($this->curTpl['lockId']))
|
||||
if ($locks = Lang::getLocks($this->curTpl['lockId']))
|
||||
foreach ($locks as $l)
|
||||
$x .= '<tr><td>'.sprintf(Lang::game('requires'), $l).'</td></tr>';
|
||||
$x .= '<tr><td>'.$l.'</td></tr>';
|
||||
|
||||
$x .= '</table>';
|
||||
|
||||
@@ -115,7 +110,7 @@ class GameObjectList extends BaseType
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[Type::OBJECT][$this->id] = ['name' => $this->getField('name', true)];
|
||||
$data[TYPE_OBJECT][$this->id] = ['name' => $this->getField('name', true)];
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -128,7 +123,7 @@ class GameObjectList extends BaseType
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'n' => $this->getField('name', true),
|
||||
't' => Type::OBJECT,
|
||||
't' => TYPE_OBJECT,
|
||||
'ti' => $this->id
|
||||
// 'bd' => bossdrop
|
||||
// 'dd' => dungeondifficulty
|
||||
@@ -143,43 +138,20 @@ class GameObjectList extends BaseType
|
||||
class GameObjectListFilter extends Filter
|
||||
{
|
||||
public $extraOpts = [];
|
||||
protected $enums = array(
|
||||
50 => array(
|
||||
null, 1, 2, 3, 4,
|
||||
663 => 663,
|
||||
883 => 883,
|
||||
FILTER_ENUM_ANY => true,
|
||||
FILTER_ENUM_NONE => false
|
||||
)
|
||||
);
|
||||
|
||||
protected $genericFilter = array(
|
||||
1 => [FILTER_CR_ENUM, 's.areaId', null ], // foundin
|
||||
2 => [FILTER_CR_CALLBACK, 'cbQuestRelation', 'startsQuests', 0x1 ], // startsquest [side]
|
||||
3 => [FILTER_CR_CALLBACK, 'cbQuestRelation', 'endsQuests', 0x2 ], // endsquest [side]
|
||||
4 => [FILTER_CR_CALLBACK, 'cbOpenable', null, null], // openable [yn]
|
||||
5 => [FILTER_CR_NYI_PH, null, null ], // averagemoneycontained [op] [int] - GOs don't contain money, match against 0
|
||||
7 => [FILTER_CR_NUMERIC, 'reqSkill', NUM_CAST_INT ], // requiredskilllevel
|
||||
7 => [FILTER_CR_NUMERIC, 'reqSkill', null ], // requiredskilllevel
|
||||
11 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT], // hasscreenshots
|
||||
13 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_COMMENT ], // hascomments
|
||||
15 => [FILTER_CR_NUMERIC, 'id', NUM_CAST_INT ], // id
|
||||
16 => [FILTER_CR_CALLBACK, 'cbRelEvent', null, null], // relatedevent (ignore removed by event)
|
||||
15 => [FILTER_CR_NUMERIC, 'id', null ], // id
|
||||
18 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_VIDEO ], // hasvideos
|
||||
50 => [FILTER_CR_ENUM, 'spellFocusId', null, ], // SpellFocus
|
||||
);
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'cr' => [FILTER_V_LIST, [[1, 5], 7, 11, 13, 15, 16, 18, 50], true ], // criteria ids
|
||||
'crs' => [FILTER_V_LIST, [FILTER_ENUM_NONE, FILTER_ENUM_ANY, [0, 5000]], true ], // criteria operators
|
||||
'crv' => [FILTER_V_RANGE, [0, 99999], true ], // criteria values - only numeric input values expected
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false] // match any / all filter
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
if (in_array($cr[0], array_keys($this->genericFilter)))
|
||||
{
|
||||
if ($genCR = $this->genericCriterion($cr))
|
||||
return $genCR;
|
||||
|
||||
@@ -188,51 +160,53 @@ class GameObjectListFilter extends Filter
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
switch ($cr[0])
|
||||
{
|
||||
$parts = [];
|
||||
$_v = $this->fiData['v'];
|
||||
case 4:
|
||||
if (!$this->int2Bool($cr[1]))
|
||||
break;
|
||||
|
||||
// name
|
||||
if (isset($_v['na']))
|
||||
if ($_ = $this->modularizeString(['name_loc'.User::$localeId]))
|
||||
$parts[] = $_;
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbOpenable($cr)
|
||||
{
|
||||
if ($this->int2Bool($cr[1]))
|
||||
return $cr[1] ? ['OR', ['flags', 0x2, '&'], ['type', 3]] : ['AND', [['flags', 0x2, '&'], 0], ['type', 3, '!']];
|
||||
case 5: // averagemoneycontained [op] [int] GOs don't contain money .. eval to 0 == true
|
||||
if (!$this->isSaneNumeric($cr[2], false) || !$this->int2Op($cr[1]))
|
||||
break;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbQuestRelation($cr, $field, $value)
|
||||
{
|
||||
return eval('return ('.$cr[2].' '.$cr[1].' 0)') ? [1] : [0];
|
||||
case 2: // startsquest [side]
|
||||
switch ($cr[1])
|
||||
{
|
||||
case 1: // any
|
||||
return ['AND', ['qse.method', $value, '&'], ['qse.questId', null, '!']];
|
||||
return ['AND', ['qse.method', 0x1, '&'], ['qse.questId', null, '!']];
|
||||
case 2: // alliance only
|
||||
return ['AND', ['qse.method', $value, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_HORDE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&']];
|
||||
return ['AND', ['qse.method', 0x1, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_HORDE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&']];
|
||||
case 3: // horde only
|
||||
return ['AND', ['qse.method', $value, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']];
|
||||
return ['AND', ['qse.method', 0x1, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']];
|
||||
case 4: // both
|
||||
return ['AND', ['qse.method', $value, '&'], ['qse.questId', null, '!'], ['OR', ['AND', ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']], ['qt.reqRaceMask', 0]]];
|
||||
case 5: // none todo (low): broken, if entry starts and ends quests...
|
||||
$this->extraOpts['o']['h'][] = $field.' = 0';
|
||||
return ['AND', ['qse.method', 0x1, '&'], ['qse.questId', null, '!'], ['OR', ['AND', ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']], ['qt.reqRaceMask', 0]]];
|
||||
case 5: // none
|
||||
$this->extraOpts['o']['h'][] = 'startsQuests = 0';
|
||||
return [1];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbRelEvent($cr)
|
||||
break;
|
||||
case 3: // endsquest [side]
|
||||
switch ($cr[1])
|
||||
{
|
||||
if (!Util::checkNumeric($cr[1], NUM_REQ_INT))
|
||||
return false;;
|
||||
case 1: // any
|
||||
return ['AND', ['qse.method', 0x2, '&'], ['qse.questId', null, '!']];
|
||||
case 2: // alliance only
|
||||
return ['AND', ['qse.method', 0x2, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_HORDE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&']];
|
||||
case 3: // horde only
|
||||
return ['AND', ['qse.method', 0x2, '&'], ['qse.questId', null, '!'], [['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], 0], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']];
|
||||
case 4: // both
|
||||
return ['AND', ['qse.method', 0x2, '&'], ['qse.questId', null, '!'], ['OR', ['AND', ['qt.reqRaceMask', RACE_MASK_ALLIANCE, '&'], ['qt.reqRaceMask', RACE_MASK_HORDE, '&']], ['qt.reqRaceMask', 0]]];
|
||||
case 5: // none todo: broken, if entry starts and ends quests...
|
||||
$this->extraOpts['o']['h'][] = 'endsQuests = 0';
|
||||
return [1];
|
||||
}
|
||||
break;
|
||||
case 16; // relatedevent (ignore removed by event)
|
||||
if (!$this->isSaneNumeric($cr[1]))
|
||||
break;
|
||||
|
||||
if ($cr[1] == FILTER_ENUM_ANY)
|
||||
{
|
||||
@@ -253,7 +227,25 @@ class GameObjectListFilter extends Filter
|
||||
return ['s.guid', $goGuids];
|
||||
}
|
||||
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
unset($cr);
|
||||
$this->error = 1;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
$_v = $this->fiData['v'];
|
||||
|
||||
// name
|
||||
if (isset($_v['na']))
|
||||
if ($_ = $this->modularizeString(['name_loc'.User::$localeId]))
|
||||
$parts[] = $_;
|
||||
|
||||
return $parts;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuideList extends BaseType
|
||||
{
|
||||
use ListviewHelper;
|
||||
|
||||
public const STATUS_COLORS = array(
|
||||
GUIDE_STATUS_DRAFT => '#71D5FF',
|
||||
GUIDE_STATUS_REVIEW => '#FFFF00',
|
||||
GUIDE_STATUS_APPROVED => '#1EFF00',
|
||||
GUIDE_STATUS_REJECTED => '#FF4040',
|
||||
GUIDE_STATUS_ARCHIVED => '#FFD100'
|
||||
);
|
||||
|
||||
public static $type = Type::GUIDE;
|
||||
public static $brickFile = 'guide';
|
||||
public static $dataTable = '?_guides';
|
||||
|
||||
private $article = [];
|
||||
private $jsGlobals = [];
|
||||
|
||||
protected $queryBase = 'SELECT g.*, g.id AS ARRAY_KEY FROM ?_guides g';
|
||||
protected $queryOpts = array(
|
||||
'g' => [['a', 'c'], 'g' => 'g.`id`'],
|
||||
'a' => ['j' => ['?_account a ON a.id = g.userId', true], 's' => ', IFNULL(a.displayName, "") AS author'],
|
||||
'c' => ['j' => ['?_comments c ON c.`type` = '.Type::GUIDE.' AND c.`typeId` = g.`id` AND (c.`flags` & '.CC_FLAG_DELETED.') = 0', true], 's' => ', COUNT(c.`id`) AS `comments`']
|
||||
);
|
||||
|
||||
public function __construct($conditions = [])
|
||||
{
|
||||
parent::__construct($conditions);
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
$ratings = DB::Aowow()->select('SELECT `entry` AS ARRAY_KEY, IFNULL(SUM(`value`), 0) AS `t`, IFNULL(COUNT(*), 0) AS `n`, IFNULL(MAX(IF(`userId` = ?d, `value`, 0)), 0) AS `s` FROM ?_user_ratings WHERE `type` = ?d AND `entry` IN (?a)', User::$id, RATING_GUIDE, $this->getFoundIDs());
|
||||
|
||||
// post processing
|
||||
foreach ($this->iterate() as $id => &$_curTpl)
|
||||
{
|
||||
if (isset($ratings[$id]))
|
||||
{
|
||||
$_curTpl['nvotes'] = $ratings[$id]['n'];
|
||||
$_curTpl['rating'] = $ratings[$id]['n'] < 5 ? -1 : $ratings[$id]['t'] / $ratings[$id]['n'];
|
||||
$_curTpl['_self'] = $ratings[$id]['s'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$_curTpl['nvotes'] = 0;
|
||||
$_curTpl['rating'] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getArticle(int $rev = -1) : string
|
||||
{
|
||||
if ($rev < -1)
|
||||
$rev = -1;
|
||||
|
||||
if (empty($this->article[$rev]))
|
||||
{
|
||||
$a = DB::Aowow()->selectRow('SELECT `article`, `rev` FROM ?_articles WHERE ((`type` = ?d AND `typeId` = ?d){ OR `url` = ?}){ AND `rev`= ?d} ORDER BY `rev` DESC LIMIT 1',
|
||||
Type::GUIDE, $this->id, $this->getField('url') ?: DBSIMPLE_SKIP, $rev < 0 ? DBSIMPLE_SKIP : $rev);
|
||||
|
||||
$this->article[$a['rev']] = $a['article'];
|
||||
if ($this->article[$a['rev']])
|
||||
{
|
||||
(new Markup($this->article[$a['rev']]))->parseGlobalsFromText($this->jsGlobals);
|
||||
return $this->article[$a['rev']];
|
||||
}
|
||||
else
|
||||
trigger_error('GuideList::getArticle - linked article is missing');
|
||||
}
|
||||
|
||||
return $this->article[$rev] ?? '';
|
||||
}
|
||||
|
||||
public function getListviewData(bool $addDescription = false) : array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'id' => $this->id,
|
||||
'category' => $this->getField('category'),
|
||||
'title' => $this->getField('title'),
|
||||
'description' => $this->getField('description'),
|
||||
'sticky' => !!($this->getField('cuFlags') & CC_FLAG_STICKY),
|
||||
'nvotes' => $this->getField('nvotes'),
|
||||
'url' => '/?guide=' . ($this->getField('url') ?: $this->id),
|
||||
'status' => $this->getField('status'),
|
||||
'author' => $this->getField('author'),
|
||||
'authorroles' => $this->getField('roles'),
|
||||
'rating' => $this->getField('rating'),
|
||||
'views' => $this->getField('views'),
|
||||
'comments' => $this->getField('comments'),
|
||||
// 'patch' => $this->getField(''), // 30305 - patch is pointless, use date instead
|
||||
'date' => $this->getField('date'), // ok
|
||||
'when' => date(Util::$dateFormatInternal, $this->getField('date'))
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function userCanView() : bool
|
||||
{
|
||||
// is owner || is staff
|
||||
return $this->getField('userId') == User::$id || User::isInGroup(U_GROUP_STAFF);
|
||||
}
|
||||
|
||||
public function canBeViewed() : bool
|
||||
{
|
||||
// currently approved || has prev. approved version
|
||||
return $this->getField('status') == GUIDE_STATUS_APPROVED || $this->getField('rev') > 0;
|
||||
}
|
||||
|
||||
public function canBeReported() : bool
|
||||
{
|
||||
// not own guide && is not archived
|
||||
return $this->getField('userId') != User::$id && $this->getField('status') != GUIDE_STATUS_ARCHIVED;
|
||||
}
|
||||
|
||||
public function getJSGlobals($addMask = GLOBALINFO_ANY) : array
|
||||
{
|
||||
return $this->jsGlobals;
|
||||
}
|
||||
|
||||
public function renderTooltip() : string
|
||||
{
|
||||
$specStr = '';
|
||||
|
||||
if ($this->getField('classId') && $this->getField('category') == 1)
|
||||
{
|
||||
$c = $this->getField('classId');
|
||||
if (($s = $this->getField('specId')) > -1)
|
||||
{
|
||||
$i = Game::$specIconStrings[$c][$s];
|
||||
$n = Lang::game('classSpecs', $c, $s);
|
||||
}
|
||||
else
|
||||
{
|
||||
$i = 'class_'.Game::$classFileStrings[$c];
|
||||
$n = Lang::game('cl', $c);
|
||||
}
|
||||
|
||||
$specStr = ' – <span class="icontiny c'.$c.'" style="background-image: url('.STATIC_URL.'/images/wow/icons/tiny/'.$i.'.gif)">'.$n.'</span>';
|
||||
}
|
||||
|
||||
$tt = '<table><tr><td><div style="max-width: 320px"><b class="q">'.$this->getField('title').'</b><br>';
|
||||
$tt .= '<table width="100%"><tr><td>'.Lang::guide('guide').'</td><th>'.Lang::guide('byAuthor', [$this->getField('author')]).'</th></tr></table>';
|
||||
$tt .= '<table width="100%"><tr><td>'.Lang::guide('category', $this->getField('category')).$specStr.'</td><th>'.Lang::guide('patch').' 3.3.5</th></tr></table>';
|
||||
$tt .= '<div class="q" style="margin: 0.25em 0">'.$this->getField('description').'</div>';
|
||||
$tt .= '</div></td></tr></table>';
|
||||
|
||||
return $tt;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,307 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class GuildList extends BaseType
|
||||
{
|
||||
use profilerHelper, listviewHelper;
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
$this->getGuildScores();
|
||||
|
||||
$data = [];
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'name' => '$"'.str_replace ('"', '', $this->curTpl['name']).'"', // MUST be a string, omit any quotes in name
|
||||
'members' => $this->curTpl['members'],
|
||||
'faction' => $this->curTpl['faction'],
|
||||
'achievementpoints' => $this->getField('achievementpoints'),
|
||||
'gearscore' => $this->getField('gearscore'),
|
||||
'realm' => Profiler::urlize($this->curTpl['realmName'], true),
|
||||
'realmname' => $this->curTpl['realmName'],
|
||||
// 'battlegroup' => Profiler::urlize($this->curTpl['battlegroup']), // was renamed to subregion somewhere around cata release
|
||||
// 'battlegroupname' => $this->curTpl['battlegroup'],
|
||||
'region' => Profiler::urlize($this->curTpl['region'])
|
||||
);
|
||||
}
|
||||
|
||||
return array_values($data);
|
||||
}
|
||||
|
||||
private function getGuildScores()
|
||||
{
|
||||
/*
|
||||
Guild gear scores and achievement points are derived using a weighted average of all of the known characters in that guild.
|
||||
Guilds with at least 25 level 80 players receive full benefit of the top 25 characters' gear scores, while guilds with at least 10 level 80 characters receive a slight penalty,
|
||||
at least 1 level 80 a moderate penalty, and no level 80 characters a severe penalty. [...]
|
||||
Instead of being based on level, achievement point averages are based around 1,500 points, but the same penalties apply.
|
||||
*/
|
||||
$guilds = array_column($this->templates, 'id');
|
||||
if (!$guilds)
|
||||
return;
|
||||
|
||||
$stats = DB::Aowow()->select('SELECT guild AS ARRAY_KEY, id AS ARRAY_KEY2, level, gearscore, achievementpoints, IF(cuFlags & ?d, 0, 1) AS synced FROM ?_profiler_profiles WHERE guild IN (?a) ORDER BY gearscore DESC', PROFILER_CU_NEEDS_RESYNC, $guilds);
|
||||
foreach ($this->iterate() as &$_curTpl)
|
||||
{
|
||||
$id = $_curTpl['id'];
|
||||
if (empty($stats[$id]))
|
||||
continue;
|
||||
|
||||
$guildStats = array_filter($stats[$id], function ($x) { return $x['synced']; } );
|
||||
if (!$guildStats)
|
||||
continue;
|
||||
|
||||
$nMaxLevel = count(array_filter($stats[$id], function ($x) { return $x['level'] >= MAX_LEVEL; } ));
|
||||
$levelMod = 1.0;
|
||||
|
||||
if ($nMaxLevel < 25)
|
||||
$levelMod = 0.85;
|
||||
if ($nMaxLevel < 10)
|
||||
$levelMod = 0.66;
|
||||
if ($nMaxLevel < 1)
|
||||
$levelMod = 0.20;
|
||||
|
||||
$totalGS = $totalAP = $nMembers = 0;
|
||||
foreach ($guildStats as $gs)
|
||||
{
|
||||
$totalGS += $gs['gearscore'] * $levelMod * min($gs['level'], MAX_LEVEL) / MAX_LEVEL;
|
||||
$totalAP += $gs['achievementpoints'] * $levelMod * min($gs['achievementpoints'], 1500) / 1500;
|
||||
$nMembers += min($gs['level'], MAX_LEVEL) / MAX_LEVEL;
|
||||
}
|
||||
|
||||
$_curTpl['gearscore'] = intval($totalGS / $nMembers);
|
||||
$_curTpl['achievementpoints'] = intval($totalAP / $nMembers);
|
||||
}
|
||||
}
|
||||
|
||||
public function renderTooltip() {}
|
||||
public function getJSGlobals($addMask = 0) {}
|
||||
}
|
||||
|
||||
|
||||
class GuildListFilter extends Filter
|
||||
{
|
||||
public $extraOpts = [];
|
||||
protected $genericFilter = [];
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'ex' => [FILTER_V_EQUAL, 'on', false], // only match exact
|
||||
'si' => [FILTER_V_LIST, [1, 2], false], // side
|
||||
'rg' => [FILTER_V_CALLBACK, 'cbRegionCheck', false], // region
|
||||
'sv' => [FILTER_V_CALLBACK, 'cbServerCheck', false], // server
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr) { }
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
$_v = $this->fiData['v'];
|
||||
|
||||
// region (rg), battlegroup (bg) and server (sv) are passed to GuildList as miscData and handled there
|
||||
|
||||
// name [str]
|
||||
if (!empty($_v['na']))
|
||||
if ($_ = $this->modularizeString(['g.name'], $_v['na'], !empty($_v['ex']) && $_v['ex'] == 'on'))
|
||||
$parts[] = $_;
|
||||
|
||||
// side [list]
|
||||
if (!empty($_v['si']))
|
||||
{
|
||||
if ($_v['si'] == 1)
|
||||
$parts[] = ['c.race', [1, 3, 4, 7, 11]];
|
||||
else if ($_v['si'] == 2)
|
||||
$parts[] = ['c.race', [2, 5, 6, 8, 10]];
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbRegionCheck(&$v)
|
||||
{
|
||||
if (in_array($v, Util::$regions))
|
||||
{
|
||||
$this->parentCats[0] = $v; // directly redirect onto this region
|
||||
$v = ''; // remove from filter
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbServerCheck(&$v)
|
||||
{
|
||||
foreach (Profiler::getRealms() as $realm)
|
||||
if ($realm['name'] == $v)
|
||||
{
|
||||
$this->parentCats[1] = Profiler::urlize($v);// directly redirect onto this server
|
||||
$v = ''; // remove from filter
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RemoteGuildList extends GuildList
|
||||
{
|
||||
protected $queryBase = 'SELECT `g`.*, `g`.`guildid` AS ARRAY_KEY FROM guild g';
|
||||
protected $queryOpts = array(
|
||||
'g' => [['gm', 'c'], 'g' => 'ARRAY_KEY'],
|
||||
'gm' => ['j' => 'guild_member gm ON gm.guildid = g.guildid', 's' => ', COUNT(1) AS members'],
|
||||
'c' => ['j' => 'characters c ON c.guid = gm.guid', 's' => ', BIT_OR(IF(c.race IN (1, 3, 4, 7, 11), 1, 2)) - 1 AS faction']
|
||||
);
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
// select DB by realm
|
||||
if (!$this->selectRealms($miscData))
|
||||
{
|
||||
trigger_error('no access to auth-db or table realmlist is empty', E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
parent::__construct($conditions, $miscData);
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
reset($this->dbNames); // only use when querying single realm
|
||||
$realmId = key($this->dbNames);
|
||||
$realms = Profiler::getRealms();
|
||||
$distrib = [];
|
||||
|
||||
// post processing
|
||||
foreach ($this->iterate() as $guid => &$curTpl)
|
||||
{
|
||||
// battlegroup
|
||||
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
|
||||
|
||||
$r = explode(':', $guid)[0];
|
||||
if (!empty($realms[$r]))
|
||||
{
|
||||
$curTpl['realm'] = $r;
|
||||
$curTpl['realmName'] = $realms[$r]['name'];
|
||||
$curTpl['region'] = $realms[$r]['region'];
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error('character "'.$curTpl['name'].'" belongs to nonexistant realm #'.$r, E_USER_WARNING);
|
||||
unset($this->templates[$guid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// equalize distribution
|
||||
if (empty($distrib[$curTpl['realm']]))
|
||||
$distrib[$curTpl['realm']] = 1;
|
||||
else
|
||||
$distrib[$curTpl['realm']]++;
|
||||
}
|
||||
|
||||
$limit = CFG_SQL_LIMIT_DEFAULT;
|
||||
foreach ($conditions as $c)
|
||||
if (is_int($c))
|
||||
$limit = $c;
|
||||
|
||||
$total = array_sum($distrib);
|
||||
foreach ($distrib as &$d)
|
||||
$d = ceil($limit * $d / $total);
|
||||
|
||||
foreach ($this->iterate() as $guid => &$curTpl)
|
||||
{
|
||||
if ($limit <= 0 || $distrib[$curTpl['realm']] <= 0)
|
||||
{
|
||||
unset($this->templates[$guid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$distrib[$curTpl['realm']]--;
|
||||
$limit--;
|
||||
}
|
||||
}
|
||||
|
||||
public function initializeLocalEntries()
|
||||
{
|
||||
$data = [];
|
||||
foreach ($this->iterate() as $guid => $__)
|
||||
{
|
||||
$data[$guid] = array(
|
||||
'realm' => $this->getField('realm'),
|
||||
'realmGUID' => $this->getField('guildid'),
|
||||
'name' => $this->getField('name'),
|
||||
'nameUrl' => Profiler::urlize($this->getField('name')),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
}
|
||||
|
||||
// basic guild data
|
||||
foreach (Util::createSqlBatchInsert($data) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_guild (?#) VALUES '.$ins, array_keys(reset($data)));
|
||||
|
||||
// merge back local ids
|
||||
$localIds = DB::Aowow()->selectCol(
|
||||
'SELECT CONCAT(realm, ":", realmGUID) AS ARRAY_KEY, id FROM ?_profiler_guild WHERE realm IN (?a) AND realmGUID IN (?a)',
|
||||
array_column($data, 'realm'),
|
||||
array_column($data, 'realmGUID')
|
||||
);
|
||||
|
||||
foreach ($this->iterate() as $guid => &$_curTpl)
|
||||
if (isset($localIds[$guid]))
|
||||
$_curTpl['id'] = $localIds[$guid];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LocalGuildList extends GuildList
|
||||
{
|
||||
protected $queryBase = 'SELECT g.*, g.id AS ARRAY_KEY FROM ?_profiler_guild g';
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
parent::__construct($conditions, $miscData);
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
$realms = Profiler::getRealms();
|
||||
|
||||
foreach ($this->iterate() as $id => &$curTpl)
|
||||
{
|
||||
if ($curTpl['realm'] && !isset($realms[$curTpl['realm']]))
|
||||
continue;
|
||||
|
||||
if (isset($realms[$curTpl['realm']]))
|
||||
{
|
||||
$curTpl['realmName'] = $realms[$curTpl['realm']]['name'];
|
||||
$curTpl['region'] = $realms[$curTpl['realm']]['region'];
|
||||
}
|
||||
|
||||
// battlegroup
|
||||
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
|
||||
}
|
||||
}
|
||||
|
||||
public function getProfileUrl()
|
||||
{
|
||||
$url = '?guild=';
|
||||
|
||||
return $url.implode('.', array(
|
||||
Profiler::urlize($this->getField('region')),
|
||||
Profiler::urlize($this->getField('realmName')),
|
||||
Profiler::urlize($this->getField('name'))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,237 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class IconList extends BaseType
|
||||
{
|
||||
use listviewHelper;
|
||||
|
||||
public static $type = Type::ICON;
|
||||
public static $brickFile = 'icon';
|
||||
public static $dataTable = '?_icons';
|
||||
public static $contribute = CONTRIBUTE_CO;
|
||||
|
||||
private $pseudoQry = 'SELECT iconId AS ARRAY_KEY, COUNT(*) FROM ?# WHERE iconId IN (?a) GROUP BY iconId';
|
||||
private $pseudoJoin = array(
|
||||
'nItems' => '?_items',
|
||||
'nSpells' => '?_spell',
|
||||
'nAchievements' => '?_achievement',
|
||||
'nCurrencies' => '?_currencies',
|
||||
'nPets' => '?_pet'
|
||||
);
|
||||
|
||||
protected $queryBase = 'SELECT ic.*, ic.id AS ARRAY_KEY FROM ?_icons ic';
|
||||
/* this works, but takes ~100x more time than i'm comfortable with .. kept as reference
|
||||
protected $queryOpts = array( // 29 => Type::ICON
|
||||
'ic' => [['s', 'i', 'a', 'c', 'p'], 'g' => 'ic.id'],
|
||||
'i' => ['j' => ['?_items `i` ON `i`.`iconId` = `ic`.`id`', true], 's' => ', COUNT(DISTINCT `i`.`id`) AS nItems'],
|
||||
's' => ['j' => ['?_spell `s` ON `s`.`iconId` = `ic`.`id`', true], 's' => ', COUNT(DISTINCT `s`.`id`) AS nSpells'],
|
||||
'a' => ['j' => ['?_achievement `a` ON `a`.`iconId` = `ic`.`id`', true], 's' => ', COUNT(DISTINCT `a`.`id`) AS nAchievements'],
|
||||
'c' => ['j' => ['?_currencies `c` ON `c`.`iconId` = `ic`.`id`', true], 's' => ', COUNT(DISTINCT `c`.`id`) AS nCurrencies'],
|
||||
'p' => ['j' => ['?_pet `p` ON `p`.`iconId` = `ic`.`id`', true], 's' => ', COUNT(DISTINCT `p`.`id`) AS nPets']
|
||||
);
|
||||
*/
|
||||
|
||||
public function __construct($conditions)
|
||||
{
|
||||
parent::__construct($conditions);
|
||||
|
||||
if (!$this->getFoundIDs())
|
||||
return;
|
||||
|
||||
foreach ($this->pseudoJoin as $var => $tbl)
|
||||
{
|
||||
$res = DB::Aowow()->selectCol($this->pseudoQry, $tbl, $this->getFoundIDs());
|
||||
foreach ($res as $icon => $qty)
|
||||
$this->templates[$icon][$var] = $qty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// use if you JUST need the name
|
||||
public static function getName($id)
|
||||
{
|
||||
$n = DB::Aowow()->SelectRow('SELECT name FROM ?_icons WHERE id = ?d', $id );
|
||||
return Util::localizedString($n, 'name');
|
||||
}
|
||||
// end static use
|
||||
|
||||
public function getListviewData($addInfoMask = 0x0)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'id' => $this->id,
|
||||
'name' => $this->getField('name', true, true),
|
||||
'icon' => $this->getField('name', true, true),
|
||||
'itemcount' => (int)$this->getField('nItems'),
|
||||
'spellcount' => (int)$this->getField('nSpells'),
|
||||
'achievementcount' => (int)$this->getField('nAchievements'),
|
||||
'npccount' => 0, // UNUSED
|
||||
'petabilitycount' => 0, // UNUSED
|
||||
'currencycount' => (int)$this->getField('nCurrencies'),
|
||||
'missionabilitycount' => 0, // UNUSED
|
||||
'buildingcount' => 0, // UNUSED
|
||||
'petcount' => (int)$this->getField('nPets'),
|
||||
'threatcount' => 0, // UNUSED
|
||||
'classcount' => 0 // class icons are hardcoded and not referenced in dbc
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getJSGlobals($addMask = GLOBALINFO_ANY)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[Type::ICON][$this->id] = ['name' => $this->getField('name', true, true), 'icon' => $this->getField('name', true, true)];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function renderTooltip() { }
|
||||
}
|
||||
|
||||
|
||||
class IconListFilter extends Filter
|
||||
{
|
||||
public $extraOpts = null;
|
||||
|
||||
// cr => [type, field, misc, extraCol]
|
||||
private $criterion2field = array(
|
||||
1 => '?_items', // items [num]
|
||||
2 => '?_spell', // spells [num]
|
||||
3 => '?_achievement', // achievements [num]
|
||||
// 4 => '', // battlepets [num]
|
||||
// 5 => '', // battlepetabilities [num]
|
||||
6 => '?_currencies', // currencies [num]
|
||||
// 7 => '', // garrisonabilities [num]
|
||||
// 8 => '', // garrisonbuildings [num]
|
||||
9 => '?_pet', // hunterpets [num]
|
||||
// 10 => '', // garrisonmissionthreats [num]
|
||||
11 => '', // classes [num]
|
||||
13 => '' // used [num]
|
||||
);
|
||||
private $totalUses = [];
|
||||
|
||||
protected $genericFilter = array(
|
||||
1 => [FILTER_CR_CALLBACK, 'cbUseAny' ], // items [num]
|
||||
2 => [FILTER_CR_CALLBACK, 'cbUseAny' ], // spells [num]
|
||||
3 => [FILTER_CR_CALLBACK, 'cbUseAny' ], // achievements [num]
|
||||
6 => [FILTER_CR_CALLBACK, 'cbUseAny' ], // currencies [num]
|
||||
9 => [FILTER_CR_CALLBACK, 'cbUseAny' ], // hunterpets [num]
|
||||
11 => [FILTER_CR_NYI_PH, null, null], // classes [num]
|
||||
13 => [FILTER_CR_CALLBACK, 'cbUseAll' ] // used [num]
|
||||
);
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'cr' => [FILTER_V_LIST, [1, 2, 3, 6, 9, 11, 13], true ], // criteria ids
|
||||
'crs' => [FILTER_V_RANGE, [1, 6], true ], // criteria operators
|
||||
'crv' => [FILTER_V_RANGE, [0, 99999], true ], // criteria values - all criteria are numeric here
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false] // match any / all filter
|
||||
);
|
||||
|
||||
private function _getCnd($op, $val, $tbl)
|
||||
{
|
||||
switch ($op)
|
||||
{
|
||||
case '>':
|
||||
case '>=':
|
||||
case '=':
|
||||
$ids = DB::Aowow()->selectCol('SELECT iconId AS ARRAY_KEY, COUNT(*) AS n FROM ?# GROUP BY iconId HAVING n '.$op.' '.$val, $tbl);
|
||||
return $ids ? ['id', array_keys($ids)] : [1];
|
||||
case '<=':
|
||||
if ($val)
|
||||
$op = '>';
|
||||
break;
|
||||
case '<':
|
||||
if ($val)
|
||||
$op = '>=';
|
||||
break;
|
||||
case '!=':
|
||||
if ($val)
|
||||
$op = '=';
|
||||
break;
|
||||
}
|
||||
|
||||
$ids = DB::Aowow()->selectCol('SELECT iconId AS ARRAY_KEY, COUNT(*) AS n FROM ?# GROUP BY iconId HAVING n '.$op.' '.$val, $tbl);
|
||||
return $ids ? ['id', array_keys($ids), '!'] : [1];
|
||||
}
|
||||
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
if (in_array($cr[0], array_keys($this->genericFilter)))
|
||||
if ($genCr = $this->genericCriterion($cr))
|
||||
return $genCr;
|
||||
|
||||
unset($cr);
|
||||
$this->error = true;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
$_v = &$this->fiData['v'];
|
||||
|
||||
//string
|
||||
if (isset($_v['na']))
|
||||
if ($_ = $this->modularizeString(['name']))
|
||||
$parts[] = $_;
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbUseAny($cr, $value)
|
||||
{
|
||||
if (Util::checkNumeric($cr[2], NUM_CAST_INT) && $this->int2Op($cr[1]))
|
||||
return $this->_getCnd($cr[1], $cr[2], $this->criterion2field[$cr[0]]);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbUseAll($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
if (!$this->totalUses)
|
||||
{
|
||||
foreach ($this->criterion2field as $tbl)
|
||||
{
|
||||
if (!$tbl)
|
||||
continue;
|
||||
|
||||
$res = DB::Aowow()->selectCol('SELECT iconId AS ARRAY_KEY, COUNT(*) AS n FROM ?# GROUP BY iconId', $tbl);
|
||||
Util::arraySumByKey($this->totalUses, $res);
|
||||
}
|
||||
}
|
||||
|
||||
if ($cr[1] == '=')
|
||||
$cr[1] = '==';
|
||||
|
||||
$op = $cr[1];
|
||||
if ($cr[1] == '<=' && $cr[2])
|
||||
$op = '>';
|
||||
else if ($cr[1] == '<' && $cr[2])
|
||||
$op = '>=';
|
||||
else if ($cr[1] == '!=' && $cr[2])
|
||||
$op = '==';
|
||||
$ids = array_filter($this->totalUses, function ($x) use ($op, $cr) { return eval('return '.$x.' '.$op.' '.$cr[2].';'); });
|
||||
|
||||
if ($cr[1] != $op)
|
||||
return $ids ? ['id', array_keys($ids), '!'] : [1];
|
||||
else
|
||||
return $ids ? ['id', array_keys($ids)] : ['id', array_keys($this->totalUses), '!'];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,18 +8,14 @@ class ItemsetList extends BaseType
|
||||
{
|
||||
use ListviewHelper;
|
||||
|
||||
public static $type = Type::ITEMSET;
|
||||
public static $type = TYPE_ITEMSET;
|
||||
public static $brickFile = 'itemset';
|
||||
public static $dataTable = '?_itemset';
|
||||
|
||||
public $pieceToSet = []; // used to build g_items and search
|
||||
private $classes = []; // used to build g_classes
|
||||
|
||||
protected $queryBase = 'SELECT `set`.*, `set`.id AS ARRAY_KEY FROM ?_itemset `set`';
|
||||
protected $queryOpts = array(
|
||||
'set' => ['o' => 'maxlevel DESC'],
|
||||
'e' => ['j' => ['?_events e ON e.id = `set`.eventId', true], 's' => ', e.holidayId']
|
||||
);
|
||||
protected $queryBase = 'SELECT *, id AS ARRAY_KEY FROM ?_itemset `set`';
|
||||
protected $queryOpts = ['set' => ['o' => 'maxlevel DESC']];
|
||||
|
||||
public function __construct($conditions = [])
|
||||
{
|
||||
@@ -80,91 +76,19 @@ class ItemsetList extends BaseType
|
||||
$data = [];
|
||||
|
||||
if ($this->classes && ($addMask & GLOBALINFO_RELATED))
|
||||
$data[Type::CHR_CLASS] = array_combine($this->classes, $this->classes);
|
||||
$data[TYPE_CLASS] = array_combine($this->classes, $this->classes);
|
||||
|
||||
if ($this->pieceToSet && ($addMask & GLOBALINFO_SELF))
|
||||
$data[Type::ITEM] = array_combine(array_keys($this->pieceToSet), array_keys($this->pieceToSet));
|
||||
$data[TYPE_ITEM] = array_combine(array_keys($this->pieceToSet), array_keys($this->pieceToSet));
|
||||
|
||||
if ($addMask & GLOBALINFO_SELF)
|
||||
foreach ($this->iterate() as $id => $__)
|
||||
$data[Type::ITEMSET][$id] = ['name' => $this->getField('name', true)];
|
||||
$data[TYPE_ITEMSET][$id] = ['name' => $this->getField('name', true)];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function renderTooltip()
|
||||
{
|
||||
if (!$this->curTpl)
|
||||
return array();
|
||||
|
||||
$x = '<table><tr><td>';
|
||||
$x .= '<span class="q'.$this->getField('quality').'">'.$this->getField('name', true).'</span><br />';
|
||||
|
||||
$nCl = 0;
|
||||
if ($_ = $this->getField('classMask'))
|
||||
{
|
||||
$jsg = [];
|
||||
$cl = Lang::getClassString($_, $jsg);
|
||||
$nCl = count($jsg);
|
||||
$x .= Util::ucFirst($nCl > 1 ? Lang::game('classes') : Lang::game('class')).Lang::main('colon').$cl.'<br />';
|
||||
}
|
||||
|
||||
if ($_ = $this->getField('contentGroup'))
|
||||
$x .= Lang::itemset('notes', $_).($this->getField('heroic') ? ' <i class="q2">('.Lang::item('heroic').')</i>' : '').'<br />';
|
||||
|
||||
if (!$nCl || !$this->getField('contentGroup'))
|
||||
$x.= Lang::itemset('types', $this->getField('type')).'<br />';
|
||||
|
||||
if ($bonuses = $this->getBonuses())
|
||||
{
|
||||
$x .= '<span>';
|
||||
|
||||
foreach ($bonuses as $b)
|
||||
$x .= '<br /><span class="q13">'.$b['bonus'].' '.Lang::itemset('_pieces').Lang::main('colon').'</span>'.$b['desc'];
|
||||
|
||||
$x .= '</span>';
|
||||
}
|
||||
|
||||
$x .= '</td></tr></table>';
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
public function getBonuses()
|
||||
{
|
||||
$spells = [];
|
||||
for ($i = 1; $i < 9; $i++)
|
||||
{
|
||||
$spl = $this->getField('spell'.$i);
|
||||
$qty = $this->getField('bonus'.$i);
|
||||
|
||||
// cant use spell as index, would change order
|
||||
if ($spl && $qty)
|
||||
$spells[] = ['id' => $spl, 'bonus' => $qty];
|
||||
}
|
||||
|
||||
// sort by required pieces ASC
|
||||
usort($spells, function($a, $b) {
|
||||
if ($a['bonus'] == $b['bonus'])
|
||||
return 0;
|
||||
|
||||
return ($a['bonus'] > $b['bonus']) ? 1 : -1;
|
||||
});
|
||||
|
||||
$setSpells = new SpellList(array(['s.id', array_column($spells, 'id')]));
|
||||
foreach ($setSpells->iterate() as $spellId => $__)
|
||||
{
|
||||
foreach ($spells as &$s)
|
||||
{
|
||||
if ($spellId != $s['id'])
|
||||
continue;
|
||||
|
||||
$s['desc'] = $setSpells->parseText('description', $this->getField('reqLevel') ?: MAX_LEVEL)[0];
|
||||
}
|
||||
}
|
||||
|
||||
return $spells;
|
||||
}
|
||||
public function renderTooltip() { }
|
||||
}
|
||||
|
||||
|
||||
@@ -173,37 +97,20 @@ class ItemsetListFilter extends Filter
|
||||
{
|
||||
// cr => [type, field, misc, extraCol]
|
||||
protected $genericFilter = array( // misc (bool): _NUMERIC => useFloat; _STRING => localized; _FLAG => match Value; _BOOLEAN => stringSet
|
||||
2 => [FILTER_CR_NUMERIC, 'id', NUM_CAST_INT, true], // id
|
||||
3 => [FILTER_CR_NUMERIC, 'npieces', NUM_CAST_INT ], // pieces
|
||||
4 => [FILTER_CR_STRING, 'bonusText', STR_LOCALIZED ], // bonustext
|
||||
2 => [FILTER_CR_NUMERIC, 'id', null, true], // id
|
||||
3 => [FILTER_CR_NUMERIC, 'npieces', ], // pieces
|
||||
4 => [FILTER_CR_STRING, 'bonusText', true ], // bonustext
|
||||
5 => [FILTER_CR_BOOLEAN, 'heroic', ], // heroic
|
||||
6 => [FILTER_CR_ENUM, 'e.holidayId', ], // relatedevent
|
||||
6 => [FILTER_CR_ENUM, 'holidayId', ], // relatedevent
|
||||
8 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_COMMENT ], // hascomments
|
||||
9 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT ], // hasscreenshots
|
||||
10 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_VIDEO ], // hasvideos
|
||||
12 => [FILTER_CR_NYI_PH, null, 1 ] // available to players [yn] - ugh .. scan loot, quest and vendor templates and write to ?_itemset
|
||||
);
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'cr' => [FILTER_V_RANGE, [2, 12], true ], // criteria ids
|
||||
'crs' => [FILTER_V_LIST, [FILTER_ENUM_NONE, FILTER_ENUM_ANY, [0, 424]], true ], // criteria operators
|
||||
'crv' => [FILTER_V_REGEX, '/[\p{C};:%\\\\]/ui', true ], // criteria values - only printable chars, no delimiters
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name / description - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'qu' => [FILTER_V_RANGE, [0, 7], true ], // quality
|
||||
'ty' => [FILTER_V_RANGE, [1, 12], true ], // set type
|
||||
'minle' => [FILTER_V_RANGE, [1, 999], false], // min item level
|
||||
'maxle' => [FILTER_V_RANGE, [1, 999], false], // max itemlevel
|
||||
'minrl' => [FILTER_V_RANGE, [1, MAX_LEVEL], false], // min required level
|
||||
'maxrl' => [FILTER_V_RANGE, [1, MAX_LEVEL], false], // max required level
|
||||
'cl' => [FILTER_V_LIST, [[1, 9], 11], false], // class
|
||||
'ta' => [FILTER_V_RANGE, [1, 30], false] // tag / content group
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
if (in_array($cr[0], array_keys($this->genericFilter)))
|
||||
{
|
||||
if ($genCR = $this->genericCriterion($cr))
|
||||
return $genCR;
|
||||
|
||||
@@ -212,6 +119,17 @@ class ItemsetListFilter extends Filter
|
||||
return [1];
|
||||
}
|
||||
|
||||
switch ($cr[0])
|
||||
{
|
||||
case 12: // available to players [yn] ugh .. scan loot, quest and vendor templates and write to ?_itemset
|
||||
/* todo */ return [1];
|
||||
}
|
||||
|
||||
unset($cr);
|
||||
$this->error = true;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
@@ -224,35 +142,65 @@ class ItemsetListFilter extends Filter
|
||||
|
||||
// quality [enum]
|
||||
if (isset($_v['qu']))
|
||||
$parts[] = ['quality', $_v['qu']];
|
||||
$parts[] = ['quality', (array)$_v['qu']];
|
||||
|
||||
// type [enum]
|
||||
if (isset($_v['ty']))
|
||||
$parts[] = ['type', $_v['ty']];
|
||||
$parts[] = ['type', (array)$_v['ty']];
|
||||
|
||||
// itemLevel min [int]
|
||||
if (isset($_v['minle']))
|
||||
{
|
||||
if (is_int($_v['minle']) && $_v['minle'] > 0)
|
||||
$parts[] = ['minLevel', $_v['minle'], '>='];
|
||||
else
|
||||
unset($_v['minle']);
|
||||
}
|
||||
|
||||
// itemLevel max [int]
|
||||
if (isset($_v['maxle']))
|
||||
{
|
||||
if (is_int($_v['maxle']) && $_v['maxle'] > 0)
|
||||
$parts[] = ['maxLevel', $_v['maxle'], '<='];
|
||||
else
|
||||
unset($_v['maxle']);
|
||||
}
|
||||
|
||||
// reqLevel min [int]
|
||||
if (isset($_v['minrl']))
|
||||
{
|
||||
if (is_int($_v['minrl']) && $_v['minrl'] > 0)
|
||||
$parts[] = ['reqLevel', $_v['minrl'], '>='];
|
||||
else
|
||||
unset($_v['minrl']);
|
||||
}
|
||||
|
||||
// reqLevel max [int]
|
||||
if (isset($_v['maxrl']))
|
||||
{
|
||||
if (is_int($_v['maxrl']) && $_v['maxrl'] > 0)
|
||||
$parts[] = ['reqLevel', $_v['maxrl'], '<='];
|
||||
else
|
||||
unset($_v['maxrl']);
|
||||
}
|
||||
|
||||
// class [enum]
|
||||
if (isset($_v['cl']))
|
||||
$parts[] = ['classMask', $this->list2Mask([$_v['cl']]), '&'];
|
||||
{
|
||||
if (in_array($_v['cl'], [1, 2, 3, 4, 5, 6, 7, 8, 9, 11]))
|
||||
$parts[] = ['classMask', $this->list2Mask($_v['cl']), '&'];
|
||||
else
|
||||
unset($_v['cl']);
|
||||
}
|
||||
|
||||
// tag [enum]
|
||||
if (isset($_v['ta']))
|
||||
{
|
||||
if ($_v['ta'] > 0 && $_v['ta'] < 31)
|
||||
$parts[] = ['contentGroup', intVal($_v['ta'])];
|
||||
else
|
||||
unset($_v['ta']);
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class MailList extends BaseType
|
||||
{
|
||||
public static $type = Type::MAIL;
|
||||
public static $brickFile = 'mail';
|
||||
public static $dataTable = '?_mails';
|
||||
|
||||
protected $queryBase = 'SELECT m.*, m.id AS ARRAY_KEY FROM ?_mails m';
|
||||
protected $queryOpts = [];
|
||||
|
||||
public function __construct($conditions = [])
|
||||
{
|
||||
parent::__construct($conditions);
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
// post processing
|
||||
foreach ($this->iterate() as $_id => &$_curTpl)
|
||||
{
|
||||
$_curTpl['name'] = Util::localizedString($_curTpl, 'subject', true);
|
||||
if (!$_curTpl['name'])
|
||||
{
|
||||
$_curTpl['name'] = sprintf(Lang::mail('untitled'), $_id);
|
||||
$_curTpl['subject_loc0'] = $_curTpl['name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getName($id)
|
||||
{
|
||||
$n = DB::Aowow()->SelectRow('SELECT subject_loc0, subject_loc2, subject_loc3, subject_loc4, subject_loc6, subject_loc8 FROM ?_mails WHERE id = ?d', $id);
|
||||
return Util::localizedString($n, 'subject');
|
||||
}
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$body = str_replace('[br]', ' ', Util::parseHtmlText($this->getField('text', true), true));
|
||||
|
||||
$data[$this->id] = array(
|
||||
'id' => $this->id,
|
||||
'subject' => $this->getField('subject', true),
|
||||
'body' => Lang::trimTextClean($body),
|
||||
'attachments' => [$this->getField('attachment')]
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getJSGlobals($addMask = 0)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
if ($a = $this->curTpl['attachment'])
|
||||
$data[Type::ITEM][$a] = $a;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function renderTooltip() { }
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -8,15 +8,10 @@ class PetList extends BaseType
|
||||
{
|
||||
use ListviewHelper;
|
||||
|
||||
public static $type = Type::PET;
|
||||
public static $type = TYPE_PET;
|
||||
public static $brickFile = 'pet';
|
||||
public static $dataTable = '?_pet';
|
||||
|
||||
protected $queryBase = 'SELECT p.*, p.id AS ARRAY_KEY FROM ?_pet p';
|
||||
protected $queryOpts = array(
|
||||
'p' => [['ic']],
|
||||
'ic' => ['j' => ['?_icons ic ON p.iconId = ic.id', true], 's' => ', ic.name AS iconString'],
|
||||
);
|
||||
protected $queryBase = 'SELECT *, id AS ARRAY_KEY FROM ?_pet p';
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
@@ -59,10 +54,10 @@ class PetList extends BaseType
|
||||
if ($addMask & GLOBALINFO_RELATED)
|
||||
for ($i = 1; $i <= 4; $i++)
|
||||
if ($this->curTpl['spellId'.$i] > 0)
|
||||
$data[Type::SPELL][$this->curTpl['spellId'.$i]] = $this->curTpl['spellId'.$i];
|
||||
$data[TYPE_SPELL][$this->curTpl['spellId'.$i]] = $this->curTpl['spellId'.$i];
|
||||
|
||||
if ($addMask & GLOBALINFO_SELF)
|
||||
$data[Type::PET][$this->id] = ['icon' => $this->curTpl['iconString']];
|
||||
$data[TYPE_PET][$this->id] = ['icon' => $this->curTpl['iconString']];
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
||||
@@ -4,324 +4,194 @@ if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// class CharacterList extends BaseType // new profiler-related parent: ProfilerType?; maybe a trait is enough => use ProfileHelper;
|
||||
// class GuildList extends BaseType
|
||||
// class ArenaTeamList extends BaseType
|
||||
class ProfileList extends BaseType
|
||||
{
|
||||
use profilerHelper, listviewHelper;
|
||||
public static $type = 0; // profiles dont actually have one
|
||||
public static $brickFile = 'profile';
|
||||
|
||||
public function getListviewData($addInfo = 0, array $reqCols = [])
|
||||
protected $queryBase = ''; // SELECT p.*, p.id AS ARRAY_KEY FROM ?_profiles p';
|
||||
protected $queryOpts = array(
|
||||
'p' => [['pa', 'pg']],
|
||||
'pam' => [['?_profiles_arenateam_member pam ON pam.memberId = p.id', true], 's' => ', pam.status'],
|
||||
'pa' => ['?_profiles_arenateam pa ON pa.id = pam.teamId', 's' => ', pa.mode, pa.name'],
|
||||
'pgm' => [['?_profiles_guid_member pgm ON pgm.memberId = p.Id', true], 's' => ', pgm.rankId'],
|
||||
'pg' => ['?_profiles_guild pg ON pg.if = pgm.guildId', 's' => ', pg.name']
|
||||
);
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
$character = array(
|
||||
'id' => 2,
|
||||
'name' => 'CharName',
|
||||
'region' => ['eu', 'Europe'],
|
||||
'battlegroup' => ['pure-pwnage', 'Pure Pwnage'],
|
||||
'realm' => ['dafuque', 'da\'Fuqúe'],
|
||||
'level' => 80,
|
||||
'classs' => 11,
|
||||
'race' => 6,
|
||||
'faction' => 1, // 0:alliance; 1:horde
|
||||
'gender' => 1, // 0:male, 1:female
|
||||
'skincolor' => 0, // playerbytes % 256
|
||||
'hairstyle' => 0, // (playerbytes >> 16) % 256
|
||||
'haircolor' => 0, // (playerbytes >> 24) % 256
|
||||
'facetype' => 0, // (playerbytes >> 8) % 256 [maybe features]
|
||||
'features' => 0, // playerBytes2 % 256 [maybe facetype]
|
||||
'source' => 2, // source: used if you create a profile from a genuine character. It inherites region, realm and bGroup
|
||||
'sourcename' => 'SourceCharName', // > if these three are false we get a 'genuine' profile [0 for genuine characters..?]
|
||||
'user' => 1, // > 'genuine' is the parameter for _isArmoryProfile(allowCustoms) ['' for genuine characters..?]
|
||||
'username' => 'TestUser', // > also, if 'source' <> 0, the char-icon is requestet via profile.php?avatar
|
||||
'published' => 1, // public / private
|
||||
'pinned' => 1, // usable for some utility funcs on site
|
||||
'nomodel' => 0x0, // unchecks DisplayOnCharacter by (1 << slotId - 1)
|
||||
'title' => 0, // titleId currently in use or null
|
||||
'guild' => 'GuildName', // only on chars; id or null
|
||||
'description' => 'this is a profile', // only on custom profiles
|
||||
'arenateams' => [], // [size(2|3|5) => DisplayName]; DisplayName gets urlized to use as link
|
||||
'playedtime' => 0, // exact to the day
|
||||
'lastupdated' => 0, // timestamp in ms
|
||||
'achievementpoints' => 0, // max you have
|
||||
'talents' => array(
|
||||
'builds' => array(
|
||||
['talents' => '', 'glyphs' => ''], // talents:string of 0-5 points; glyphs: itemIds.join(':')
|
||||
),
|
||||
'active' => 1 // 1|2
|
||||
),
|
||||
'customs' => [], // custom profiles created from this char; profileId => [name, ownerId, iconString(optional)]
|
||||
'skills' => [], // skillId => [curVal, maxVal]; can contain anything, should be limited to prim/sec professions
|
||||
'inventory' => [], // slotId => [itemId, subItemId, permEnchantId, tempEnchantId, gemItemId1, gemItemId2, gemItemId3, gemItemId4]
|
||||
'auras' => [], // custom list of buffs, debuffs [spellId]
|
||||
|
||||
// completion lists: [subjectId => amount/timestamp/1]
|
||||
'reputation' => [], // factionId => amount
|
||||
'titles' => [], // titleId => 1
|
||||
'spells' => [], // spellId => 1; recipes, pets, mounts
|
||||
'achievements' => [], // achievementId => timestamp
|
||||
'quests' => [], // questId => 1
|
||||
|
||||
// UNKNOWN
|
||||
'bookmarks' => [2], // UNK pinned or claimed userId => profileIds..?
|
||||
'statistics' => [], // UNK all statistics? [achievementId => killCount]
|
||||
'activity' => [], // UNK recent achievements? [achievementId => killCount]
|
||||
'glyphs' => [], // not really used .. i guess..?
|
||||
'pets' => array( // UNK
|
||||
[], // one array per pet, structure UNK
|
||||
),
|
||||
);
|
||||
|
||||
// parent::__construct($conditions, $miscData);
|
||||
@include('datasets/ProfilerExampleChar'); // tmp char data
|
||||
|
||||
$this->templates[2] = $character;
|
||||
$this->curTpl = $character;
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
// post processing
|
||||
// foreach ($this->iterate() as $_id => &$curTpl)
|
||||
// {
|
||||
// }
|
||||
}
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
$data = [];
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
if (!$this->isVisibleToUser())
|
||||
continue;
|
||||
|
||||
if (($addInfo & PROFILEINFO_PROFILE) && !$this->isCustom())
|
||||
continue;
|
||||
|
||||
if (($addInfo & PROFILEINFO_CHARACTER) && $this->isCustom())
|
||||
continue;
|
||||
$tDistrib = $this->getTalentDistribution();
|
||||
|
||||
$data[$this->id] = array(
|
||||
'id' => $this->getField('id'),
|
||||
'name' => $this->getField('name'),
|
||||
'race' => $this->getField('race'),
|
||||
'classs' => $this->getField('class'),
|
||||
'gender' => $this->getField('gender'),
|
||||
'level' => $this->getField('level'),
|
||||
'faction' => (1 << ($this->getField('race') - 1)) & RACE_MASK_ALLIANCE ? 0 : 1,
|
||||
'talenttree1' => $this->getField('talenttree1'),
|
||||
'talenttree2' => $this->getField('talenttree2'),
|
||||
'talenttree3' => $this->getField('talenttree3'),
|
||||
'talentspec' => $this->getField('activespec') + 1, // 0 => 1; 1 => 2
|
||||
'achievementpoints' => $this->getField('achievementpoints'),
|
||||
'guild' => '$"'.str_replace ('"', '', $this->curTpl['guildname']).'"',// force this to be a string
|
||||
'guildrank' => $this->getField('guildrank'),
|
||||
'realm' => Profiler::urlize($this->getField('realmName'), true),
|
||||
'realmname' => $this->getField('realmName'),
|
||||
// 'battlegroup' => Profiler::urlize($this->getField('battlegroup')), // was renamed to subregion somewhere around cata release
|
||||
// 'battlegroupname' => $this->getField('battlegroup'),
|
||||
'gearscore' => $this->getField('gearscore')
|
||||
'id' => 0,
|
||||
'name' => $this->curTpl['name'],
|
||||
'achievementpoints' => $this->curTpl['achievementpoints'],
|
||||
'guild' => $this->curTpl['guild'], // 0 if none
|
||||
'guildRank' => -1,
|
||||
'realm' => $this->curTpl['realm'][0],
|
||||
'realmname' => $this->curTpl['realm'][1],
|
||||
'battlegroup' => $this->curTpl['battlegroup'][0],
|
||||
'battlegroupname' => $this->curTpl['battlegroup'][0],
|
||||
'region' => $this->curTpl['region'][0],
|
||||
'level' => $this->curTpl['level'],
|
||||
'race' => $this->curTpl['race'],
|
||||
'gender' => $this->curTpl['gender'],
|
||||
'classs' => $this->curTpl['classs'],
|
||||
'faction' => $this->curTpl['faction'],
|
||||
'talenttree1' => $tDistrib[0],
|
||||
'talenttree2' => $tDistrib[1],
|
||||
'talenttree3' => $tDistrib[2],
|
||||
'talentspec' => $this->curTpl['talents']['active']
|
||||
);
|
||||
|
||||
if ($addInfo & PROFILEINFO_USER)
|
||||
$data[$this->id]['published'] = (int)!!($this->getField('cuFlags') & PROFILER_CU_PUBLISHED);
|
||||
if (!empty($this->curTpl['description']))
|
||||
$data[$this->id]['description'] = $this->curTpl['description'];
|
||||
|
||||
// for the lv this determins if the link is profile=<id> or profile=<region>.<realm>.<name>
|
||||
if (!$this->isCustom())
|
||||
$data[$this->id]['region'] = Profiler::urlize($this->getField('region'));
|
||||
if (!empty($this->curTpl['icon']))
|
||||
$data[$this->id]['icon'] = $this->curTpl['icon'];
|
||||
|
||||
if ($addInfo & PROFILEINFO_ARENA)
|
||||
{
|
||||
$data[$this->id]['rating'] = $this->getField('rating');
|
||||
$data[$this->id]['captain'] = $this->getField('captain');
|
||||
$data[$this->id]['games'] = $this->getField('seasonGames');
|
||||
$data[$this->id]['wins'] = $this->getField('seasonWins');
|
||||
}
|
||||
if ($this->curTpl['cuFlags'] & PROFILE_CU_PUBLISHED)
|
||||
$data[$this->id]['published'] = 1;
|
||||
|
||||
// Filter asked for skills - add them
|
||||
foreach ($reqCols as $col)
|
||||
$data[$this->id][$col] = $this->getField($col);
|
||||
|
||||
if ($addInfo & PROFILEINFO_PROFILE)
|
||||
{
|
||||
if ($_ = $this->getField('description'))
|
||||
$data[$this->id]['description'] = $_;
|
||||
|
||||
if ($_ = $this->getField('icon'))
|
||||
$data[$this->id]['icon'] = $_;
|
||||
}
|
||||
|
||||
if ($addInfo & PROFILEINFO_CHARACTER)
|
||||
if ($_ = $this->getField('renameItr'))
|
||||
$data[$this->id]['renameItr'] = $_;
|
||||
|
||||
if ($this->getField('cuFlags') & PROFILER_CU_PINNED)
|
||||
if ($this->curTpl['cuFlags'] & PROFILE_CU_PINNED)
|
||||
$data[$this->id]['pinned'] = 1;
|
||||
|
||||
if ($this->getField('cuFlags') & PROFILER_CU_DELETED)
|
||||
if ($this->curTpl['cuFlags'] & PROFILE_CU_DELETED)
|
||||
$data[$this->id]['deleted'] = 1;
|
||||
}
|
||||
|
||||
return array_values($data);
|
||||
}
|
||||
|
||||
public function renderTooltip()
|
||||
{
|
||||
if (!$this->curTpl)
|
||||
return [];
|
||||
|
||||
$title = '';
|
||||
$name = $this->getField('name');
|
||||
if ($_ = $this->getField('title'))
|
||||
$title = (new TitleList(array(['id', $_])))->getField($this->getField('gender') ? 'female' : 'male', true);
|
||||
|
||||
if ($this->isCustom())
|
||||
$name .= Lang::profiler('customProfile');
|
||||
else if ($title)
|
||||
$name = sprintf($title, $name);
|
||||
|
||||
$x = '<table>';
|
||||
$x .= '<tr><td><b class="q">'.$name.'</b></td></tr>';
|
||||
if ($g = $this->getField('guildname'))
|
||||
$x .= '<tr><td><'.$g.'></td></tr>';
|
||||
else if ($d = $this->getField('description'))
|
||||
$x .= '<tr><td>'.$d.'</td></tr>';
|
||||
$x .= '<tr><td>'.Lang::game('level').' '.$this->getField('level').' '.Lang::game('ra', $this->getField('race')).' '.Lang::game('cl', $this->getField('class')).'</td></tr>';
|
||||
$x .= '</table>';
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
public function getJSGlobals($addMask = 0)
|
||||
{
|
||||
$data = [];
|
||||
$realms = Profiler::getRealms();
|
||||
|
||||
foreach ($this->iterate() as $id => $__)
|
||||
{
|
||||
if (($addMask & PROFILEINFO_PROFILE) && $this->isCustom())
|
||||
{
|
||||
$profile = array(
|
||||
'id' => $this->getField('id'),
|
||||
'name' => $this->getField('name'),
|
||||
'race' => $this->getField('race'),
|
||||
'classs' => $this->getField('class'),
|
||||
'level' => $this->getField('level'),
|
||||
'gender' => $this->getField('gender')
|
||||
);
|
||||
|
||||
if ($_ = $this->getField('icon'))
|
||||
$profile['icon'] = $_;
|
||||
|
||||
$data[] = $profile;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($addMask & PROFILEINFO_CHARACTER && !$this->isCustom())
|
||||
{
|
||||
if (!isset($realms[$this->getField('realm')]))
|
||||
continue;
|
||||
|
||||
$data[] = array(
|
||||
'id' => $this->getField('id'),
|
||||
'name' => $this->getField('name'),
|
||||
'realmname' => $realms[$this->getField('realm')]['name'],
|
||||
'region' => $realms[$this->getField('realm')]['region'],
|
||||
'realm' => Profiler::urlize($realms[$this->getField('realm')]['name']),
|
||||
'race' => $this->getField('race'),
|
||||
'classs' => $this->getField('class'),
|
||||
'level' => $this->getField('level'),
|
||||
'gender' => $this->getField('gender'),
|
||||
'pinned' => $this->getField('cuFlags') & PROFILER_CU_PINNED ? 1 : 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function isCustom()
|
||||
public function renderTooltip($interactive = false)
|
||||
{
|
||||
return $this->getField('cuFlags') & PROFILER_CU_PROFILE;
|
||||
if (!$this->curTpl)
|
||||
return [];
|
||||
|
||||
$x = '<table>';
|
||||
$x .= '<tr><td><b class="q">'.$this->getField('name').'</b></td></tr>';
|
||||
if ($g = $this->getField('name'))
|
||||
$x .= '<tr><td><'.$g.'> ('.$this->getField('guildrank').')</td></tr>';
|
||||
else if ($d = $this->getField('description'))
|
||||
$x .= '<tr><td>'.$d.'</td></tr>';
|
||||
$x .= '<tr><td>'.Lang::game('level').' '.$this->getField('level').' '.Lang::game('ra', $this->curTpl['race']).' '.Lang::game('cl', $this->curTpl['classs']).'</td></tr>';
|
||||
$x .= '</table>';
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
public function isVisibleToUser()
|
||||
public function getJSGlobals($addMask = 0) {}
|
||||
|
||||
private function getTalentDistribution()
|
||||
{
|
||||
if (!$this->isCustom() || User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
return true;
|
||||
if (!empty($this->tDistribution))
|
||||
$this->tDistribution[$this->curTpl['classId']] = DB::Aowow()->selectCol('SELECT COUNT(t.id) FROM dbc_talent t JOIN dbc_talenttab tt ON t.tabId = tt.id WHERE tt.classMask & ?d GROUP BY tt.id ORDER BY tt.tabNumber ASC', 1 << ($this->curTpl['classId'] - 1));
|
||||
|
||||
if ($this->getField('cuFlags') & PROFILER_CU_DELETED)
|
||||
return false;
|
||||
|
||||
if (User::$id == $this->getField('user'))
|
||||
return true;
|
||||
|
||||
return (bool)($this->getField('cuFlags') & PROFILER_CU_PUBLISHED);
|
||||
$result = [];
|
||||
$start = 0;
|
||||
foreach ($this->tDistribution[$this->curTpl['classId']] as $len)
|
||||
{
|
||||
$result[] = array_sum(str_split(substr($this->curTpl['talentString'], $start, $len)));
|
||||
$start += $len;
|
||||
}
|
||||
|
||||
public function getIcon()
|
||||
{
|
||||
if ($_ = $this->getField('icon'))
|
||||
return $_;
|
||||
|
||||
$str = 'chr_';
|
||||
|
||||
switch ($this->getField('race'))
|
||||
{
|
||||
case 1: $str .= 'human_'; break;
|
||||
case 2: $str .= 'orc_'; break;
|
||||
case 3: $str .= 'dwarf_'; break;
|
||||
case 4: $str .= 'nightelf_'; break;
|
||||
case 5: $str .= 'scourge_'; break;
|
||||
case 6: $str .= 'tauren_'; break;
|
||||
case 7: $str .= 'gnome_'; break;
|
||||
case 8: $str .= 'troll_'; break;
|
||||
case 10: $str .= 'bloodelf_'; break;
|
||||
case 11: $str .= 'draenei_'; break;
|
||||
}
|
||||
|
||||
switch ($this->getField('gender'))
|
||||
{
|
||||
case 0: $str .= 'male_'; break;
|
||||
case 1: $str .= 'female_'; break;
|
||||
}
|
||||
|
||||
switch ($this->getField('class'))
|
||||
{
|
||||
case 1: $str .= 'warrior0'; break;
|
||||
case 2: $str .= 'paladin0'; break;
|
||||
case 3: $str .= 'hunter0'; break;
|
||||
case 4: $str .= 'rogue0'; break;
|
||||
case 5: $str .= 'priest0'; break;
|
||||
case 6: $str .= 'deathknight0'; break;
|
||||
case 7: $str .= 'shaman0'; break;
|
||||
case 8: $str .= 'mage0'; break;
|
||||
case 9: $str .= 'warlock0'; break;
|
||||
case 11: $str .= 'druid0'; break;
|
||||
}
|
||||
|
||||
$level = $this->getField('level');
|
||||
if ($level > 59)
|
||||
$str .= floor(($level - 60) / 10) + 2;
|
||||
else
|
||||
$str .= 1;
|
||||
|
||||
return $str;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ProfileListFilter extends Filter
|
||||
{
|
||||
public $useLocalList = false;
|
||||
public $extraOpts = [];
|
||||
|
||||
private $realms = [];
|
||||
|
||||
protected $enums = array(
|
||||
-1 => array( // arena team sizes
|
||||
// by name by rating by contrib
|
||||
12 => 2, 13 => 2, 14 => 2,
|
||||
15 => 3, 16 => 3, 17 => 3,
|
||||
18 => 5, 19 => 5, 20 => 5
|
||||
)
|
||||
protected $genericFilter = array(
|
||||
);
|
||||
|
||||
protected $genericFilter = array( // misc (bool): _NUMERIC => useFloat; _STRING => localized; _FLAG => match Value; _BOOLEAN => stringSet
|
||||
2 => [FILTER_CR_NUMERIC, 'gearscore', NUM_CAST_INT ], // gearscore [num]
|
||||
3 => [FILTER_CR_CALLBACK, 'cbAchievs', null, null], // achievementpoints [num]
|
||||
5 => [FILTER_CR_NUMERIC, 'talenttree1', NUM_CAST_INT ], // talenttree1 [num]
|
||||
6 => [FILTER_CR_NUMERIC, 'talenttree2', NUM_CAST_INT ], // talenttree2 [num]
|
||||
7 => [FILTER_CR_NUMERIC, 'talenttree3', NUM_CAST_INT ], // talenttree3 [num]
|
||||
9 => [FILTER_CR_STRING, 'g.name', ], // guildname
|
||||
10 => [FILTER_CR_CALLBACK, 'cbHasGuildRank', null, null], // guildrank
|
||||
12 => [FILTER_CR_CALLBACK, 'cbTeamName', null, null], // teamname2v2
|
||||
15 => [FILTER_CR_CALLBACK, 'cbTeamName', null, null], // teamname3v3
|
||||
18 => [FILTER_CR_CALLBACK, 'cbTeamName', null, null], // teamname5v5
|
||||
13 => [FILTER_CR_CALLBACK, 'cbTeamRating', null, null], // teamrtng2v2
|
||||
16 => [FILTER_CR_CALLBACK, 'cbTeamRating', null, null], // teamrtng3v3
|
||||
19 => [FILTER_CR_CALLBACK, 'cbTeamRating', null, null], // teamrtng5v5
|
||||
14 => [FILTER_CR_NYI_PH, 0 ], // teamcontrib2v2 [num]
|
||||
17 => [FILTER_CR_NYI_PH, 0 ], // teamcontrib3v3 [num]
|
||||
20 => [FILTER_CR_NYI_PH, 0 ], // teamcontrib5v5 [num]
|
||||
21 => [FILTER_CR_CALLBACK, 'cbWearsItems', null, null], // wearingitem [str]
|
||||
23 => [FILTER_CR_CALLBACK, 'cbCompletedAcv', null, null], // completedachievement
|
||||
25 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_ALCHEMY, null], // alchemy [num]
|
||||
26 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_BLACKSMITHING, null], // blacksmithing [num]
|
||||
27 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_ENCHANTING, null], // enchanting [num]
|
||||
28 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_ENGINEERING, null], // engineering [num]
|
||||
29 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_HERBALISM, null], // herbalism [num]
|
||||
30 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_INSCRIPTION, null], // inscription [num]
|
||||
31 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_JEWELCRAFTING, null], // jewelcrafting [num]
|
||||
32 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_LEATHERWORKING, null], // leatherworking [num]
|
||||
33 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_MINING, null], // mining [num]
|
||||
34 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_SKINNING, null], // skinning [num]
|
||||
35 => [FILTER_CR_CALLBACK, 'cbProfession', SKILL_TAILORING, null], // tailoring [num]
|
||||
36 => [FILTER_CR_CALLBACK, 'cbHasGuild', null, null] // hasguild [yn]
|
||||
);
|
||||
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'cr' => [FILTER_V_RANGE, [1, 36], true ], // criteria ids
|
||||
'crs' => [FILTER_V_LIST, [FILTER_ENUM_NONE, FILTER_ENUM_ANY, [0, 5000]], true ], // criteria operators
|
||||
'crv' => [FILTER_V_REGEX, '/[\p{C}:;%\\\\]/ui', true ], // criteria values
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name - only printable chars, no delimiter
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'ex' => [FILTER_V_EQUAL, 'on', false], // only match exact
|
||||
'si' => [FILTER_V_LIST, [1, 2], false], // side
|
||||
'ra' => [FILTER_V_LIST, [[1, 8], 10, 11], true ], // race
|
||||
'cl' => [FILTER_V_LIST, [[1, 9], 11], true ], // class
|
||||
'minle' => [FILTER_V_RANGE, [1, MAX_LEVEL], false], // min level
|
||||
'maxle' => [FILTER_V_RANGE, [1, MAX_LEVEL], false], // max level
|
||||
'rg' => [FILTER_V_CALLBACK, 'cbRegionCheck', false], // region
|
||||
'sv' => [FILTER_V_CALLBACK, 'cbServerCheck', false], // server
|
||||
);
|
||||
|
||||
/* heads up!
|
||||
a couple of filters are too complex to be run against the characters database
|
||||
if they are selected, force useage of LocalProfileList
|
||||
*/
|
||||
|
||||
public function __construct($fromPOST = false, $opts = [])
|
||||
{
|
||||
if (!empty($opts['realms']))
|
||||
$this->realms = $opts['realms'];
|
||||
else
|
||||
$this->realms = array_keys(Profiler::getRealms());
|
||||
|
||||
parent::__construct($fromPOST, $opts);
|
||||
|
||||
if (!empty($this->fiData['c']['cr']))
|
||||
if (array_intersect($this->fiData['c']['cr'], [2, 5, 6, 7, 21]))
|
||||
$this->useLocalList = true;
|
||||
}
|
||||
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
if (in_array($cr[0], array_keys($this->genericFilter)))
|
||||
{
|
||||
if ($genCR = $this->genericCriterion($cr))
|
||||
return $genCR;
|
||||
|
||||
@@ -330,464 +200,29 @@ class ProfileListFilter extends Filter
|
||||
return [1];
|
||||
}
|
||||
|
||||
switch ($cr[0])
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
unset($cr);
|
||||
$this->error = 1;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
$_v = $this->fiData['v'];
|
||||
|
||||
// region (rg), battlegroup (bg) and server (sv) are passed to ProflieList as miscData and handled there
|
||||
|
||||
// table key differs between remote and local :<
|
||||
$k = $this->useLocalList ? 'p' : 'c';
|
||||
|
||||
// name [str] - the table is case sensitive. Since i down't want to destroy indizes, lets alter the search terms
|
||||
if (!empty($_v['na']))
|
||||
{
|
||||
$lower = $this->modularizeString([$k.'.name'], Util::lower($_v['na']), !empty($_v['ex']) && $_v['ex'] == 'on', true);
|
||||
$proper = $this->modularizeString([$k.'.name'], Util::ucWords($_v['na']), !empty($_v['ex']) && $_v['ex'] == 'on', true);
|
||||
|
||||
$parts[] = ['OR', $lower, $proper];
|
||||
}
|
||||
|
||||
// side [list]
|
||||
if (!empty($_v['si']))
|
||||
{
|
||||
if ($_v['si'] == 1)
|
||||
$parts[] = [$k.'.race', [1, 3, 4, 7, 11]];
|
||||
else if ($_v['si'] == 2)
|
||||
$parts[] = [$k.'.race', [2, 5, 6, 8, 10]];
|
||||
}
|
||||
|
||||
// race [list]
|
||||
if (!empty($_v['ra']))
|
||||
$parts[] = [$k.'.race', $_v['ra']];
|
||||
|
||||
// class [list]
|
||||
if (!empty($_v['cl']))
|
||||
$parts[] = [$k.'.class', $_v['cl']];
|
||||
|
||||
// min level [int]
|
||||
if (isset($_v['minle']))
|
||||
$parts[] = [$k.'.level', $_v['minle'], '>='];
|
||||
|
||||
// max level [int]
|
||||
if (isset($_v['maxle']))
|
||||
$parts[] = [$k.'.level', $_v['maxle'], '<='];
|
||||
// name
|
||||
if (isset($_v['na']))
|
||||
if ($_ = $this->modularizeString(['name_loc'.User::$localeId]))
|
||||
$parts[] = $_;
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbRegionCheck(&$v)
|
||||
{
|
||||
if (in_array($v, Util::$regions))
|
||||
{
|
||||
$this->parentCats[0] = $v; // directly redirect onto this region
|
||||
$v = ''; // remove from filter
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbServerCheck(&$v)
|
||||
{
|
||||
foreach (Profiler::getRealms() as $realm)
|
||||
if ($realm['name'] == $v)
|
||||
{
|
||||
$this->parentCats[1] = Profiler::urlize($v);// directly redirect onto this server
|
||||
$v = ''; // remove from filter
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbProfession($cr, $skillId)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return;
|
||||
|
||||
$k = 'sk_'.Util::createHash(12);
|
||||
$col = 'skill'.$skillId;
|
||||
|
||||
$this->formData['extraCols'][$skillId] = $col;
|
||||
|
||||
if ($this->useLocalList)
|
||||
{
|
||||
$this->extraOpts[$k] = array(
|
||||
'j' => ['?_profiler_completion '.$k.' ON '.$k.'.id = p.id AND '.$k.'.`type` = '.Type::SKILL.' AND '.$k.'.typeId = '.$skillId.' AND '.$k.'.cur '.$cr[1].' '.$cr[2], true],
|
||||
's' => [', '.$k.'.cur AS '.$col]
|
||||
);
|
||||
return [$k.'.typeId', null, '!'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->extraOpts[$k] = array(
|
||||
'j' => ['character_skills '.$k.' ON '.$k.'.guid = c.guid AND '.$k.'.skill = '.$skillId.' AND '.$k.'.value '.$cr[1].' '.$cr[2], true],
|
||||
's' => [', '.$k.'.value AS '.$col]
|
||||
);
|
||||
return [$k.'.skill', null, '!'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function cbCompletedAcv($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT))
|
||||
return false;
|
||||
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_achievement WHERE id = ?d', $cr[2]))
|
||||
return false;
|
||||
|
||||
$k = 'acv_'.Util::createHash(12);
|
||||
|
||||
if ($this->useLocalList)
|
||||
{
|
||||
$this->extraOpts[$k] = ['j' => ['?_profiler_completion '.$k.' ON '.$k.'.id = p.id AND '.$k.'.`type` = '.Type::ACHIEVEMENT.' AND '.$k.'.typeId = '.$cr[2], true]];
|
||||
return [$k.'.typeId', null, '!'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->extraOpts[$k] = ['j' => ['character_achievement '.$k.' ON '.$k.'.guid = c.guid AND '.$k.'.achievement = '.$cr[2], true]];
|
||||
return [$k.'.achievement', null, '!'];
|
||||
}
|
||||
}
|
||||
|
||||
protected function cbWearsItems($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT))
|
||||
return false;
|
||||
|
||||
if (!DB::Aowow()->selectCell('SELECT 1 FROM ?_items WHERE id = ?d', $cr[2]))
|
||||
return false;
|
||||
|
||||
$k = 'i_'.Util::createHash(12);
|
||||
|
||||
$this->extraOpts[$k] = ['j' => ['?_profiler_items '.$k.' ON '.$k.'.id = p.id AND '.$k.'.item = '.$cr[2], true]];
|
||||
return [$k.'.item', null, '!'];
|
||||
}
|
||||
|
||||
protected function cbHasGuild($cr)
|
||||
{
|
||||
if (!$this->int2Bool($cr[1]))
|
||||
return false;
|
||||
|
||||
if ($this->useLocalList)
|
||||
return ['p.guild', null, $cr[1] ? '!' : null];
|
||||
else
|
||||
return ['gm.guildId', null, $cr[1] ? '!' : null];
|
||||
}
|
||||
|
||||
protected function cbHasGuildRank($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
if ($this->useLocalList)
|
||||
return ['p.guildrank', $cr[2], $cr[1]];
|
||||
else
|
||||
return ['gm.rank', $cr[2], $cr[1]];
|
||||
}
|
||||
|
||||
protected function cbTeamName($cr)
|
||||
{
|
||||
if ($_ = $this->modularizeString(['at.name'], $cr[2]))
|
||||
return ['AND', ['at.type', $this->enums[-1][$cr[0]]], $_];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbTeamRating($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
return ['AND', ['at.type', $this->enums[-1][$cr[0]]], ['at.rating', $cr[2], $cr[1]]];
|
||||
}
|
||||
|
||||
protected function cbAchievs($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
if ($this->useLocalList)
|
||||
return ['p.achievementpoints', $cr[2], $cr[1]];
|
||||
else
|
||||
return ['cap.counter', $cr[2], $cr[1]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RemoteProfileList extends ProfileList
|
||||
{
|
||||
protected $queryBase = 'SELECT `c`.*, `c`.`guid` AS ARRAY_KEY FROM characters c';
|
||||
protected $queryOpts = array(
|
||||
'c' => [['gm', 'g', 'cap']], // 12698: use criteria of Achievement 4496 as shortcut to get total achievement points
|
||||
'cap' => ['j' => ['character_achievement_progress cap ON cap.guid = c.guid AND cap.criteria = 12698', true], 's' => ', IFNULL(cap.counter, 0) AS achievementpoints'],
|
||||
'gm' => ['j' => ['guild_member gm ON gm.guid = c.guid', true], 's' => ', gm.rank AS guildrank'],
|
||||
'g' => ['j' => ['guild g ON g.guildid = gm.guildid', true], 's' => ', g.guildid AS guild, g.name AS guildname'],
|
||||
'atm' => ['j' => ['arena_team_member atm ON atm.guid = c.guid', true], 's' => ', atm.personalRating AS rating'],
|
||||
'at' => [['atm'], 'j' => 'arena_team at ON atm.arenaTeamId = at.arenaTeamId', 's' => ', at.name AS arenateam, IF(at.captainGuid = c.guid, 1, 0) AS captain']
|
||||
);
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
// select DB by realm
|
||||
if (!$this->selectRealms($miscData))
|
||||
{
|
||||
trigger_error('no access to auth-db or table realmlist is empty', E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
parent::__construct($conditions, $miscData);
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
reset($this->dbNames); // only use when querying single realm
|
||||
$realmId = key($this->dbNames);
|
||||
$realms = Profiler::getRealms();
|
||||
$talentSpells = [];
|
||||
$talentLookup = [];
|
||||
$distrib = null;
|
||||
$limit = CFG_SQL_LIMIT_DEFAULT;
|
||||
|
||||
foreach ($conditions as $c)
|
||||
if (is_int($c))
|
||||
$limit = $c;
|
||||
|
||||
// post processing
|
||||
foreach ($this->iterate() as $guid => &$curTpl)
|
||||
{
|
||||
// battlegroup
|
||||
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
|
||||
|
||||
// realm
|
||||
[$r, $g] = explode(':', $guid);
|
||||
if (!empty($realms[$r]))
|
||||
{
|
||||
$curTpl['realm'] = $r;
|
||||
$curTpl['realmName'] = $realms[$r]['name'];
|
||||
$curTpl['region'] = $realms[$r]['region'];
|
||||
}
|
||||
else
|
||||
{
|
||||
trigger_error('character "'.$curTpl['name'].'" belongs to nonexistant realm #'.$r, E_USER_WARNING);
|
||||
unset($this->templates[$guid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// temp id
|
||||
$curTpl['id'] = 0;
|
||||
|
||||
// talent points pre
|
||||
$talentLookup[$r][$g] = [];
|
||||
$talentSpells[] = $curTpl['class'];
|
||||
$curTpl['activespec'] = $curTpl['activeTalentGroup'];
|
||||
|
||||
// equalize distribution
|
||||
if ($limit != CFG_SQL_LIMIT_NONE)
|
||||
{
|
||||
if (empty($distrib[$curTpl['realm']]))
|
||||
$distrib[$curTpl['realm']] = 1;
|
||||
else
|
||||
$distrib[$curTpl['realm']]++;
|
||||
}
|
||||
|
||||
// char is pending rename
|
||||
if ($curTpl['at_login'] & 0x1)
|
||||
{
|
||||
if (!isset($this->rnItr[$curTpl['name']]))
|
||||
$this->rnItr[$curTpl['name']] = DB::Aowow()->selectCell('SELECT MAX(renameItr) FROM ?_profiler_profiles WHERE realm = ?d AND realmGUID IS NOT NULL AND name = ?', $r, $curTpl['name']) ?: 0;
|
||||
|
||||
// already saved as "pending rename"
|
||||
if ($rnItr = DB::Aowow()->selectCell('SELECT renameItr FROM ?_profiler_profiles WHERE realm = ?d AND realmGUID = ?d', $r, $g))
|
||||
$curTpl['renameItr'] = $rnItr;
|
||||
// not yet recognized: get max itr
|
||||
else
|
||||
$curTpl['renameItr'] = ++$this->rnItr[$curTpl['name']];
|
||||
}
|
||||
else
|
||||
$curTpl['renameItr'] = 0;
|
||||
|
||||
$curTpl['cuFlags'] = 0;
|
||||
}
|
||||
|
||||
foreach ($talentLookup as $realm => $chars)
|
||||
$talentLookup[$realm] = DB::Characters($realm)->selectCol('SELECT guid AS ARRAY_KEY, spell AS ARRAY_KEY2, talentGroup FROM character_talent ct WHERE guid IN (?a)', array_keys($chars));
|
||||
|
||||
$talentSpells = DB::Aowow()->select('SELECT spell AS ARRAY_KEY, tab, `rank` FROM ?_talents WHERE class IN (?a)', array_unique($talentSpells));
|
||||
|
||||
if ($distrib !== null)
|
||||
{
|
||||
$total = array_sum($distrib);
|
||||
foreach ($distrib as &$d)
|
||||
$d = ceil($limit * $d / $total);
|
||||
}
|
||||
|
||||
foreach ($this->iterate() as $guid => &$curTpl)
|
||||
{
|
||||
if ($distrib !== null)
|
||||
{
|
||||
if ($limit <= 0 || $distrib[$curTpl['realm']] <= 0)
|
||||
{
|
||||
unset($this->templates[$guid]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$distrib[$curTpl['realm']]--;
|
||||
$limit--;
|
||||
}
|
||||
|
||||
[$r, $g] = explode(':', $guid);
|
||||
|
||||
// talent points post
|
||||
$curTpl['talenttree1'] = 0;
|
||||
$curTpl['talenttree2'] = 0;
|
||||
$curTpl['talenttree3'] = 0;
|
||||
if (!empty($talentLookup[$r][$g]))
|
||||
{
|
||||
$talents = array_filter($talentLookup[$r][$g], function($v) use ($curTpl) { return $curTpl['activespec'] == $v; } );
|
||||
foreach (array_intersect_key($talentSpells, $talents) as $spell => $data)
|
||||
$curTpl['talenttree'.($data['tab'] + 1)] += $data['rank'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getListviewData($addInfoMask = 0, array $reqCols = [])
|
||||
{
|
||||
$data = parent::getListviewData($addInfoMask, $reqCols);
|
||||
|
||||
// not wanted on server list
|
||||
foreach ($data as &$d)
|
||||
unset($d['published']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function initializeLocalEntries()
|
||||
{
|
||||
$baseData = $guildData = [];
|
||||
foreach ($this->iterate() as $guid => $__)
|
||||
{
|
||||
$baseData[$guid] = array(
|
||||
'realm' => $this->getField('realm'),
|
||||
'realmGUID' => $this->getField('guid'),
|
||||
'name' => $this->getField('name'),
|
||||
'renameItr' => $this->getField('renameItr'),
|
||||
'race' => $this->getField('race'),
|
||||
'class' => $this->getField('class'),
|
||||
'level' => $this->getField('level'),
|
||||
'gender' => $this->getField('gender'),
|
||||
'guild' => $this->getField('guild') ?: null,
|
||||
'guildrank' => $this->getField('guild') ? $this->getField('guildrank') : null,
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
|
||||
if ($this->getField('guild'))
|
||||
$guildData[] = array(
|
||||
'realm' => $this->getField('realm'),
|
||||
'realmGUID' => $this->getField('guild'),
|
||||
'name' => $this->getField('guildname'),
|
||||
'nameUrl' => Profiler::urlize($this->getField('guildname')),
|
||||
'cuFlags' => PROFILER_CU_NEEDS_RESYNC
|
||||
);
|
||||
}
|
||||
|
||||
// basic guild data (satisfying table constraints)
|
||||
if ($guildData)
|
||||
{
|
||||
foreach (Util::createSqlBatchInsert($guildData) as $ins)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_guild (?#) VALUES '.$ins, array_keys(reset($guildData)));
|
||||
|
||||
// merge back local ids
|
||||
$localGuilds = DB::Aowow()->selectCol('SELECT realm AS ARRAY_KEY, realmGUID AS ARRAY_KEY2, id FROM ?_profiler_guild WHERE realm IN (?a) AND realmGUID IN (?a)',
|
||||
array_column($guildData, 'realm'), array_column($guildData, 'realmGUID')
|
||||
);
|
||||
|
||||
foreach ($baseData as &$bd)
|
||||
if ($bd['guild'])
|
||||
$bd['guild'] = $localGuilds[$bd['realm']][$bd['guild']];
|
||||
}
|
||||
|
||||
// basic char data (enough for tooltips)
|
||||
if ($baseData)
|
||||
{
|
||||
foreach (Util::createSqlBatchInsert($baseData) as $ins)
|
||||
DB::Aowow()->query('INSERT INTO ?_profiler_profiles (?#) VALUES '.$ins.' ON DUPLICATE KEY UPDATE name = VALUES(name), renameItr = VALUES(renameItr)', array_keys(reset($baseData)));
|
||||
|
||||
// merge back local ids
|
||||
$localIds = DB::Aowow()->select(
|
||||
'SELECT CONCAT(realm, ":", realmGUID) AS ARRAY_KEY, id, gearscore FROM ?_profiler_profiles WHERE (cuFlags & ?d) = 0 AND realm IN (?a) AND realmGUID IN (?a)',
|
||||
PROFILER_CU_PROFILE,
|
||||
array_column($baseData, 'realm'),
|
||||
array_column($baseData, 'realmGUID')
|
||||
);
|
||||
|
||||
foreach ($this->iterate() as $guid => &$_curTpl)
|
||||
if (isset($localIds[$guid]))
|
||||
$_curTpl = array_merge($_curTpl, $localIds[$guid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class LocalProfileList extends ProfileList
|
||||
{
|
||||
protected $queryBase = 'SELECT p.*, p.id AS ARRAY_KEY FROM ?_profiler_profiles p';
|
||||
protected $queryOpts = array(
|
||||
'p' => [['g'], 'g' => 'p.id'],
|
||||
'ap' => ['j' => ['?_account_profiles ap ON ap.profileId = p.id', true], 's' => ', (IFNULL(ap.ExtraFlags, 0) | p.cuFlags) AS cuFlags'],
|
||||
'atm' => ['j' => ['?_profiler_arena_team_member atm ON atm.profileId = p.id', true], 's' => ', atm.captain, atm.personalRating AS rating, atm.seasonGames, atm.seasonWins'],
|
||||
'at' => [['atm'], 'j' => ['?_profiler_arena_team at ON at.id = atm.arenaTeamId', true], 's' => ', at.type'],
|
||||
'g' => ['j' => ['?_profiler_guild g ON g.id = p.guild', true], 's' => ', g.name AS guildname']
|
||||
);
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
parent::__construct($conditions, $miscData);
|
||||
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
$realms = Profiler::getRealms();
|
||||
|
||||
// post processing
|
||||
$acvPoints = DB::Aowow()->selectCol('SELECT pc.id AS ARRAY_KEY, SUM(a.points) FROM ?_profiler_completion pc LEFT JOIN ?_achievement a ON a.id = pc.typeId WHERE pc.`type` = ?d AND pc.id IN (?a) GROUP BY pc.id', Type::ACHIEVEMENT, $this->getFoundIDs());
|
||||
|
||||
foreach ($this->iterate() as $id => &$curTpl)
|
||||
{
|
||||
if ($curTpl['realm'] && !isset($realms[$curTpl['realm']]))
|
||||
continue;
|
||||
|
||||
if (isset($realms[$curTpl['realm']]))
|
||||
{
|
||||
$curTpl['realmName'] = $realms[$curTpl['realm']]['name'];
|
||||
$curTpl['region'] = $realms[$curTpl['realm']]['region'];
|
||||
}
|
||||
|
||||
// battlegroup
|
||||
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
|
||||
|
||||
$curTpl['achievementpoints'] = isset($acvPoints[$id]) ? $acvPoints[$id] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
public function getProfileUrl()
|
||||
{
|
||||
$url = '?profile=';
|
||||
|
||||
if ($this->isCustom())
|
||||
return $url.$this->getField('id');
|
||||
|
||||
return $url.implode('.', array(
|
||||
Profiler::urlize($this->getField('region')),
|
||||
Profiler::urlize($this->getField('realmName')),
|
||||
urlencode($this->getField('name'))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -6,9 +6,8 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class QuestList extends BaseType
|
||||
{
|
||||
public static $type = Type::QUEST;
|
||||
public static $type = TYPE_QUEST;
|
||||
public static $brickFile = 'quest';
|
||||
public static $dataTable = '?_quests';
|
||||
|
||||
public $requires = [];
|
||||
public $rewards = [];
|
||||
@@ -19,7 +18,6 @@ class QuestList extends BaseType
|
||||
'q' => [],
|
||||
'rsc' => ['j' => '?_spell rsc ON q.rewardSpellCast = rsc.id'], // limit rewardSpellCasts
|
||||
'qse' => ['j' => '?_quests_startend qse ON q.id = qse.questId', 's' => ', qse.method'], // groupConcat..?
|
||||
'e' => ['j' => ['?_events e ON e.id = `q`.eventId', true], 's' => ', e.holidayId']
|
||||
);
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
@@ -35,7 +33,7 @@ class QuestList extends BaseType
|
||||
$_curTpl['cat1'] = $_curTpl['zoneOrSort']; // should probably be in a method...
|
||||
$_curTpl['cat2'] = 0;
|
||||
|
||||
foreach (Game::$questClasses as $k => $arr)
|
||||
foreach (Util::$questClasses as $k => $arr)
|
||||
{
|
||||
if (in_array($_curTpl['cat1'], $arr))
|
||||
{
|
||||
@@ -49,18 +47,18 @@ class QuestList extends BaseType
|
||||
for ($i = 1; $i < 7; $i++)
|
||||
{
|
||||
if ($_ = $_curTpl['reqItemId'.$i])
|
||||
$requires[Type::ITEM][] = $_;
|
||||
$requires[TYPE_ITEM][] = $_;
|
||||
|
||||
if ($i > 4)
|
||||
continue;
|
||||
|
||||
if ($_curTpl['reqNpcOrGo'.$i] > 0)
|
||||
$requires[Type::NPC][] = $_curTpl['reqNpcOrGo'.$i];
|
||||
$requires[TYPE_NPC][] = $_curTpl['reqNpcOrGo'.$i];
|
||||
else if ($_curTpl['reqNpcOrGo'.$i] < 0)
|
||||
$requires[Type::OBJECT][] = -$_curTpl['reqNpcOrGo'.$i];
|
||||
$requires[TYPE_OBJECT][] = -$_curTpl['reqNpcOrGo'.$i];
|
||||
|
||||
if ($_ = $_curTpl['reqSourceItemId'.$i])
|
||||
$requires[Type::ITEM][] = $_;
|
||||
$requires[TYPE_ITEM][] = $_;
|
||||
}
|
||||
if ($requires)
|
||||
$this->requires[$id] = $requires;
|
||||
@@ -70,24 +68,24 @@ class QuestList extends BaseType
|
||||
$choices = [];
|
||||
|
||||
if ($_ = $_curTpl['rewardTitleId'])
|
||||
$rewards[Type::TITLE][] = $_;
|
||||
$rewards[TYPE_TITLE][] = $_;
|
||||
|
||||
if ($_ = $_curTpl['rewardHonorPoints'])
|
||||
$rewards[Type::CURRENCY][104] = $_;
|
||||
$rewards[TYPE_CURRENCY][104] = $_;
|
||||
|
||||
if ($_ = $_curTpl['rewardArenaPoints'])
|
||||
$rewards[Type::CURRENCY][103] = $_;
|
||||
$rewards[TYPE_CURRENCY][103] = $_;
|
||||
|
||||
for ($i = 1; $i < 7; $i++)
|
||||
{
|
||||
if ($_ = $_curTpl['rewardChoiceItemId'.$i])
|
||||
$choices[Type::ITEM][$_] = $_curTpl['rewardChoiceItemCount'.$i];
|
||||
$choices[TYPE_ITEM][$_] = $_curTpl['rewardChoiceItemCount'.$i];
|
||||
|
||||
if ($i > 5)
|
||||
continue;
|
||||
|
||||
if ($_ = $_curTpl['rewardFactionId'.$i])
|
||||
$rewards[Type::FACTION][$_] = $_curTpl['rewardFactionValue'.$i];
|
||||
$rewards[TYPE_FACTION][$_] = $_curTpl['rewardFactionValue'.$i];
|
||||
|
||||
if ($i > 4)
|
||||
continue;
|
||||
@@ -96,9 +94,9 @@ class QuestList extends BaseType
|
||||
{
|
||||
$qty = $_curTpl['rewardItemCount'.$i];
|
||||
if (in_array($_, $currencies))
|
||||
$rewards[Type::CURRENCY][array_search($_, $currencies)] = $qty;
|
||||
$rewards[TYPE_CURRENCY][array_search($_, $currencies)] = $qty;
|
||||
else
|
||||
$rewards[Type::ITEM][$_] = $qty;
|
||||
$rewards[TYPE_ITEM][$_] = $qty;
|
||||
}
|
||||
}
|
||||
if ($rewards)
|
||||
@@ -112,7 +110,7 @@ class QuestList extends BaseType
|
||||
// static use START
|
||||
public static function getName($id)
|
||||
{
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8 FROM ?_quests WHERE id = ?d', $id);
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc6, name_loc8 FROM ?_quests WHERE id = ?d', $id);
|
||||
return Util::localizedString($n, 'name');
|
||||
}
|
||||
// static use END
|
||||
@@ -122,18 +120,12 @@ class QuestList extends BaseType
|
||||
return $this->curTpl['flags'] & QUEST_FLAG_REPEATABLE || $this->curTpl['specialFlags'] & QUEST_FLAG_SPECIAL_REPEATABLE;
|
||||
}
|
||||
|
||||
public function isDaily()
|
||||
public function isDaily($strict = false)
|
||||
{
|
||||
if ($this->curTpl['flags'] & QUEST_FLAG_DAILY)
|
||||
return 1;
|
||||
|
||||
if ($this->curTpl['flags'] & QUEST_FLAG_WEEKLY)
|
||||
return 2;
|
||||
|
||||
if ($this->curTpl['specialFlags'] & QUEST_FLAG_SPECIAL_MONTHLY)
|
||||
return 3;
|
||||
|
||||
return 0;
|
||||
if ($strict)
|
||||
return $this->curTpl['flags'] & QUEST_FLAG_DAILY;
|
||||
else
|
||||
return $this->curTpl['flags'] & (QUEST_FLAG_DAILY | QUEST_FLAG_WEEKLY) || $this->curTpl['specialFlags'] & QUEST_FLAG_SPECIAL_MONTHLY;
|
||||
}
|
||||
|
||||
// using reqPlayerKills and rewardHonor as a crutch .. has TC this even implemented..?
|
||||
@@ -156,7 +148,7 @@ class QuestList extends BaseType
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
"n" => $this->getField('name', true),
|
||||
"t" => Type::QUEST,
|
||||
"t" => TYPE_QUEST,
|
||||
"ti" => $this->id,
|
||||
"c" => $this->curTpl['cat1'],
|
||||
"c2" => $this->curTpl['cat2']
|
||||
@@ -172,10 +164,10 @@ class QuestList extends BaseType
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
if (!(Game::sideByRaceMask($this->curTpl['reqRaceMask']) & $side))
|
||||
if (!(Util::sideByRaceMask($this->curTpl['reqRaceMask']) & $side))
|
||||
continue;
|
||||
|
||||
[$series, $first] = DB::Aowow()->SelectRow(
|
||||
list($series, $first) = DB::Aowow()->SelectRow(
|
||||
'SELECT IF(prev.id OR cur.nextQuestIdChain, 1, 0) AS "0", IF(prev.id IS NULL AND cur.nextQuestIdChain, 1, 0) AS "1" FROM ?_quests cur LEFT JOIN ?_quests prev ON prev.nextQuestIdChain = cur.id WHERE cur.id = ?d',
|
||||
$this->id
|
||||
);
|
||||
@@ -209,21 +201,21 @@ class QuestList extends BaseType
|
||||
'level' => $this->curTpl['level'],
|
||||
'reqlevel' => $this->curTpl['minLevel'],
|
||||
'name' => $this->getField('name', true),
|
||||
'side' => Game::sideByRaceMask($this->curTpl['reqRaceMask']),
|
||||
'side' => Util::sideByRaceMask($this->curTpl['reqRaceMask']),
|
||||
'wflags' => 0x0,
|
||||
'xp' => $this->curTpl['rewardXP']
|
||||
);
|
||||
|
||||
if (!empty($this->rewards[$this->id][Type::CURRENCY]))
|
||||
foreach ($this->rewards[$this->id][Type::CURRENCY] as $iId => $qty)
|
||||
if (!empty($this->rewards[$this->id][TYPE_CURRENCY]))
|
||||
foreach ($this->rewards[$this->id][TYPE_CURRENCY] as $iId => $qty)
|
||||
$data[$this->id]['currencyrewards'][] = [$iId, $qty];
|
||||
|
||||
if (!empty($this->rewards[$this->id][Type::ITEM]))
|
||||
foreach ($this->rewards[$this->id][Type::ITEM] as $iId => $qty)
|
||||
if (!empty($this->rewards[$this->id][TYPE_ITEM]))
|
||||
foreach ($this->rewards[$this->id][TYPE_ITEM] as $iId => $qty)
|
||||
$data[$this->id]['itemrewards'][] = [$iId, $qty];
|
||||
|
||||
if (!empty($this->choices[$this->id][Type::ITEM]))
|
||||
foreach ($this->choices[$this->id][Type::ITEM] as $iId => $qty)
|
||||
if (!empty($this->choices[$this->id][TYPE_ITEM]))
|
||||
foreach ($this->choices[$this->id][TYPE_ITEM] as $iId => $qty)
|
||||
$data[$this->id]['itemchoices'][] = [$iId, $qty];
|
||||
|
||||
if ($_ = $this->curTpl['rewardTitleId'])
|
||||
@@ -249,8 +241,6 @@ class QuestList extends BaseType
|
||||
|
||||
// if ($this->isRepeatable()) // dafuque..? says repeatable and is used as 'disabled'..?
|
||||
// $data[$this->id]['wflags'] |= QUEST_CU_REPEATABLE;
|
||||
if ($this->curTpl['cuFlags'] & (CUSTOM_UNAVAILABLE | CUSTOM_DISABLED))
|
||||
$data[$this->id]['wflags'] |= QUEST_CU_REPEATABLE;
|
||||
|
||||
if ($this->curTpl['flags'] & QUEST_FLAG_DAILY)
|
||||
{
|
||||
@@ -313,7 +303,7 @@ class QuestList extends BaseType
|
||||
if (!$this->curTpl)
|
||||
return null;
|
||||
|
||||
$title = htmlentities($this->getField('name', true));
|
||||
$title = Util::jsEscape($this->getField('name', true));
|
||||
$level = $this->curTpl['level'];
|
||||
if ($level < 0)
|
||||
$level = 0;
|
||||
@@ -332,7 +322,7 @@ class QuestList extends BaseType
|
||||
$x .= '<table><tr><td><b class="q">'.$title.'</b></td></tr></table>';
|
||||
|
||||
|
||||
$x .= '<table><tr><td><br />'.$this->parseText('objectives', false);
|
||||
$x .= '<table><tr><td><br />'.$this->parseText('objectives');
|
||||
|
||||
|
||||
$xReq = '';
|
||||
@@ -350,7 +340,7 @@ class QuestList extends BaseType
|
||||
else
|
||||
$name = $rng > 0 ? CreatureList::getName($rng) : GameObjectList::getName(-$rng);
|
||||
|
||||
$xReq .= '<br /> - '.$name.($rngQty > 1 ? ' x '.$rngQty : null);
|
||||
$xReq .= '<br /> - '.Util::jsEscape($name).($rngQty > 1 ? ' x '.$rngQty : null);
|
||||
}
|
||||
|
||||
for ($i = 1; $i < 7; $i++)
|
||||
@@ -361,11 +351,11 @@ class QuestList extends BaseType
|
||||
if (!$ri || $riQty < 1)
|
||||
continue;
|
||||
|
||||
$xReq .= '<br /> - '.ItemList::getName($ri).($riQty > 1 ? ' x '.$riQty : null);
|
||||
$xReq .= '<br /> - '.Util::jsEscape(ItemList::getName($ri)).($riQty > 1 ? ' x '.$riQty : null);
|
||||
}
|
||||
|
||||
if ($et = $this->getField('end', true))
|
||||
$xReq .= '<br /> - '.$et;
|
||||
$xReq .= '<br /> - '.Util::jsEscape($et);
|
||||
|
||||
if ($_ = $this->getField('rewardOrReqMoney'))
|
||||
if ($_ < 0)
|
||||
@@ -390,31 +380,33 @@ class QuestList extends BaseType
|
||||
// items
|
||||
for ($i = 1; $i < 5; $i++)
|
||||
if ($this->curTpl['rewardItemId'.$i] > 0)
|
||||
$data[Type::ITEM][$this->curTpl['rewardItemId'.$i]] = $this->curTpl['rewardItemId'.$i];
|
||||
$data[TYPE_ITEM][$this->curTpl['rewardItemId'.$i]] = $this->curTpl['rewardItemId'.$i];
|
||||
|
||||
for ($i = 1; $i < 7; $i++)
|
||||
if ($this->curTpl['rewardChoiceItemId'.$i] > 0)
|
||||
$data[Type::ITEM][$this->curTpl['rewardChoiceItemId'.$i]] = $this->curTpl['rewardChoiceItemId'.$i];
|
||||
$data[TYPE_ITEM][$this->curTpl['rewardChoiceItemId'.$i]] = $this->curTpl['rewardChoiceItemId'.$i];
|
||||
|
||||
// spells
|
||||
if ($this->curTpl['rewardSpell'] > 0)
|
||||
$data[Type::SPELL][$this->curTpl['rewardSpell']] = $this->curTpl['rewardSpell'];
|
||||
$data[TYPE_SPELL][$this->curTpl['rewardSpell']] = $this->curTpl['rewardSpell'];
|
||||
|
||||
if ($this->curTpl['rewardSpellCast'] > 0)
|
||||
$data[Type::SPELL][$this->curTpl['rewardSpellCast']] = $this->curTpl['rewardSpellCast'];
|
||||
$data[TYPE_SPELL][$this->curTpl['rewardSpellCast']] = $this->curTpl['rewardSpellCast'];
|
||||
|
||||
// titles
|
||||
if ($this->curTpl['rewardTitleId'] > 0)
|
||||
$data[Type::TITLE][$this->curTpl['rewardTitleId']] = $this->curTpl['rewardTitleId'];
|
||||
$data[TYPE_TITLE][$this->curTpl['rewardTitleId']] = $this->curTpl['rewardTitleId'];
|
||||
|
||||
// currencies
|
||||
if (!empty($this->rewards[$this->id][Type::CURRENCY]))
|
||||
foreach ($this->rewards[$this->id][Type::CURRENCY] as $id => $__)
|
||||
$data[Type::CURRENCY][$id] = $id;
|
||||
if (!empty($this->rewards[$this->id][TYPE_CURRENCY]))
|
||||
{
|
||||
$_ = $this->rewards[$this->id][TYPE_CURRENCY];
|
||||
$data[TYPE_CURRENCY] = array_combine(array_keys($_), array_keys($_));
|
||||
}
|
||||
}
|
||||
|
||||
if ($addMask & GLOBALINFO_SELF)
|
||||
$data[Type::QUEST][$this->id] = ['name' => $this->getField('name', true)];
|
||||
$data[TYPE_QUEST][$this->id] = ['name' => $this->getField('name', true)];
|
||||
}
|
||||
|
||||
return $data;
|
||||
@@ -430,59 +422,27 @@ class QuestListFilter extends Filter
|
||||
38 => [null, 1, 2, 3, 4, 5, 6, 7, 8, null, 10, 11, true, false],
|
||||
);
|
||||
protected $genericFilter = array(
|
||||
1 => [FILTER_CR_CALLBACK, 'cbReputation', '>', null], // increasesrepwith
|
||||
2 => [FILTER_CR_NUMERIC, 'rewardXP', NUM_CAST_INT ], // experiencegained
|
||||
3 => [FILTER_CR_NUMERIC, 'rewardOrReqMoney', NUM_CAST_INT ], // moneyrewarded
|
||||
4 => [FILTER_CR_CALLBACK, 'cbSpellRewards', null, null], // spellrewarded [yn]
|
||||
5 => [FILTER_CR_FLAG, 'flags', QUEST_FLAG_SHARABLE ], // sharable
|
||||
6 => [FILTER_CR_NUMERIC, 'timeLimit', NUM_CAST_INT ], // timer
|
||||
7 => [FILTER_CR_NYI_PH, null, 1 ], // firstquestseries
|
||||
9 => [FILTER_CR_CALLBACK, 'cbEarnReputation', null, null], // objectiveearnrepwith [enum]
|
||||
10 => [FILTER_CR_CALLBACK, 'cbReputation', '<', null], // decreasesrepwith
|
||||
11 => [FILTER_CR_NUMERIC, 'suggestedPlayers', NUM_CAST_INT ], // suggestedplayers
|
||||
15 => [FILTER_CR_NYI_PH, null, 1 ], // lastquestseries
|
||||
16 => [FILTER_CR_NYI_PH, null, 1 ], // partseries
|
||||
18 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT ], // hasscreenshots
|
||||
19 => [FILTER_CR_CALLBACK, 'cbQuestRelation', 0x1, null], // startsfrom [enum]
|
||||
21 => [FILTER_CR_CALLBACK, 'cbQuestRelation', 0x2, null], // endsat [enum]
|
||||
22 => [FILTER_CR_CALLBACK, 'cbItemRewards', null, null], // itemrewards [op] [int]
|
||||
23 => [FILTER_CR_CALLBACK, 'cbItemChoices', null, null], // itemchoices [op] [int]
|
||||
24 => [FILTER_CR_CALLBACK, 'cbLacksStartEnd', null, null], // lacksstartend [yn]
|
||||
25 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_COMMENT ], // hascomments
|
||||
27 => [FILTER_CR_FLAG, 'flags', QUEST_FLAG_DAILY ], // daily
|
||||
28 => [FILTER_CR_FLAG, 'flags', QUEST_FLAG_WEEKLY ], // weekly
|
||||
29 => [FILTER_CR_FLAG, 'flags', QUEST_FLAG_REPEATABLE ], // repeatable
|
||||
30 => [FILTER_CR_NUMERIC, 'id', NUM_CAST_INT, true], // id
|
||||
33 => [FILTER_CR_ENUM, 'e.holidayId' ], // relatedevent
|
||||
34 => [FILTER_CR_CALLBACK, 'cbAvailable', null, null], // availabletoplayers [yn]
|
||||
30 => [FILTER_CR_NUMERIC, 'id', null, true], // id
|
||||
5 => [FILTER_CR_FLAG, 'flags', QUEST_FLAG_SHARABLE ], // sharable
|
||||
11 => [FILTER_CR_NUMERIC, 'suggestedPlayers', ], // suggestedplayers
|
||||
6 => [FILTER_CR_NUMERIC, 'timeLimit', ], // timer
|
||||
42 => [FILTER_CR_STAFFFLAG, 'flags', ], // flags
|
||||
45 => [FILTER_CR_BOOLEAN, 'rewardTitleId', ], // titlerewarded
|
||||
2 => [FILTER_CR_NUMERIC, 'rewardXP', ], // experiencegained
|
||||
3 => [FILTER_CR_NUMERIC, 'rewardOrReqMoney', ], // moneyrewarded
|
||||
33 => [FILTER_CR_ENUM, 'holidayId', ], // relatedevent
|
||||
25 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_COMMENT ], // hascomments
|
||||
18 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_SCREENSHOT ], // hasscreenshots
|
||||
36 => [FILTER_CR_FLAG, 'cuFlags', CUSTOM_HAS_VIDEO ], // hasvideos
|
||||
37 => [FILTER_CR_CALLBACK, 'cbClassSpec', null, null], // classspecific [enum]
|
||||
38 => [FILTER_CR_CALLBACK, 'cbRaceSpec', null, null], // racespecific [enum]
|
||||
42 => [FILTER_CR_STAFFFLAG, 'flags' ], // flags
|
||||
43 => [FILTER_CR_CALLBACK, 'cbCurrencyReward', null, null], // currencyrewarded [enum]
|
||||
44 => [FILTER_CR_CALLBACK, 'cbLoremaster', null, null], // countsforloremaster_stc [yn]
|
||||
45 => [FILTER_CR_BOOLEAN, 'rewardTitleId' ] // titlerewarded
|
||||
);
|
||||
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'cr' => [FILTER_V_RANGE, [1, 45], true ], // criteria ids
|
||||
'crs' => [FILTER_V_LIST, [FILTER_ENUM_NONE, FILTER_ENUM_ANY, [0, 99999]], true ], // criteria operators
|
||||
'crv' => [FILTER_V_REGEX, '/\D/', true ], // criteria values - only numerals
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name / text - only printable chars, no delimiter
|
||||
'ex' => [FILTER_V_EQUAL, 'on', false], // also match subname
|
||||
'ma' => [FILTER_V_EQUAL, 1, false], // match any / all filter
|
||||
'minle' => [FILTER_V_RANGE, [1, 99], false], // min quest level
|
||||
'maxle' => [FILTER_V_RANGE, [1, 99], false], // max quest level
|
||||
'minrl' => [FILTER_V_RANGE, [1, 99], false], // min required level
|
||||
'maxrl' => [FILTER_V_RANGE, [1, 99], false], // max required level
|
||||
'si' => [FILTER_V_LIST, [-2, -1, 1, 2, 3], false], // siede
|
||||
'ty' => [FILTER_V_LIST, [0, 1, 21, 41, 62, [81, 85], 88, 89], true ] // type
|
||||
);
|
||||
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
if (in_array($cr[0], array_keys($this->genericFilter)))
|
||||
{
|
||||
if ($genCr = $this->genericCriterion($cr))
|
||||
return $genCr;
|
||||
|
||||
@@ -491,6 +451,163 @@ class QuestListFilter extends Filter
|
||||
return [1];
|
||||
}
|
||||
|
||||
switch ($cr[0])
|
||||
{
|
||||
case 1: // increasesrepwith
|
||||
if ($this->isSaneNumeric($cr[1]) && $cr[1] > 0)
|
||||
{
|
||||
return [
|
||||
'OR',
|
||||
['AND', ['rewardFactionId1', $cr[1]], ['rewardFactionValue1', 0, '>']],
|
||||
['AND', ['rewardFactionId2', $cr[1]], ['rewardFactionValue2', 0, '>']],
|
||||
['AND', ['rewardFactionId3', $cr[1]], ['rewardFactionValue3', 0, '>']],
|
||||
['AND', ['rewardFactionId4', $cr[1]], ['rewardFactionValue4', 0, '>']],
|
||||
['AND', ['rewardFactionId5', $cr[1]], ['rewardFactionValue5', 0, '>']]
|
||||
];
|
||||
}
|
||||
break;
|
||||
case 10: // decreasesrepwith
|
||||
if ($this->isSaneNumeric($cr[1]) && $cr[1] > 0)
|
||||
{
|
||||
return [
|
||||
'OR',
|
||||
['AND', ['rewardFactionId1', $cr[1]], ['rewardFactionValue1', 0, '<']],
|
||||
['AND', ['rewardFactionId2', $cr[1]], ['rewardFactionValue2', 0, '<']],
|
||||
['AND', ['rewardFactionId3', $cr[1]], ['rewardFactionValue3', 0, '<']],
|
||||
['AND', ['rewardFactionId4', $cr[1]], ['rewardFactionValue4', 0, '<']],
|
||||
['AND', ['rewardFactionId5', $cr[1]], ['rewardFactionValue5', 0, '<']]
|
||||
];
|
||||
}
|
||||
break;
|
||||
case 43: // currencyrewarded
|
||||
if ($this->isSaneNumeric($cr[1]) && $cr[1] > 0)
|
||||
{
|
||||
return [
|
||||
'OR',
|
||||
['rewardItemId1', $cr[1]], ['rewardItemId2', $cr[1]], ['rewardItemId3', $cr[1]], ['rewardItemId4', $cr[1]],
|
||||
['rewardChoiceItemId1', $cr[1]], ['rewardChoiceItemId2', $cr[1]], ['rewardChoiceItemId3', $cr[1]], ['rewardChoiceItemId4', $cr[1]], ['rewardChoiceItemId5', $cr[1]], ['rewardChoiceItemId6', $cr[1]]
|
||||
];
|
||||
}
|
||||
break;
|
||||
case 34: // availabletoplayers
|
||||
if ($this->int2Bool($cr[1]))
|
||||
{
|
||||
if ($cr[1])
|
||||
return ['AND', [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0], [['flags', QUEST_FLAG_UNAVAILABLE, '&'], 0]];
|
||||
else
|
||||
return ['OR', ['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], ['flags', QUEST_FLAG_UNAVAILABLE, '&']];
|
||||
}
|
||||
break;
|
||||
case 23: // itemchoices [op] [int]
|
||||
if (!$this->isSaneNumeric($cr[2], false) || !$this->int2Op($cr[1]))
|
||||
break;
|
||||
|
||||
$this->extraOpts['q']['s'][] = ', (IF(rewardChoiceItemId1, 1, 0) + IF(rewardChoiceItemId2, 1, 0) + IF(rewardChoiceItemId3, 1, 0) + IF(rewardChoiceItemId4, 1, 0) + IF(rewardChoiceItemId5, 1, 0) + IF(rewardChoiceItemId6, 1, 0)) as numChoices';
|
||||
$this->extraOpts['q']['h'][] = 'numChoices '.$cr[1].' '.$cr[2];
|
||||
return [1];
|
||||
case 22: // itemrewards [op] [int]
|
||||
if (!$this->isSaneNumeric($cr[2], false) || !$this->int2Op($cr[1]))
|
||||
break;
|
||||
|
||||
$this->extraOpts['q']['s'][] = ', (IF(rewardItemId1, 1, 0) + IF(rewardItemId2, 1, 0) + IF(rewardItemId3, 1, 0) + IF(rewardItemId4, 1, 0)) as numRewards';
|
||||
$this->extraOpts['q']['h'][] = 'numRewards '.$cr[1].' '.$cr[2];
|
||||
return [1];
|
||||
case 44: // countsforloremaster_stc [bool]
|
||||
if ($this->int2Bool($cr[1]))
|
||||
{
|
||||
if ($cr[1])
|
||||
return ['AND', ['zoneOrSort', 0, '>'], [['flags', QUEST_FLAG_DAILY | QUEST_FLAG_WEEKLY | QUEST_FLAG_REPEATABLE , '&'], 0], [['specialFlags', QUEST_FLAG_SPECIAL_REPEATABLE | QUEST_FLAG_SPECIAL_MONTHLY , '&'], 0]];
|
||||
else
|
||||
return ['OR', ['zoneOrSort', 0, '<'], ['flags', QUEST_FLAG_DAILY | QUEST_FLAG_WEEKLY | QUEST_FLAG_REPEATABLE , '&'], ['specialFlags', QUEST_FLAG_SPECIAL_REPEATABLE | QUEST_FLAG_SPECIAL_MONTHLY , '&']];;
|
||||
}
|
||||
|
||||
break;
|
||||
case 4: // spellrewarded [bool]
|
||||
if ($this->int2Bool($cr[1]))
|
||||
{
|
||||
if ($cr[1])
|
||||
return ['OR', ['sourceSpellId', 0, '>'], ['rewardSpell', 0, '>'], ['rsc.effect1Id', SpellList::$effects['teach']], ['rsc.effect2Id', SpellList::$effects['teach']], ['rsc.effect3Id', SpellList::$effects['teach']]];
|
||||
else
|
||||
return ['AND', ['sourceSpellId', 0], ['rewardSpell', 0], ['rewardSpellCast', 0]];
|
||||
}
|
||||
break;
|
||||
case 9: // objectiveearnrepwith [enum]
|
||||
$_ = intVal($cr[1]);
|
||||
if ($_ > 0)
|
||||
return ['OR', ['reqFactionId1', $_], ['reqFactionId2', $_]];
|
||||
else if ($cr[1] == FILTER_ENUM_ANY) // any
|
||||
return ['OR', ['reqFactionId1', 0, '>'], ['reqFactionId2', 0, '>']];
|
||||
else if ($cr[1] == FILTER_ENUM_NONE) // none
|
||||
return ['AND', ['reqFactionId1', 0], ['reqFactionId2', 0]];
|
||||
|
||||
break;
|
||||
case 37: // classspecific [enum]
|
||||
$_ = isset($this->enums[$cr[0]][$cr[1]]) ? $this->enums[$cr[0]][$cr[1]] : null;
|
||||
if ($_ !== null)
|
||||
{
|
||||
if ($_ === true)
|
||||
return ['AND', ['reqClassMask', 0, '!'], [['reqClassMask', CLASS_MASK_ALL, '&'], CLASS_MASK_ALL, '!']];
|
||||
else if ($_ === false)
|
||||
return ['OR', ['reqClassMask', 0], [['reqClassMask', CLASS_MASK_ALL, '&'], CLASS_MASK_ALL]];
|
||||
else if (is_int($_))
|
||||
return ['AND', ['reqClassMask', (1 << ($_ - 1)), '&'], [['reqClassMask', CLASS_MASK_ALL, '&'], CLASS_MASK_ALL, '!']];
|
||||
}
|
||||
break;
|
||||
case 38: // racespecific [enum]
|
||||
$_ = isset($this->enums[$cr[0]][$cr[1]]) ? $this->enums[$cr[0]][$cr[1]] : null;
|
||||
if ($_ !== null)
|
||||
{
|
||||
if ($_ === true)
|
||||
return ['AND', ['reqRaceMask', 0, '!'], [['reqRaceMask', RACE_MASK_ALL, '&'], RACE_MASK_ALL, '!'], [['reqRaceMask', RACE_MASK_ALLIANCE, '&'], RACE_MASK_ALLIANCE, '!'], [['reqRaceMask', RACE_MASK_HORDE, '&'], RACE_MASK_HORDE, '!']];
|
||||
else if ($_ === false)
|
||||
return ['OR', ['reqRaceMask', 0], ['reqRaceMask', RACE_MASK_ALL], ['reqRaceMask', RACE_MASK_ALLIANCE], ['reqRaceMask', RACE_MASK_HORDE]];
|
||||
else if (is_int($_))
|
||||
return ['AND', ['reqRaceMask', (1 << ($_ - 1)), '&'], [['reqRaceMask', RACE_MASK_ALLIANCE, '&'], RACE_MASK_ALLIANCE, '!'], [['reqRaceMask', RACE_MASK_HORDE, '&'], RACE_MASK_HORDE, '!']];
|
||||
}
|
||||
break;
|
||||
case 19: // startsfrom [enum]
|
||||
switch ($cr[1])
|
||||
{
|
||||
case 1: // npc
|
||||
return ['AND', ['qse.type', TYPE_NPC], ['qse.method', 0x1, '&']];
|
||||
case 2: // object
|
||||
return ['AND', ['qse.type', TYPE_OBJECT], ['qse.method', 0x1, '&']];
|
||||
case 3: // item
|
||||
return ['AND', ['qse.type', TYPE_ITEM], ['qse.method', 0x1, '&']];
|
||||
}
|
||||
break;
|
||||
case 21: // endsat [enum]
|
||||
switch ($cr[1])
|
||||
{
|
||||
case 1: // npc
|
||||
return ['AND', ['qse.type', TYPE_NPC], ['qse.method', 0x2, '&']];
|
||||
case 2: // object
|
||||
return ['AND', ['qse.type', TYPE_OBJECT], ['qse.method', 0x2, '&']];
|
||||
}
|
||||
break;
|
||||
case 24: // lacksstartend [bool]
|
||||
$missing = DB::Aowow()->selectCol('SELECT questId, max(method) a, min(method) b FROM ?_quests_startend GROUP BY questId HAVING (a | b) <> 3');
|
||||
if ($this->int2Bool($cr[1]))
|
||||
{
|
||||
if ($cr[1])
|
||||
return ['id', $missing];
|
||||
else
|
||||
return ['id', $missing, '!'];
|
||||
}
|
||||
break;
|
||||
case 7: // firstquestseries
|
||||
case 15: // lastquestseries
|
||||
case 16: // partseries
|
||||
/* todo */ return [1]; // self-joining eats substential amounts of time: should restructure that and also incorporate reqQ and openQ cases from infobox
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
unset($cr);
|
||||
$this->error = 1;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
@@ -511,19 +628,39 @@ class QuestListFilter extends Filter
|
||||
|
||||
// level min
|
||||
if (isset($_v['minle']))
|
||||
{
|
||||
if (is_int($_v['minle']) && $_v['minle'] > 0)
|
||||
$parts[] = ['level', $_v['minle'], '>=']; // not considering quests that are always at player level (-1)
|
||||
else
|
||||
unset($_v['minle']);
|
||||
}
|
||||
|
||||
// level max
|
||||
if (isset($_v['maxle']))
|
||||
{
|
||||
if (is_int($_v['maxle']) && $_v['maxle'] > 0)
|
||||
$parts[] = ['level', $_v['maxle'], '<='];
|
||||
else
|
||||
unset($_v['maxle']);
|
||||
}
|
||||
|
||||
// reqLevel min
|
||||
if (isset($_v['minrl']))
|
||||
{
|
||||
if (is_int($_v['minrl']) && $_v['minrl'] > 0)
|
||||
$parts[] = ['minLevel', $_v['minrl'], '>='];// ignoring maxLevel
|
||||
else
|
||||
unset($_v['minrl']);
|
||||
}
|
||||
|
||||
// reqLevel max
|
||||
if (isset($_v['maxrl']))
|
||||
{
|
||||
if (is_int($_v['maxrl']) && $_v['maxrl'] > 0)
|
||||
$parts[] = ['minLevel', $_v['maxrl'], '<='];// ignoring maxLevel
|
||||
else
|
||||
unset($_v['maxrl']);
|
||||
}
|
||||
|
||||
// side
|
||||
if (isset($_v['si']))
|
||||
@@ -548,172 +685,23 @@ class QuestListFilter extends Filter
|
||||
case -1:
|
||||
$parts[] = ['AND', $ex, ['reqRaceMask', RACE_MASK_ALLIANCE, '&']];
|
||||
break;
|
||||
default:
|
||||
unset($_v['si']);
|
||||
}
|
||||
}
|
||||
|
||||
// type [list]
|
||||
if (isset($_v['ty']))
|
||||
$parts[] = ['type', $_v['ty']];
|
||||
{
|
||||
$_ = (array)$_v['ty'];
|
||||
if (!array_diff($_, [0, 1, 21, 41, 62, 81, 82, 83, 84, 85, 88, 89]))
|
||||
$parts[] = ['type', $_];
|
||||
else
|
||||
unset($_v['ty']);
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function cbReputation($cr, $sign)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[1], NUM_REQ_INT) || $cr[1] <= 0)
|
||||
return false;
|
||||
|
||||
if ($_ = DB::Aowow()->selectRow('SELECT * FROM ?_factions WHERE id = ?d', $cr[1]))
|
||||
$this->formData['reputationCols'][] = [$cr[1], Util::localizedString($_, 'name')];
|
||||
|
||||
return [
|
||||
'OR',
|
||||
['AND', ['rewardFactionId1', $cr[1]], ['rewardFactionValue1', 0, $sign]],
|
||||
['AND', ['rewardFactionId2', $cr[1]], ['rewardFactionValue2', 0, $sign]],
|
||||
['AND', ['rewardFactionId3', $cr[1]], ['rewardFactionValue3', 0, $sign]],
|
||||
['AND', ['rewardFactionId4', $cr[1]], ['rewardFactionValue4', 0, $sign]],
|
||||
['AND', ['rewardFactionId5', $cr[1]], ['rewardFactionValue5', 0, $sign]]
|
||||
];
|
||||
}
|
||||
|
||||
protected function cbQuestRelation($cr, $flags)
|
||||
{
|
||||
switch ($cr[1])
|
||||
{
|
||||
case 1: // npc
|
||||
return ['AND', ['qse.type', Type::NPC], ['qse.method', $flags, '&']];
|
||||
case 2: // object
|
||||
return ['AND', ['qse.type', Type::OBJECT], ['qse.method', $flags, '&']];
|
||||
case 3: // item
|
||||
return ['AND', ['qse.type', Type::ITEM], ['qse.method', $flags, '&']];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbCurrencyReward($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[1], NUM_REQ_INT) || $cr[1] <= 0)
|
||||
return false;
|
||||
|
||||
return [
|
||||
'OR',
|
||||
['rewardItemId1', $cr[1]], ['rewardItemId2', $cr[1]], ['rewardItemId3', $cr[1]], ['rewardItemId4', $cr[1]],
|
||||
['rewardChoiceItemId1', $cr[1]], ['rewardChoiceItemId2', $cr[1]], ['rewardChoiceItemId3', $cr[1]], ['rewardChoiceItemId4', $cr[1]], ['rewardChoiceItemId5', $cr[1]], ['rewardChoiceItemId6', $cr[1]]
|
||||
];
|
||||
}
|
||||
|
||||
protected function cbAvailable($cr)
|
||||
{
|
||||
if (!$this->int2Bool($cr[1]))
|
||||
return false;
|
||||
|
||||
if ($cr[1])
|
||||
return [['cuFlags', CUSTOM_UNAVAILABLE | CUSTOM_DISABLED, '&'], 0];
|
||||
else
|
||||
return ['cuFlags', CUSTOM_UNAVAILABLE | CUSTOM_DISABLED, '&'];
|
||||
}
|
||||
|
||||
protected function cbItemChoices($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
$this->extraOpts['q']['s'][] = ', (IF(rewardChoiceItemId1, 1, 0) + IF(rewardChoiceItemId2, 1, 0) + IF(rewardChoiceItemId3, 1, 0) + IF(rewardChoiceItemId4, 1, 0) + IF(rewardChoiceItemId5, 1, 0) + IF(rewardChoiceItemId6, 1, 0)) as numChoices';
|
||||
$this->extraOpts['q']['h'][] = 'numChoices '.$cr[1].' '.$cr[2];
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function cbItemRewards($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[2], NUM_CAST_INT) || !$this->int2Op($cr[1]))
|
||||
return false;
|
||||
|
||||
$this->extraOpts['q']['s'][] = ', (IF(rewardItemId1, 1, 0) + IF(rewardItemId2, 1, 0) + IF(rewardItemId3, 1, 0) + IF(rewardItemId4, 1, 0)) as numRewards';
|
||||
$this->extraOpts['q']['h'][] = 'numRewards '.$cr[1].' '.$cr[2];
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function cbLoremaster($cr)
|
||||
{
|
||||
if (!$this->int2Bool($cr[1]))
|
||||
return false;
|
||||
|
||||
if ($cr[1])
|
||||
return ['AND', ['zoneOrSort', 0, '>'], [['flags', QUEST_FLAG_DAILY | QUEST_FLAG_WEEKLY | QUEST_FLAG_REPEATABLE , '&'], 0], [['specialFlags', QUEST_FLAG_SPECIAL_REPEATABLE | QUEST_FLAG_SPECIAL_MONTHLY , '&'], 0]];
|
||||
else
|
||||
return ['OR', ['zoneOrSort', 0, '<'], ['flags', QUEST_FLAG_DAILY | QUEST_FLAG_WEEKLY | QUEST_FLAG_REPEATABLE , '&'], ['specialFlags', QUEST_FLAG_SPECIAL_REPEATABLE | QUEST_FLAG_SPECIAL_MONTHLY , '&']];;
|
||||
}
|
||||
|
||||
protected function cbSpellRewards($cr)
|
||||
{
|
||||
if (!$this->int2Bool($cr[1]))
|
||||
return false;
|
||||
|
||||
if ($cr[1])
|
||||
return ['OR', ['sourceSpellId', 0, '>'], ['rewardSpell', 0, '>'], ['rsc.effect1Id', SpellList::$effects['teach']], ['rsc.effect2Id', SpellList::$effects['teach']], ['rsc.effect3Id', SpellList::$effects['teach']]];
|
||||
else
|
||||
return ['AND', ['sourceSpellId', 0], ['rewardSpell', 0], ['rewardSpellCast', 0]];
|
||||
}
|
||||
|
||||
protected function cbEarnReputation($cr)
|
||||
{
|
||||
if (!Util::checkNumeric($cr[1], NUM_REQ_INT))
|
||||
return false;
|
||||
|
||||
if ($cr[1] > 0)
|
||||
return ['OR', ['reqFactionId1', $cr[1]], ['reqFactionId2', $cr[1]]];
|
||||
else if ($cr[1] == FILTER_ENUM_ANY) // any
|
||||
return ['OR', ['reqFactionId1', 0, '>'], ['reqFactionId2', 0, '>']];
|
||||
else if ($cr[1] == FILTER_ENUM_NONE) // none
|
||||
return ['AND', ['reqFactionId1', 0], ['reqFactionId2', 0]];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbClassSpec($cr)
|
||||
{
|
||||
if (!isset($this->enums[$cr[0]][$cr[1]]))
|
||||
return false;
|
||||
|
||||
$_ = $this->enums[$cr[0]][$cr[1]];
|
||||
if ($_ === true)
|
||||
return ['AND', ['reqClassMask', 0, '!'], [['reqClassMask', CLASS_MASK_ALL, '&'], CLASS_MASK_ALL, '!']];
|
||||
else if ($_ === false)
|
||||
return ['OR', ['reqClassMask', 0], [['reqClassMask', CLASS_MASK_ALL, '&'], CLASS_MASK_ALL]];
|
||||
else if (is_int($_))
|
||||
return ['AND', ['reqClassMask', (1 << ($_ - 1)), '&'], [['reqClassMask', CLASS_MASK_ALL, '&'], CLASS_MASK_ALL, '!']];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbRaceSpec($cr)
|
||||
{
|
||||
if (!isset($this->enums[$cr[0]][$cr[1]]))
|
||||
return false;
|
||||
|
||||
$_ = $this->enums[$cr[0]][$cr[1]];
|
||||
if ($_ === true)
|
||||
return ['AND', ['reqRaceMask', 0, '!'], [['reqRaceMask', RACE_MASK_ALL, '&'], RACE_MASK_ALL, '!'], [['reqRaceMask', RACE_MASK_ALLIANCE, '&'], RACE_MASK_ALLIANCE, '!'], [['reqRaceMask', RACE_MASK_HORDE, '&'], RACE_MASK_HORDE, '!']];
|
||||
else if ($_ === false)
|
||||
return ['OR', ['reqRaceMask', 0], ['reqRaceMask', RACE_MASK_ALL], ['reqRaceMask', RACE_MASK_ALLIANCE], ['reqRaceMask', RACE_MASK_HORDE]];
|
||||
else if (is_int($_))
|
||||
return ['AND', ['reqRaceMask', (1 << ($_ - 1)), '&'], [['reqRaceMask', RACE_MASK_ALLIANCE, '&'], RACE_MASK_ALLIANCE, '!'], [['reqRaceMask', RACE_MASK_HORDE, '&'], RACE_MASK_HORDE, '!']];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function cbLacksStartEnd($cr)
|
||||
{
|
||||
if (!$this->int2Bool($cr[1]))
|
||||
return false;
|
||||
|
||||
$missing = DB::Aowow()->selectCol('SELECT questId, max(method) a, min(method) b FROM ?_quests_startend GROUP BY questId HAVING (a | b) <> 3');
|
||||
if ($cr[1])
|
||||
return ['id', $missing];
|
||||
else
|
||||
return ['id', $missing, '!'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,14 +6,13 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class SkillList extends BaseType
|
||||
{
|
||||
public static $type = Type::SKILL;
|
||||
public static $type = TYPE_SKILL;
|
||||
public static $brickFile = 'skill';
|
||||
public static $dataTable = '?_skillline';
|
||||
|
||||
protected $queryBase = 'SELECT sl.*, sl.id AS ARRAY_KEY FROM ?_skillline sl';
|
||||
protected $queryBase = 'SELECT *, sl.id AS ARRAY_KEY FROM ?_skillline sl';
|
||||
protected $queryOpts = array(
|
||||
'sl' => [['ic']],
|
||||
'ic' => ['j' => ['?_icons ic ON ic.id = sl.iconId', true], 's' => ', ic.name AS iconString'],
|
||||
'sl' => [['si']],
|
||||
'si' => ['j' => '?_icons si ON si.id = sl.iconId', 's' => ', si.iconString'],
|
||||
);
|
||||
|
||||
public function __construct($conditions = [])
|
||||
@@ -32,15 +31,12 @@ class SkillList extends BaseType
|
||||
while (count($_) < 5)
|
||||
$_[] = 0;
|
||||
}
|
||||
|
||||
if (!$_curTpl['iconId'])
|
||||
$_curTpl['iconString'] = 'inv_misc_questionmark';
|
||||
}
|
||||
}
|
||||
|
||||
public static function getName($id)
|
||||
{
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8 FROM ?_skillline WHERE id = ?d', $id);
|
||||
$n = DB::Aowow()->SelectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc6, name_loc8 FROM ?_skillline WHERE id = ?d', $id);
|
||||
return Util::localizedString($n, 'name');
|
||||
}
|
||||
|
||||
@@ -54,11 +50,11 @@ class SkillList extends BaseType
|
||||
'category' => $this->curTpl['typeCat'],
|
||||
'categorybak' => $this->curTpl['categoryId'],
|
||||
'id' => $this->id,
|
||||
'name' => $this->getField('name', true),
|
||||
'name' => Util::jsEscape($this->getField('name', true)),
|
||||
'profession' => $this->curTpl['professionMask'],
|
||||
'recipeSubclass' => $this->curTpl['recipeSubClass'],
|
||||
'specializations' => Util::toJSON($this->curTpl['specializations'], JSON_NUMERIC_CHECK),
|
||||
'icon' => $this->curTpl['iconString']
|
||||
'specializations' => Util::toJSON($this->curTpl['specializations']),
|
||||
'icon' => Util::jsEscape($this->curTpl['iconString'])
|
||||
);
|
||||
}
|
||||
|
||||
@@ -70,7 +66,7 @@ class SkillList extends BaseType
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[self::$type][$this->id] = ['name' => $this->getField('name', true), 'icon' => $this->curTpl['iconString']];
|
||||
$data[self::$type][$this->id] = ['name' => Util::jsEscape($this->getField('name', true)), 'icon' => Util::jsEscape($this->curTpl['iconString'])];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class SoundList extends BaseType
|
||||
{
|
||||
use spawnHelper;
|
||||
|
||||
public static $type = Type::SOUND;
|
||||
public static $brickFile = 'sound';
|
||||
public static $dataTable = '?_sounds';
|
||||
public static $contribute = CONTRIBUTE_CO;
|
||||
|
||||
protected $queryBase = 'SELECT s.*, s.id AS ARRAY_KEY FROM ?_sounds s';
|
||||
|
||||
private $fileBuffer = [];
|
||||
private static $fileTypes = array(
|
||||
SOUND_TYPE_OGG => 'audio/ogg; codecs="vorbis"',
|
||||
SOUND_TYPE_MP3 => 'audio/mpeg'
|
||||
);
|
||||
|
||||
public function __construct($conditions = [])
|
||||
{
|
||||
parent::__construct($conditions);
|
||||
|
||||
// post processing
|
||||
foreach ($this->iterate() as $id => &$_curTpl)
|
||||
{
|
||||
$_curTpl['files'] = [];
|
||||
for ($i = 1; $i < 11; $i++)
|
||||
{
|
||||
if ($_curTpl['soundFile'.$i])
|
||||
{
|
||||
$this->fileBuffer[$_curTpl['soundFile'.$i]] = null;
|
||||
$_curTpl['files'][] = &$this->fileBuffer[$_curTpl['soundFile'.$i]];
|
||||
}
|
||||
|
||||
unset($_curTpl['soundFile'.$i]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->fileBuffer)
|
||||
{
|
||||
$files = DB::Aowow()->select('SELECT id AS ARRAY_KEY, `id`, `file` AS title, `type`, `path` FROM ?_sounds_files sf WHERE id IN (?a)', array_keys($this->fileBuffer));
|
||||
foreach ($files as $id => $data)
|
||||
{
|
||||
// 3.3.5 bandaid - need fullpath to play via wow API, remove for cata and later
|
||||
$data['path'] = str_replace('\\', '\\\\', $data['path'] ? $data['path'] . '\\' . $data['title'] : $data['title']);
|
||||
// skipp file extension
|
||||
$data['title'] = substr($data['title'], 0, -4);
|
||||
// enum to string
|
||||
$data['type'] = self::$fileTypes[$data['type']];
|
||||
// get real url
|
||||
$data['url'] = STATIC_URL . '/wowsounds/' . $data['id'];
|
||||
// v push v
|
||||
$this->fileBuffer[$id] = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getListviewData()
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[$this->id] = array(
|
||||
'id' => $this->id,
|
||||
'type' => $this->getField('cat'),
|
||||
'name' => $this->getField('name'),
|
||||
'files' => array_values(array_filter($this->getField('files')))
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getJSGlobals($addMask = 0)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[self::$type][$this->id] = array(
|
||||
'name' => $this->getField('name', true),
|
||||
'type' => $this->getField('cat'),
|
||||
'files' => array_values(array_filter($this->getField('files')))
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function renderTooltip() { }
|
||||
}
|
||||
|
||||
class SoundListFilter extends Filter
|
||||
{
|
||||
// fieldId => [checkType, checkValue[, fieldIsArray]]
|
||||
protected $inputFields = array(
|
||||
'na' => [FILTER_V_REGEX, '/[\p{C};%\\\\]/ui', false], // name - only printable chars, no delimiter
|
||||
'ty' => [FILTER_V_LIST, [[1, 4], 6, 9, 10, 12, 13, 14, 16, 17, [19, 23], [25, 31], 50, 52, 53], true ] // type
|
||||
);
|
||||
|
||||
// we have no criteria for this one...
|
||||
protected function createSQLForCriterium(&$cr)
|
||||
{
|
||||
unset($cr);
|
||||
$this->error = true;
|
||||
return [1];
|
||||
}
|
||||
|
||||
protected function createSQLForValues()
|
||||
{
|
||||
$parts = [];
|
||||
$_v = &$this->fiData['v'];
|
||||
|
||||
// name [str]
|
||||
if (isset($_v['na']))
|
||||
if ($_ = $this->modularizeString(['name']))
|
||||
$parts[] = $_;
|
||||
|
||||
// type [list]
|
||||
if (isset($_v['ty']))
|
||||
$parts[] = ['cat', $_v['ty']];
|
||||
|
||||
return $parts;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,15 +8,14 @@ class TitleList extends BaseType
|
||||
{
|
||||
use listviewHelper;
|
||||
|
||||
public static $type = Type::TITLE;
|
||||
public static $type = TYPE_TITLE;
|
||||
public static $brickFile = 'title';
|
||||
public static $dataTable = '?_titles';
|
||||
|
||||
public $sources = [];
|
||||
|
||||
protected $queryBase = 'SELECT t.*, id AS ARRAY_KEY FROM ?_titles t';
|
||||
protected $queryOpts = array(
|
||||
't' => [['src']], // 11: Type::TITLE
|
||||
't' => [['src']], // 11: TYPE_TITLE
|
||||
'src' => ['j' => ['?_source src ON type = 11 AND typeId = t.id', true], 's' => ', src13, moreType, moreTypeId']
|
||||
);
|
||||
|
||||
@@ -28,9 +27,9 @@ class TitleList extends BaseType
|
||||
foreach ($this->iterate() as $id => &$_curTpl)
|
||||
{
|
||||
// preparse sources - notice: under this system titles can't have more than one source (or two for achivements), which is enough for standard TC cases but may break custom cases
|
||||
if ($_curTpl['moreType'] == Type::ACHIEVEMENT)
|
||||
if ($_curTpl['moreType'] == TYPE_ACHIEVEMENT)
|
||||
$this->sources[$this->id][12][] = $_curTpl['moreTypeId'];
|
||||
else if ($_curTpl['moreType'] == Type::QUEST)
|
||||
else if ($_curTpl['moreType'] == TYPE_QUEST)
|
||||
$this->sources[$this->id][4][] = $_curTpl['moreTypeId'];
|
||||
else if ($_curTpl['src13'])
|
||||
$this->sources[$this->id][13][] = $_curTpl['src13'];
|
||||
@@ -81,10 +80,10 @@ class TitleList extends BaseType
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
{
|
||||
$data[Type::TITLE][$this->id]['name'] = $this->getField('male', true);
|
||||
$data[TYPE_TITLE][$this->id]['name'] = $this->getField('male', true);
|
||||
|
||||
if ($_ = $this->getField('female', true))
|
||||
$data[Type::TITLE][$this->id]['namefemale'] = $_;
|
||||
$data[TYPE_TITLE][$this->id]['namefemale'] = $_;
|
||||
}
|
||||
|
||||
return $data;
|
||||
@@ -115,6 +114,9 @@ class TitleList extends BaseType
|
||||
if (!empty($sources[12]))
|
||||
$sources[12] = (new AchievementList(array(['id', $sources[12]])))->getSourceData();
|
||||
|
||||
if (!empty($sources[13]))
|
||||
$sources[13] = DB::Aowow()->SELECT('SELECT *, Id AS ARRAY_KEY FROM ?_sourcestrings WHERE Id IN (?a)', $sources[13]);
|
||||
|
||||
foreach ($this->sources as $Id => $src)
|
||||
{
|
||||
$tmp = [];
|
||||
@@ -145,7 +147,7 @@ class TitleList extends BaseType
|
||||
|
||||
// other source (only one item possible, so no iteration needed)
|
||||
if (isset($src[13]))
|
||||
$tmp[13] = [Lang::game('pvpSources', $this->sources[$Id][13][0])];
|
||||
$tmp[13] = [Util::localizedString($sources[13][$this->sources[$Id][13][0]], 'source')];
|
||||
|
||||
$this->templates[$Id]['source'] = $tmp;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,8 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class UserList extends BaseType
|
||||
{
|
||||
public static $type = Type::USER;
|
||||
public static $type = TYPE_USER;
|
||||
public static $brickFile = 'user';
|
||||
public static $dataTable = ''; // doesn't have community content
|
||||
|
||||
public $sources = [];
|
||||
|
||||
@@ -52,7 +51,7 @@ class UserList extends BaseType
|
||||
// border: seen as null|1|3 .. changes the border around the avatar (i suspect its meaning changed and got decupled from premium-status with the introduction of patron-status)
|
||||
}
|
||||
|
||||
return [Type::USER => $data];
|
||||
return [TYPE_USER => $data];
|
||||
}
|
||||
|
||||
public function renderTooltip() { }
|
||||
|
||||
@@ -6,11 +6,10 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class WorldEventList extends BaseType
|
||||
{
|
||||
public static $type = Type::WORLDEVENT;
|
||||
public static $type = TYPE_WORLDEVENT;
|
||||
public static $brickFile = 'event';
|
||||
public static $dataTable = '?_events';
|
||||
|
||||
protected $queryBase = 'SELECT e.*, h.*, e.description AS nameINT, e.id AS id, e.id AS ARRAY_KEY FROM ?_events e';
|
||||
protected $queryBase = 'SELECT *, -e.id as id, -e.id AS ARRAY_KEY FROM ?_events e';
|
||||
protected $queryOpts = array(
|
||||
'e' => [['h']],
|
||||
'h' => ['j' => ['?_holidays h ON e.holidayId = h.id', true], 'o' => '-e.id ASC']
|
||||
@@ -41,18 +40,22 @@ class WorldEventList extends BaseType
|
||||
if ($this->curTpl['requires'])
|
||||
$this->curTpl['requires'] = explode(' ', $this->curTpl['requires']);
|
||||
|
||||
$this->curTpl['eventBak'] = -$this->curTpl['id'];
|
||||
|
||||
// change Ids if holiday is set
|
||||
if ($this->curTpl['holidayId'] > 0)
|
||||
{
|
||||
$this->curTpl['id'] = $this->curTpl['holidayId'];
|
||||
$this->curTpl['name'] = $this->getField('name', true);
|
||||
$replace[$this->id] = $this->curTpl;
|
||||
unset($this->curTpl['description']);
|
||||
}
|
||||
else // set a name if holiday is missing
|
||||
{
|
||||
// template
|
||||
$this->curTpl['name_loc0'] = $this->curTpl['nameINT'];
|
||||
$this->curTpl['name_loc0'] = $this->curTpl['description'];
|
||||
$this->curTpl['iconString'] = 'trade_engineering';
|
||||
$this->curTpl['name'] = '(SERVERSIDE) '.$this->getField('nameINT', true);
|
||||
$this->curTpl['name'] = '(SERVERSIDE) '.$this->getField('description', true);
|
||||
$replace[$this->id] = $this->curTpl;
|
||||
}
|
||||
}
|
||||
@@ -66,22 +69,10 @@ class WorldEventList extends BaseType
|
||||
|
||||
public static function getName($id)
|
||||
{
|
||||
$row = DB::Aowow()->SelectRow('
|
||||
SELECT
|
||||
IFNULL(h.name_loc0, e.description) AS name_loc0,
|
||||
h.name_loc2,
|
||||
h.name_loc3,
|
||||
h.name_loc4,
|
||||
h.name_loc6,
|
||||
h.name_loc8
|
||||
FROM
|
||||
?_events e
|
||||
LEFT JOIN
|
||||
?_holidays h ON e.holidayId = h.id
|
||||
WHERE
|
||||
e.id = ?d',
|
||||
$id
|
||||
);
|
||||
if ($id > 0)
|
||||
$row = DB::Aowow()->SelectRow('SELECT * FROM ?_holidays WHERE Id = ?d', intVal($id));
|
||||
else
|
||||
$row = DB::Aowow()->SelectRow('SELECT description as name FROM ?_events WHERE Id = ?d', intVal(-$id));
|
||||
|
||||
return Util::localizedString($row, 'name');
|
||||
}
|
||||
@@ -162,36 +153,12 @@ class WorldEventList extends BaseType
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[Type::WORLDEVENT][$this->id] = ['name' => $this->getField('name', true), 'icon' => $this->curTpl['iconString']];
|
||||
$data[TYPE_WORLDEVENT][$this->id] = ['name' => $this->getField('name', true), 'icon' => $this->curTpl['iconString']];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function renderTooltip()
|
||||
{
|
||||
if (!$this->curTpl)
|
||||
return null;
|
||||
|
||||
$x = '<table><tr><td>';
|
||||
|
||||
// head v that extra % is nesecary because we are using sprintf later on
|
||||
$x .= '<table width="100%%"><tr><td><b>'.$this->getField('name', true).'</b></td><th><b class="q0">'.Lang::event('category', $this->getField('category')).'</b></th></tr></table>';
|
||||
|
||||
// use string-placeholder for dates
|
||||
// start
|
||||
$x .= Lang::event('start').Lang::main('colon').'%s<br>';
|
||||
// end
|
||||
$x .= Lang::event('end').Lang::main('colon').'%s';
|
||||
|
||||
$x .= '</td></tr></table>';
|
||||
|
||||
// desc
|
||||
if ($this->getField('holidayId'))
|
||||
if ($_ = $this->getField('description', true))
|
||||
$x .= '<table><tr><td><span class="q">'.$_.'</span></td></tr></table>';
|
||||
|
||||
return $x;
|
||||
}
|
||||
public function renderTooltip() { }
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -8,11 +8,10 @@ class ZoneList extends BaseType
|
||||
{
|
||||
use listviewHelper;
|
||||
|
||||
public static $type = Type::ZONE;
|
||||
public static $type = TYPE_ZONE;
|
||||
public static $brickFile = 'zone';
|
||||
public static $dataTable = '?_zones';
|
||||
|
||||
protected $queryBase = 'SELECT z.*, id AS ARRAY_KEY FROM ?_zones z';
|
||||
protected $queryBase = 'SELECT *, id AS ARRAY_KEY FROM ?_zones z';
|
||||
|
||||
public function __construct($conditions = [], $miscData = null)
|
||||
{
|
||||
@@ -54,7 +53,7 @@ class ZoneList extends BaseType
|
||||
// use if you JUST need the name
|
||||
public static function getName($id)
|
||||
{
|
||||
$n = DB::Aowow()->selectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8 FROM ?_zones WHERE id = ?d', $id );
|
||||
$n = DB::Aowow()->selectRow('SELECT name_loc0, name_loc2, name_loc3, name_loc6, name_loc8 FROM ?_zones WHERE id = ?d', $id );
|
||||
return Util::localizedString($n, 'name');
|
||||
}
|
||||
|
||||
@@ -100,7 +99,7 @@ class ZoneList extends BaseType
|
||||
$data = [];
|
||||
|
||||
foreach ($this->iterate() as $__)
|
||||
$data[Type::ZONE][$this->id] = ['name' => $this->getField('name', true)];
|
||||
$data[TYPE_ZONE][$this->id] = ['name' => $this->getField('name', true)];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ class User
|
||||
private static $dataKey = '';
|
||||
private static $expires = false;
|
||||
private static $passHash = '';
|
||||
private static $excludeGroups = 1;
|
||||
private static $profiles = null;
|
||||
|
||||
public static function init()
|
||||
{
|
||||
@@ -41,7 +39,7 @@ class User
|
||||
// check IP bans
|
||||
if ($ipBan = DB::Aowow()->selectRow('SELECT count, unbanDate FROM ?_account_bannedips WHERE ip = ? AND type = 0', self::$ip))
|
||||
{
|
||||
if ($ipBan['count'] > CFG_ACC_FAILED_AUTH_COUNT && $ipBan['unbanDate'] > time())
|
||||
if ($ipBan['count'] > CFG_FAILED_AUTH_COUNT && $ipBan['unbanDate'] > time())
|
||||
return false;
|
||||
else if ($ipBan['unbanDate'] <= time())
|
||||
DB::Aowow()->query('DELETE FROM ?_account_bannedips WHERE ip = ?', self::$ip);
|
||||
@@ -56,7 +54,7 @@ class User
|
||||
return false;
|
||||
|
||||
$query = DB::Aowow()->SelectRow('
|
||||
SELECT a.id, a.passHash, a.displayName, a.locale, a.userGroups, a.userPerms, a.allowExpire, BIT_OR(ab.typeMask) AS bans, IFNULL(SUM(r.amount), 0) as reputation, a.avatar, a.dailyVotes, a.excludeGroups
|
||||
SELECT a.id, a.passHash, a.displayName, a.locale, a.userGroups, a.userPerms, a.allowExpire, BIT_OR(ab.typeMask) AS bans, IFNULL(SUM(r.amount), 0) as reputation, a.avatar, a.dailyVotes
|
||||
FROM ?_account a
|
||||
LEFT JOIN ?_account_banned ab ON a.id = ab.userId AND ab.end > UNIX_TIMESTAMP()
|
||||
LEFT JOIN ?_account_reputation r ON a.id = r.userId
|
||||
@@ -84,17 +82,6 @@ class User
|
||||
self::$groups = $query['bans'] & (ACC_BAN_TEMP | ACC_BAN_PERM) ? 0 : intval($query['userGroups']);
|
||||
self::$perms = $query['bans'] & (ACC_BAN_TEMP | ACC_BAN_PERM) ? 0 : intval($query['userPerms']);
|
||||
self::$dailyVotes = $query['dailyVotes'];
|
||||
self::$excludeGroups = $query['excludeGroups'];
|
||||
|
||||
$conditions = array(
|
||||
[['cuFlags', PROFILER_CU_DELETED, '&'], 0],
|
||||
['OR', ['user', self::$id], ['ap.accountId', self::$id]]
|
||||
);
|
||||
|
||||
if (self::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
|
||||
array_shift($conditions);
|
||||
|
||||
self::$profiles = (new LocalProfileList($conditions));
|
||||
|
||||
if ($query['avatar'])
|
||||
self::$avatar = $query['avatar'];
|
||||
@@ -125,7 +112,7 @@ class User
|
||||
);
|
||||
|
||||
// gain rep for daily visit
|
||||
if (!(self::$banStatus & (ACC_BAN_TEMP | ACC_BAN_PERM)) && !self::isInGroup(U_GROUP_PENDING))
|
||||
if (!(self::$banStatus & (ACC_BAN_TEMP | ACC_BAN_PERM)))
|
||||
Util::gainSiteReputation(self::$id, SITEREP_ACTION_DAILYVISIT);
|
||||
|
||||
// increment consecutive visits (next day or first of new month and not more than 48h)
|
||||
@@ -153,11 +140,11 @@ class User
|
||||
$rawIp = explode(',', $rawIp)[0]; // [ip, proxy1, proxy2]
|
||||
|
||||
// check IPv4
|
||||
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
|
||||
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))
|
||||
break;
|
||||
|
||||
// check IPv6
|
||||
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))
|
||||
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -183,27 +170,17 @@ class User
|
||||
{
|
||||
$loc = strtolower(substr($_SERVER["HTTP_ACCEPT_LANGUAGE"], 0, 2));
|
||||
switch ($loc) {
|
||||
case 'fr': $loc = LOCALE_FR; break;
|
||||
case 'de': $loc = LOCALE_DE; break;
|
||||
case 'zh': $loc = LOCALE_CN; break; // may cause issues in future with zh-tw
|
||||
case 'es': $loc = LOCALE_ES; break;
|
||||
case 'ru': $loc = LOCALE_RU; break;
|
||||
case 'es': $loc = LOCALE_ES; break;
|
||||
case 'de': $loc = LOCALE_DE; break;
|
||||
case 'fr': $loc = LOCALE_FR; break;
|
||||
default: $loc = LOCALE_EN;
|
||||
}
|
||||
}
|
||||
|
||||
// check; pick first viable if failed
|
||||
if (CFG_LOCALES && !(CFG_LOCALES & (1 << $loc)))
|
||||
{
|
||||
foreach (Util::$localeStrings as $idx => $__)
|
||||
{
|
||||
if (CFG_LOCALES & (1 << $idx))
|
||||
{
|
||||
$loc = $idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// check
|
||||
if ($loc != LOCALE_EN && !(CFG_LOCALES & (1 << $loc)))
|
||||
$loc = LOCALE_EN;
|
||||
|
||||
// set
|
||||
if (self::$id)
|
||||
@@ -236,7 +213,7 @@ class User
|
||||
$user = 0;
|
||||
$hash = '';
|
||||
|
||||
switch (CFG_ACC_AUTH_MODE)
|
||||
switch (CFG_AUTH_MODE)
|
||||
{
|
||||
case AUTH_MODE_SELF:
|
||||
{
|
||||
@@ -246,11 +223,11 @@ class User
|
||||
// handle login try limitation
|
||||
$ip = DB::Aowow()->selectRow('SELECT ip, count, unbanDate FROM ?_account_bannedips WHERE type = 0 AND ip = ?', self::$ip);
|
||||
if (!$ip || $ip['unbanDate'] < time()) // no entry exists or time expired; set count to 1
|
||||
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (ip, type, count, unbanDate) VALUES (?, 0, 1, UNIX_TIMESTAMP() + ?d)', self::$ip, CFG_ACC_FAILED_AUTH_BLOCK);
|
||||
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (ip, type, count, unbanDate) VALUES (?, 0, 1, UNIX_TIMESTAMP() + ?d)', self::$ip, CFG_FAILED_AUTH_EXCLUSION);
|
||||
else // entry already exists; increment count
|
||||
DB::Aowow()->query('UPDATE ?_account_bannedips SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ?', CFG_ACC_FAILED_AUTH_BLOCK, self::$ip);
|
||||
DB::Aowow()->query('UPDATE ?_account_bannedips SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ?', CFG_FAILED_AUTH_EXCLUSION, self::$ip);
|
||||
|
||||
if ($ip && $ip['count'] >= CFG_ACC_FAILED_AUTH_COUNT && $ip['unbanDate'] >= time())
|
||||
if ($ip && $ip['count'] >= CFG_FAILED_AUTH_COUNT && $ip['unbanDate'] >= time())
|
||||
return AUTH_IPBANNED;
|
||||
|
||||
$query = DB::Aowow()->SelectRow('
|
||||
@@ -268,6 +245,9 @@ class User
|
||||
if (!self::verifyCrypt($pass))
|
||||
return AUTH_WRONGPASS;
|
||||
|
||||
if ($query['status'] & ACC_STATUS_NEW)
|
||||
return AUTH_ACC_INACTIVE;
|
||||
|
||||
// successfull auth; clear bans for this IP
|
||||
DB::Aowow()->query('DELETE FROM ?_account_bannedips WHERE type = 0 AND ip = ?', self::$ip);
|
||||
|
||||
@@ -283,11 +263,12 @@ class User
|
||||
if (!DB::isConnectable(DB_AUTH))
|
||||
return AUTH_INTERNAL_ERR;
|
||||
|
||||
$wow = DB::Auth()->selectRow('SELECT a.id, a.salt, a.verifier, ab.active AS hasBan FROM account a LEFT JOIN account_banned ab ON ab.id = a.id AND active <> 0 WHERE username = ? LIMIT 1', $name);
|
||||
$wow = DB::Auth()->selectRow('SELECT a.id, a.sha_pass_hash, ab.active AS hasBan FROM account a LEFT JOIN account_banned ab ON ab.id = a.id AND active <> 0 WHERE username = ? LIMIT 1', $name);
|
||||
if (!$wow)
|
||||
return AUTH_WRONGUSER;
|
||||
|
||||
if (!self::verifySRP6($name, $pass, $wow['salt'], $wow['verifier']))
|
||||
self::$passHash = $wow['sha_pass_hash'];
|
||||
if (!self::verifySHA1($name, $pass))
|
||||
return AUTH_WRONGPASS;
|
||||
|
||||
if ($wow['hasBan'])
|
||||
@@ -306,13 +287,11 @@ class User
|
||||
return AUTH_INTERNAL_ERR;
|
||||
|
||||
require 'config/extAuth.php';
|
||||
|
||||
$extGroup = -1;
|
||||
$result = extAuth($name, $pass, $extId, $extGroup);
|
||||
$result = extAuth($name, $pass, $extId);
|
||||
|
||||
if ($result == AUTH_OK && $extId)
|
||||
{
|
||||
if ($_ = self::checkOrCreateInDB($extId, $name, $extGroup))
|
||||
if ($_ = self::checkOrCreateInDB($extId, $name))
|
||||
$user = $_;
|
||||
else
|
||||
return AUTH_INTERNAL_ERR;
|
||||
@@ -335,28 +314,18 @@ class User
|
||||
}
|
||||
|
||||
// create a linked account for our settings if nessecary
|
||||
private static function checkOrCreateInDB($extId, $name, $userGroup = -1)
|
||||
private static function checkOrCreateInDB($extId, $name)
|
||||
{
|
||||
if (!intVal($extId))
|
||||
return 0;
|
||||
|
||||
$userGroup = intVal($userGroup);
|
||||
|
||||
if ($_ = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE extId = ?d', $extId))
|
||||
{
|
||||
if ($userGroup >= U_GROUP_NONE)
|
||||
DB::Aowow()->query('UPDATE ?_account SET userGroups = ?d WHERE extId = ?d', $userGroup, $extId);
|
||||
return $_;
|
||||
}
|
||||
|
||||
$newId = DB::Aowow()->query('INSERT IGNORE INTO ?_account (extId, user, displayName, joinDate, prevIP, prevLogin, locale, status, userGroups) VALUES (?d, ?, ?, UNIX_TIMESTAMP(), ?, UNIX_TIMESTAMP(), ?d, ?d, ?d)',
|
||||
$newId = DB::Aowow()->query('INSERT IGNORE INTO ?_account (extId, user, displayName, joinDate, prevIP, prevLogin, locale, status) VALUES (?d, ?, ?, UNIX_TIMESTAMP(), ?, UNIX_TIMESTAMP(), ?d, ?d)',
|
||||
$extId,
|
||||
$name,
|
||||
Util::ucFirst($name),
|
||||
isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : '',
|
||||
User::$localeId,
|
||||
ACC_STATUS_OK,
|
||||
$userGroup >= U_GROUP_NONE ? $userGroup : U_GROUP_NONE
|
||||
ACC_STATUS_OK
|
||||
);
|
||||
|
||||
if ($newId)
|
||||
@@ -383,43 +352,27 @@ class User
|
||||
public static function verifyCrypt($pass, $hash = '')
|
||||
{
|
||||
$_ = $hash ?: self::$passHash;
|
||||
return $_ === crypt($pass, $_);
|
||||
return $_ == crypt($pass, $_);
|
||||
}
|
||||
|
||||
private static function verifySRP6($user, $pass, $salt, $verifier)
|
||||
// sha1 used by TC / MaNGOS
|
||||
private static function hashSHA1($name, $pass)
|
||||
{
|
||||
$g = gmp_init(7);
|
||||
$N = gmp_init('894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7', 16);
|
||||
$x = gmp_import(
|
||||
sha1($salt . sha1(strtoupper($user . ':' . $pass), TRUE), TRUE),
|
||||
1,
|
||||
GMP_LSW_FIRST
|
||||
);
|
||||
$v = gmp_powm($g, $x, $N);
|
||||
return ($verifier === str_pad(gmp_export($v, 1, GMP_LSW_FIRST), 32, chr(0), STR_PAD_RIGHT));
|
||||
return sha1(strtoupper($name).':'.strtoupper($pass));
|
||||
}
|
||||
|
||||
private static function verifySHA1($name, $pass)
|
||||
{
|
||||
return self::$passHash == self::hashSHA1($name, $pass);
|
||||
}
|
||||
|
||||
public static function isValidName($name, &$errCode = 0)
|
||||
{
|
||||
$errCode = 0;
|
||||
|
||||
// different auth modes require different usernames
|
||||
$min = 0; // external case
|
||||
$max = 0;
|
||||
if (CFG_ACC_AUTH_MODE == AUTH_MODE_SELF)
|
||||
{
|
||||
$min = 4;
|
||||
$max = 16;
|
||||
}
|
||||
else if (CFG_ACC_AUTH_MODE == AUTH_MODE_REALM)
|
||||
{
|
||||
$min = 3;
|
||||
$max = 32;
|
||||
}
|
||||
|
||||
if (($min && mb_strlen($name) < $min) || ($max && mb_strlen($name) > $max))
|
||||
if (strlen($name) < 4 || strlen($name) > 16)
|
||||
$errCode = 1;
|
||||
else if (preg_match('/[^\w\d\-]/i', $name))
|
||||
else if (preg_match('/[^\w\d]/i', $name))
|
||||
$errCode = 2;
|
||||
|
||||
return $errCode == 0;
|
||||
@@ -429,8 +382,7 @@ class User
|
||||
{
|
||||
$errCode = 0;
|
||||
|
||||
// only enforce for own passwords
|
||||
if (mb_strlen($pass) < 6 && CFG_ACC_AUTH_MODE == AUTH_MODE_SELF)
|
||||
if (strlen($pass) < 6 || strlen($pass) > 16)
|
||||
$errCode = 1;
|
||||
// else if (preg_match('/[^\w\d!"#\$%]/', $pass)) // such things exist..? :o
|
||||
// $errCode = 2;
|
||||
@@ -478,14 +430,6 @@ class User
|
||||
return self::$perms || self::$reputation >= CFG_REP_REQ_COMMENT;
|
||||
}
|
||||
|
||||
public static function canReply()
|
||||
{
|
||||
if (!self::$id || self::$banStatus & (ACC_BAN_COMMENT | ACC_BAN_PERM | ACC_BAN_TEMP))
|
||||
return false;
|
||||
|
||||
return self::$perms || self::$reputation >= CFG_REP_REQ_REPLY;
|
||||
}
|
||||
|
||||
public static function canUpvote()
|
||||
{
|
||||
if (!self::$id || self::$banStatus & (ACC_BAN_COMMENT | ACC_BAN_PERM | ACC_BAN_TEMP))
|
||||
@@ -510,30 +454,6 @@ class User
|
||||
return self::$reputation >= CFG_REP_REQ_SUPERVOTE;
|
||||
}
|
||||
|
||||
public static function canUploadScreenshot()
|
||||
{
|
||||
if (!self::$id || self::$banStatus & (ACC_BAN_SCREENSHOT | ACC_BAN_PERM | ACC_BAN_TEMP))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function canWriteGuide()
|
||||
{
|
||||
if (!self::$id || self::$banStatus & (ACC_BAN_GUIDE | ACC_BAN_PERM | ACC_BAN_TEMP))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function canSuggestVideo()
|
||||
{
|
||||
if (!self::$id || self::$banStatus & (ACC_BAN_VIDEO | ACC_BAN_PERM | ACC_BAN_TEMP))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function isPremium()
|
||||
{
|
||||
return self::isInGroup(U_GROUP_PREMIUM) || self::$reputation >= CFG_REP_REQ_PREMIUM;
|
||||
@@ -580,26 +500,18 @@ class User
|
||||
if (!self::$id || self::$banStatus & (ACC_BAN_TEMP | ACC_BAN_PERM))
|
||||
return $gUser;
|
||||
|
||||
$gUser['commentban'] = !self::canComment();
|
||||
$gUser['commentban'] = (bool)(self::$banStatus & ACC_BAN_COMMENT);
|
||||
$gUser['canUpvote'] = self::canUpvote();
|
||||
$gUser['canDownvote'] = self::canDownvote();
|
||||
$gUser['canPostReplies'] = self::canReply();
|
||||
$gUser['canPostReplies'] = self::canComment();
|
||||
$gUser['superCommentVotes'] = self::canSupervote();
|
||||
$gUser['downvoteRep'] = CFG_REP_REQ_DOWNVOTE;
|
||||
$gUser['upvoteRep'] = CFG_REP_REQ_UPVOTE;
|
||||
$gUser['characters'] = self::getCharacters();
|
||||
$gUser['excludegroups'] = self::$excludeGroups;
|
||||
$gUser['settings'] = (new StdClass); // profiler requires this to be set; has property premiumborder (NYI)
|
||||
|
||||
if ($_ = self::getProfilerExclusions())
|
||||
$gUser = array_merge($gUser, $_);
|
||||
|
||||
if ($_ = self::getProfiles())
|
||||
$gUser['profiles'] = $_;
|
||||
|
||||
if ($_ = self::getGuides())
|
||||
$gUser['guides'] = $_;
|
||||
|
||||
if ($_ = self::getWeightScales())
|
||||
$gUser['weightscales'] = $_;
|
||||
|
||||
@@ -611,59 +523,63 @@ class User
|
||||
|
||||
public static function getWeightScales()
|
||||
{
|
||||
$result = [];
|
||||
$data = [];
|
||||
|
||||
$res = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, name FROM ?_account_weightscales WHERE userId = ?d', self::$id);
|
||||
if (!$res)
|
||||
return $result;
|
||||
$res = DB::Aowow()->select('SELECT * FROM ?_account_weightscales WHERE userId = ?d', self::$id);
|
||||
foreach ($res as $i)
|
||||
{
|
||||
$set = array (
|
||||
'name' => $i['name'],
|
||||
'id' => $i['id']
|
||||
);
|
||||
|
||||
$weights = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, `field` AS ARRAY_KEY2, val FROM ?_account_weightscale_data WHERE id IN (?a)', array_keys($res));
|
||||
foreach ($weights as $id => $data)
|
||||
$result[] = array_merge(['name' => $res[$id], 'id' => $id], $data);
|
||||
$weights = explode(',', $i['weights']);
|
||||
foreach ($weights as $weight)
|
||||
{
|
||||
$w = explode(':', $weight);
|
||||
|
||||
return $result;
|
||||
if ($w[1] === 'undefined')
|
||||
$w[1] = 0;
|
||||
|
||||
$set[$w[0]] = $w[1];
|
||||
}
|
||||
|
||||
public static function getProfilerExclusions()
|
||||
{
|
||||
$result = [];
|
||||
$modes = [1 => 'excludes', 2 => 'includes'];
|
||||
foreach ($modes as $mode => $field)
|
||||
if ($ex = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, typeId AS ARRAY_KEY2, typeId FROM ?_account_excludes WHERE mode = ?d AND userId = ?d', $mode, self::$id))
|
||||
foreach ($ex as $type => $ids)
|
||||
$result[$field][$type] = array_values($ids);
|
||||
$data[] = $set;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function getCharacters()
|
||||
{
|
||||
if (!self::$profiles)
|
||||
return [];
|
||||
// existing chars on realm(s)
|
||||
$characters = array(
|
||||
// array(
|
||||
// 'id' => 22,
|
||||
// 'name' => 'Example Char',
|
||||
// 'realmname' => 'Example Realm',
|
||||
// 'region' => 'eu',
|
||||
// 'realm' => 'example-realm',
|
||||
// 'race' => 6,
|
||||
// 'classs' => 11,
|
||||
// 'level' => 80,
|
||||
// 'gender' => 1,
|
||||
// 'pinned' => 1
|
||||
// )
|
||||
);
|
||||
|
||||
return self::$profiles->getJSGlobals(PROFILEINFO_CHARACTER);
|
||||
return $characters;
|
||||
}
|
||||
|
||||
public static function getProfiles()
|
||||
{
|
||||
if (!self::$profiles)
|
||||
return [];
|
||||
// chars build in profiler
|
||||
$profiles = array(
|
||||
// array('id' => 21, 'name' => 'Example Profile 1', 'race' => 4, 'classs' => 5, 'level' => 72, 'gender' => 1, 'icon' => 'inv_axe_04'),
|
||||
// array('id' => 23, 'name' => 'Example Profile 2', 'race' => 11, 'classs' => 3, 'level' => 17, 'gender' => 0)
|
||||
);
|
||||
|
||||
return self::$profiles->getJSGlobals(PROFILEINFO_PROFILE);
|
||||
}
|
||||
|
||||
public static function getGuides()
|
||||
{
|
||||
$result = [];
|
||||
|
||||
if ($guides = DB::Aowow()->select('SELECT `id`, `title`, `url` FROM ?_guides WHERE `userId` = ?d AND `status` <> ?d', self::$id, GUIDE_STATUS_ARCHIVED))
|
||||
{
|
||||
// fix url
|
||||
array_walk($guides, fn(&$x) => $x['url'] = '/?guide='.($x['url'] ?? $x['id']));
|
||||
$result = $guides;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $profiles;
|
||||
}
|
||||
|
||||
public static function getCookies()
|
||||
@@ -675,33 +591,6 @@ class User
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function getFavorites()
|
||||
{
|
||||
if (!self::$id)
|
||||
return [];
|
||||
|
||||
$res = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, `typeId` AS ARRAY_KEY2, `typeId` FROM ?_account_favorites WHERE `userId` = ?d', self::$id);
|
||||
if (!$res)
|
||||
return [];
|
||||
|
||||
$data = [];
|
||||
foreach ($res as $type => $ids)
|
||||
{
|
||||
$tc = Type::newList($type, [['id', array_values($ids)]]);
|
||||
if (!$tc || $tc->error)
|
||||
continue;
|
||||
|
||||
$entities = [];
|
||||
foreach ($tc->iterate() as $id => $__)
|
||||
$entities[] = [$id, $tc->getField('name', true, true)];
|
||||
|
||||
if ($entities)
|
||||
$data[] = ['id' => $type, 'entities' => $entities];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
91
index.php
91
index.php
@@ -22,39 +22,24 @@ switch ($pageCall)
|
||||
case 'account': // account management [nyi]
|
||||
case 'achievement':
|
||||
case 'achievements':
|
||||
case 'areatrigger':
|
||||
case 'areatriggers':
|
||||
case 'arena-team':
|
||||
case 'arena-teams':
|
||||
// case 'arena-team':
|
||||
// case 'arena-teams':
|
||||
case 'class':
|
||||
case 'classes':
|
||||
case 'currency':
|
||||
case 'currencies':
|
||||
case 'compare': // tool: item comparison
|
||||
case 'emote':
|
||||
case 'emotes':
|
||||
case 'enchantment':
|
||||
case 'enchantments':
|
||||
case 'event':
|
||||
case 'events':
|
||||
case 'faction':
|
||||
case 'factions':
|
||||
case 'guide':
|
||||
case 'guides':
|
||||
case 'guild':
|
||||
case 'guilds':
|
||||
case 'icon':
|
||||
case 'icons':
|
||||
// case 'guild':
|
||||
// case 'guilds':
|
||||
case 'item':
|
||||
case 'items':
|
||||
case 'itemset':
|
||||
case 'itemsets':
|
||||
case 'maps': // tool: map listing
|
||||
case 'mail':
|
||||
case 'mails':
|
||||
case 'my-guides':
|
||||
if ($pageCall == 'my-guides')
|
||||
$altClass = 'guides';
|
||||
case 'npc':
|
||||
case 'npcs':
|
||||
case 'object':
|
||||
@@ -75,8 +60,8 @@ switch ($pageCall)
|
||||
case 'search': // tool: searches
|
||||
case 'skill':
|
||||
case 'skills':
|
||||
case 'sound':
|
||||
case 'sounds':
|
||||
// case 'sound': // db: sounds for zone, creature, spell, ...
|
||||
// case 'sounds':
|
||||
case 'spell':
|
||||
case 'spells':
|
||||
case 'talent': // tool: talent calculator
|
||||
@@ -86,51 +71,17 @@ switch ($pageCall)
|
||||
case 'video':
|
||||
case 'zone':
|
||||
case 'zones':
|
||||
/* called by script */
|
||||
case 'data': // tool: dataset-loader
|
||||
case 'cookie': // lossless cookies and user settings
|
||||
case 'contactus':
|
||||
case 'comment':
|
||||
case 'edit': // guide editor: targeted by QQ fileuploader, detail-page article editor
|
||||
case 'get-description': // guide editor: shorten fulltext into description
|
||||
case 'filter': // pre-evaluate filter POST-data; sanitize and forward as GET-data
|
||||
case 'go-to-comment': // find page the comment is on and forward
|
||||
case 'locale': // subdomain-workaround, change the language
|
||||
$cleanName = str_replace(['-', '_'], '', ucFirst($altClass ?: $pageCall));
|
||||
try // can it be handled as ajax?
|
||||
if (in_array($pageCall, ['admin', 'account', 'profile']))
|
||||
{
|
||||
$out = '';
|
||||
$class = 'Ajax'.$cleanName;
|
||||
$ajax = new $class(explode('.', $pageParam));
|
||||
|
||||
if ($ajax->handle($out))
|
||||
if (($_ = (new AjaxHandler($pageParam))->handle($pageCall)) !== null)
|
||||
{
|
||||
Util::sendNoCacheHeader();
|
||||
|
||||
if ($ajax->doRedirect)
|
||||
header('Location: '.$out, true, 302);
|
||||
else
|
||||
{
|
||||
header($ajax->getContentType());
|
||||
die($out);
|
||||
header('Content-type: application/x-javascript; charset=utf-8');
|
||||
die((string)$_);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new Exception('not handled as ajax');
|
||||
}
|
||||
catch (Exception $e) // no, apparently not..
|
||||
{
|
||||
$class = $cleanName.'Page';
|
||||
$classInstance = new $class($pageCall, $pageParam);
|
||||
|
||||
if (is_callable([$classInstance, 'display']))
|
||||
$classInstance->display();
|
||||
else if (isset($_GET['power']))
|
||||
die('$WowheadPower.register(0, '.User::$localeId.', {})');
|
||||
else // in conjunction with a proper rewriteRule in .htaccess...
|
||||
(new GenericPage($pageCall))->error();
|
||||
}
|
||||
|
||||
$_ = ($altClass ?: $pageCall).'Page';
|
||||
(new $_($pageCall, $pageParam))->display();
|
||||
break;
|
||||
/* other pages */
|
||||
case 'whats-new':
|
||||
@@ -140,13 +91,10 @@ switch ($pageCall)
|
||||
case 'help':
|
||||
case 'faq':
|
||||
case 'aboutus':
|
||||
case 'reputation':
|
||||
case 'privilege':
|
||||
case 'privileges':
|
||||
case 'top-users':
|
||||
(new MorePage($pageCall, $pageParam))->display();
|
||||
break;
|
||||
case 'latest-additions':
|
||||
case 'latest-articles':
|
||||
case 'latest-comments':
|
||||
case 'latest-screenshots':
|
||||
case 'latest-videos':
|
||||
@@ -156,6 +104,19 @@ switch ($pageCall)
|
||||
case 'random':
|
||||
(new UtilityPage($pageCall, $pageParam))->display();
|
||||
break;
|
||||
/* called by script */
|
||||
case 'data': // tool: dataset-loader
|
||||
case 'cookie': // lossless cookies and user settings
|
||||
case 'contactus':
|
||||
case 'comment':
|
||||
case 'go-to-comment': // find page the comment is on and forward
|
||||
case 'locale': // subdomain-workaround, change the language
|
||||
if (($_ = (new AjaxHandler($pageParam))->handle($pageCall)) !== null)
|
||||
{
|
||||
header('Content-type: application/x-javascript; charset=utf-8');
|
||||
die((string)$_);
|
||||
}
|
||||
break;
|
||||
default: // unk parameter given -> ErrorPage
|
||||
if (isset($_GET['power']))
|
||||
die('$WowheadPower.register(0, '.User::$localeId.', {})');
|
||||
|
||||
@@ -6,48 +6,26 @@ class Lang
|
||||
private static $main;
|
||||
private static $account;
|
||||
private static $user;
|
||||
private static $mail;
|
||||
private static $game;
|
||||
private static $maps;
|
||||
private static $profiler;
|
||||
private static $screenshot;
|
||||
private static $privileges;
|
||||
private static $smartAI;
|
||||
private static $unit;
|
||||
|
||||
// types
|
||||
private static $achievement;
|
||||
private static $areatrigger;
|
||||
private static $chrClass;
|
||||
private static $currency;
|
||||
private static $event;
|
||||
private static $faction;
|
||||
private static $gameObject;
|
||||
private static $icon;
|
||||
private static $item;
|
||||
private static $itemset;
|
||||
private static $mail;
|
||||
private static $maps;
|
||||
private static $npc;
|
||||
private static $pet;
|
||||
private static $quest;
|
||||
private static $race;
|
||||
private static $skill;
|
||||
private static $sound;
|
||||
private static $spell;
|
||||
private static $title;
|
||||
private static $zone;
|
||||
private static $guide;
|
||||
|
||||
private static $emote;
|
||||
private static $enchantment;
|
||||
|
||||
private static $locales = array(
|
||||
LOCALE_EN => 'English',
|
||||
LOCALE_FR => 'Français',
|
||||
LOCALE_DE => 'Deutsch',
|
||||
LOCALE_CN => '简体中文',
|
||||
LOCALE_ES => 'Español',
|
||||
LOCALE_RU => 'Русский'
|
||||
);
|
||||
|
||||
public static function load($loc)
|
||||
{
|
||||
@@ -59,136 +37,33 @@ class Lang
|
||||
foreach ($lang as $k => $v)
|
||||
self::$$k = $v;
|
||||
|
||||
// *cough* .. reuse-hacks (because copy-pastaing text for 5 locales sucks)
|
||||
// *cough* .. reuse-hack
|
||||
self::$item['cat'][2] = [self::$item['cat'][2], self::$spell['weaponSubClass']];
|
||||
self::$item['cat'][2][1][14] .= ' ('.self::$item['cat'][2][0].')';
|
||||
self::$main['moreTitles']['privilege'] = self::$privileges['_privileges'];
|
||||
}
|
||||
|
||||
// todo: make static props private and access through this
|
||||
public static function __callStatic($prop, $args)
|
||||
{
|
||||
if (!isset(self::$$prop))
|
||||
{
|
||||
$dbt = debug_backtrace()[0];
|
||||
$file = explode(DIRECTORY_SEPARATOR, $dbt['file']);
|
||||
trigger_error('Lang - tried to use undefined property Lang::$'.$prop.', called in '.array_pop($file).':'.$dbt['line'], E_USER_WARNING);
|
||||
Util::addNote(U_GROUP_STAFF, 'Lang::__callStatic() - tried to use undefined property Lang::$'.$prop);
|
||||
return null;
|
||||
}
|
||||
|
||||
$vspfArgs = [];
|
||||
|
||||
$var = self::$$prop;
|
||||
foreach ($args as $arg)
|
||||
foreach ($args as $key)
|
||||
{
|
||||
if (is_array($arg))
|
||||
if (!isset($var[$key]))
|
||||
{
|
||||
$vspfArgs = $arg;
|
||||
continue;
|
||||
}
|
||||
else if (!isset($var[$arg]))
|
||||
{
|
||||
$dbt = debug_backtrace()[0];
|
||||
$file = explode(DIRECTORY_SEPARATOR, $dbt['file']);
|
||||
trigger_error('Lang - undefined property Lang::$'.$prop.'[\''.implode('\'][\'', $args).'\'], called in '.array_pop($file).':'.$dbt['line'], E_USER_WARNING);
|
||||
Util::addNote(U_GROUP_STAFF, 'Lang::__callStatic() - undefined key "'.$key.'" in property Lang::$'.$prop.'[\''.implode('\'][\'', $args).'\']');
|
||||
return null;
|
||||
}
|
||||
|
||||
$var = $var[$arg];
|
||||
$var = $var[$key];
|
||||
}
|
||||
|
||||
// meh :x
|
||||
if ($var === null && $prop == 'spell' && count($args) == 1)
|
||||
{
|
||||
if ($args[0] == 'effects')
|
||||
$var = self::$$prop['unkEffect'];
|
||||
else if ($args[0] == 'auras')
|
||||
$var = self::$$prop['unkAura'];
|
||||
}
|
||||
|
||||
return self::vspf($var, $vspfArgs);
|
||||
}
|
||||
|
||||
public static function concat($args, $useAnd = true, $callback = null)
|
||||
{
|
||||
$b = '';
|
||||
$i = 0;
|
||||
$n = count($args);
|
||||
foreach ($args as $k => $arg)
|
||||
{
|
||||
if (is_callable($callback))
|
||||
$b .= $callback($arg, $k);
|
||||
else
|
||||
$b .= $arg;
|
||||
|
||||
if ($n > 1 && $i < ($n - 2))
|
||||
$b .= ', ';
|
||||
else if ($n > 1 && $i == $n - 2)
|
||||
$b .= Lang::main($useAnd ? 'and' : 'or');
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $b;
|
||||
}
|
||||
|
||||
// truncate string after X chars. If X is inside a word truncate behind it.
|
||||
public static function trimTextClean(string $text, int $len = 100) : string
|
||||
{
|
||||
// remove line breaks
|
||||
$text = strtr($text, ["\n" => ' ', "\r" => ' ']);
|
||||
|
||||
// limit whitespaces to one at a time
|
||||
$text = preg_replace('/\s+/', ' ', trim($text));
|
||||
|
||||
if ($len > 0 && mb_strlen($text) > $len)
|
||||
{
|
||||
$n = 0;
|
||||
$b = [];
|
||||
$parts = explode(' ', $text);
|
||||
while ($n < $len && $parts)
|
||||
{
|
||||
$_ = array_shift($parts);
|
||||
$n += mb_strlen($_);
|
||||
$b[] = $_;
|
||||
}
|
||||
|
||||
$text = implode(' ', $b).'…';
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
// add line breaks to string after X chars. If X is inside a word break behind it.
|
||||
public static function breakTextClean(string $text, int $len = 30, bool $asHTML = true) : string
|
||||
{
|
||||
// remove line breaks
|
||||
$text = strtr($text, ["\n" => ' ', "\r" => ' ']);
|
||||
|
||||
// limit whitespaces to one at a time
|
||||
$text = preg_replace('/\s+/', ' ', trim($text));
|
||||
|
||||
$row = [];
|
||||
if ($len > 0 && mb_strlen($text) > $len)
|
||||
{
|
||||
$i = 0;
|
||||
$n = 0;
|
||||
$parts = explode(' ', $text);
|
||||
foreach ($parts as $p)
|
||||
{
|
||||
$row[$i][] = $p;
|
||||
$n += (mb_strlen($p) + 1);
|
||||
|
||||
if ($n < $len)
|
||||
continue;
|
||||
|
||||
$n = 0;
|
||||
$i++;
|
||||
}
|
||||
foreach ($row as &$r)
|
||||
$r = implode(' ', $r);
|
||||
}
|
||||
|
||||
return implode($asHTML ? '<br />' : '[br]', $row);
|
||||
return $var;
|
||||
}
|
||||
|
||||
public static function sort($prop, $group, $method = SORT_NATURAL)
|
||||
@@ -196,14 +71,14 @@ class Lang
|
||||
|
||||
if (!isset(self::$$prop))
|
||||
{
|
||||
trigger_error('Lang::sort - tried to use undefined property Lang::$'.$prop, E_USER_WARNING);
|
||||
Util::addNote(U_GROUP_STAFF, 'Lang::sort() - tried to use undefined property Lang::$'.$prop);
|
||||
return null;
|
||||
}
|
||||
|
||||
$var = &self::$$prop;
|
||||
if (!isset($var[$group]))
|
||||
{
|
||||
trigger_error('Lang::sort - tried to use undefined property Lang::$'.$prop.'[\''.$group.'\']', E_USER_WARNING);
|
||||
Util::addNote(U_GROUP_STAFF, 'Lang::sort() - tried to use undefined property Lang::$'.$prop.'[\''.$group.'\']');
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -230,10 +105,9 @@ class Lang
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
public static function getLocks(int $lockId, ?array &$ids = [], bool $interactive = false, bool $asHTML = false) : array
|
||||
public static function getLocks($lockId, $interactive = false)
|
||||
{
|
||||
$locks = [];
|
||||
$ids = [];
|
||||
$lock = DB::Aowow()->selectRow('SELECT * FROM ?_lock WHERE id = ?d', $lockId);
|
||||
if (!$lock)
|
||||
return $locks;
|
||||
@@ -244,71 +118,47 @@ class Lang
|
||||
$rank = $lock['reqSkill'.$i];
|
||||
$name = '';
|
||||
|
||||
if ($lock['type'.$i] == LOCK_TYPE_ITEM)
|
||||
if ($lock['type'.$i] == 1) // opened by item
|
||||
{
|
||||
$name = ItemList::getName($prop);
|
||||
if (!$name)
|
||||
continue;
|
||||
|
||||
if ($interactive && $asHTML)
|
||||
if ($interactive)
|
||||
$name = '<a class="q1" href="?item='.$prop.'">'.$name.'</a>';
|
||||
else if ($interactive && !$asHTML)
|
||||
{
|
||||
$name = '[item='.$prop.']';
|
||||
$ids[Type::ITEM][] = $prop;
|
||||
}
|
||||
}
|
||||
else if ($lock['type'.$i] == LOCK_TYPE_SKILL)
|
||||
else if ($lock['type'.$i] == 2) // opened by skill
|
||||
{
|
||||
// exclude unusual stuff
|
||||
if (!in_array($prop, [1, 2, 3, 4, 9, 16, 20]))
|
||||
continue;
|
||||
|
||||
$name = self::spell('lockType', $prop);
|
||||
if (!$name)
|
||||
continue;
|
||||
|
||||
// skills
|
||||
if (in_array($prop, [1, 2, 3, 20]))
|
||||
if ($interactive)
|
||||
{
|
||||
$skills = array(
|
||||
1 => SKILL_LOCKPICKING,
|
||||
2 => SKILL_HERBALISM,
|
||||
3 => SKILL_MINING,
|
||||
20 => SKILL_INSCRIPTION
|
||||
);
|
||||
$skill = 0;
|
||||
switch ($prop)
|
||||
{
|
||||
case 1: $skill = 633; break; // Lockpicking
|
||||
case 2: $skill = 182; break; // Herbing
|
||||
case 3: $skill = 186; break; // Mining
|
||||
case 20: $skill = 773; break; // Scribing
|
||||
}
|
||||
|
||||
if ($interactive && $asHTML)
|
||||
$name = '<a href="?skill='.$skills[$prop].'">'.$name.'</a>';
|
||||
else if ($interactive && !$asHTML)
|
||||
{
|
||||
$name = '[skill='.$skills[$prop].']';
|
||||
$ids[Type::SKILL][] = $skills[$prop];
|
||||
if ($skill)
|
||||
$name = '<a href="?skill='.$skill.'">'.$name.'</a>';
|
||||
}
|
||||
|
||||
if ($rank > 0)
|
||||
$name .= ' ('.$rank.')';
|
||||
}
|
||||
// Lockpicking
|
||||
else if ($prop == 4)
|
||||
{
|
||||
if ($interactive && $asHTML)
|
||||
$name = '<a href="?spell=1842">'.$name.'</a>';
|
||||
else if ($interactive && !$asHTML)
|
||||
{
|
||||
$name = '[spell=1842]';
|
||||
$ids[Type::SPELL][] = 1842;
|
||||
}
|
||||
}
|
||||
// exclude unusual stuff
|
||||
else if (User::isInGroup(U_GROUP_STAFF))
|
||||
{
|
||||
if ($rank > 0)
|
||||
$name .= ' ('.$rank.')';
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
$locks[$lock['type'.$i] == LOCK_TYPE_ITEM ? $prop : -$prop] = $name;
|
||||
$locks[$lock['type'.$i] == 1 ? $prop : -$prop] = sprintf(self::game('requires'), $name);
|
||||
}
|
||||
|
||||
return $locks;
|
||||
@@ -316,7 +166,7 @@ class Lang
|
||||
|
||||
public static function getReputationLevelForPoints($pts)
|
||||
{
|
||||
$_ = Game::getReputationLevelForPoints($pts);
|
||||
$_ = Util::getReputationLevelForPoints($pts);
|
||||
|
||||
return self::game('rep', $_);
|
||||
}
|
||||
@@ -347,7 +197,7 @@ class Lang
|
||||
}
|
||||
|
||||
if ($class == ITEM_CLASS_MISC) // yeah hardcoded.. sue me!
|
||||
return self::spell('cat', -5, 0);
|
||||
return self::spell('cat', -5);
|
||||
|
||||
$tmp = [];
|
||||
$strs = self::spell($class == ITEM_CLASS_ARMOR ? 'armorSubClass' : 'weaponSubClass');
|
||||
@@ -355,17 +205,12 @@ class Lang
|
||||
if ($mask & (1 << $k) && $str)
|
||||
$tmp[] = $str;
|
||||
|
||||
if (!$tmp && $class == ITEM_CLASS_ARMOR)
|
||||
return self::spell('cat', -11, 8);
|
||||
else if (!$tmp && $class == ITEM_CLASS_WEAPON)
|
||||
return self::spell('cat', -11, 6);
|
||||
else
|
||||
return implode(', ', $tmp);
|
||||
}
|
||||
|
||||
public static function getStances($stanceMask)
|
||||
{
|
||||
$stanceMask &= 0xFF37F6FF; // clamp to available stances/forms..
|
||||
$stanceMask &= 0xFC27909F; // clamp to available stances/forms..
|
||||
|
||||
$tmp = [];
|
||||
$i = 1;
|
||||
@@ -402,7 +247,7 @@ class Lang
|
||||
return implode(', ', $tmp);
|
||||
}
|
||||
|
||||
public static function getClassString(int $classMask, array &$ids = [], bool $asHTML = true) : string
|
||||
public static function getClassString($classMask, &$ids = [], &$n = 0, $asHTML = true)
|
||||
{
|
||||
$classMask &= CLASS_MASK_ALL; // clamp to available classes..
|
||||
|
||||
@@ -424,26 +269,36 @@ class Lang
|
||||
$i++;
|
||||
}
|
||||
|
||||
$n = count($tmp);
|
||||
$ids = array_keys($tmp);
|
||||
|
||||
return implode(', ', $tmp);
|
||||
}
|
||||
|
||||
public static function getRaceString(int $raceMask, array &$ids = [], bool $asHTML = true) : string
|
||||
public static function getRaceString($raceMask, &$side = 0, &$ids = [], &$n = 0, $asHTML = true)
|
||||
{
|
||||
$raceMask &= RACE_MASK_ALL; // clamp to available races..
|
||||
|
||||
if ($raceMask == RACE_MASK_ALL) // available to all races (we don't display 'both factions')
|
||||
return false;
|
||||
|
||||
if (!$raceMask)
|
||||
return false;
|
||||
|
||||
$tmp = [];
|
||||
$i = 1;
|
||||
$base = $asHTML ? '<a href="?race=%d" class="q1">%s</a>' : '[race=%d]';
|
||||
$br = $asHTML ? '' : '[br]';
|
||||
|
||||
if (!$raceMask)
|
||||
{
|
||||
$side |= SIDE_BOTH;
|
||||
return self::game('ra', 0);
|
||||
}
|
||||
|
||||
if ($raceMask & RACE_MASK_HORDE)
|
||||
$side |= SIDE_HORDE;
|
||||
|
||||
if ($raceMask & RACE_MASK_ALLIANCE)
|
||||
$side |= SIDE_ALLIANCE;
|
||||
|
||||
if ($raceMask == RACE_MASK_HORDE)
|
||||
return self::game('ra', -2);
|
||||
|
||||
@@ -460,138 +315,11 @@ class Lang
|
||||
$i++;
|
||||
}
|
||||
|
||||
$n = count($tmp);
|
||||
$ids = array_keys($tmp);
|
||||
|
||||
return implode(', ', $tmp);
|
||||
}
|
||||
|
||||
public static function formatSkillBreakpoints(array $bp, bool $html = false) : string
|
||||
{
|
||||
$tmp = Lang::game('difficulty').Lang::main('colon');
|
||||
|
||||
for ($i = 0; $i < 4; $i++)
|
||||
if (!empty($bp[$i]))
|
||||
$tmp .= $html ? '<span class="r'.($i + 1).'">'.$bp[$i].'</span> ' : '[color=r'.($i + 1).']'.$bp[$i].'[/color] ';
|
||||
|
||||
return trim($tmp);
|
||||
}
|
||||
|
||||
public static function nf($number, $decimals = 0, $no1k = false)
|
||||
{
|
||||
// [decimal, thousand]
|
||||
$seps = array(
|
||||
LOCALE_EN => [',', '.'],
|
||||
LOCALE_FR => [' ', ','],
|
||||
LOCALE_DE => ['.', ','],
|
||||
LOCALE_CN => [',', '.'],
|
||||
LOCALE_ES => ['.', ','],
|
||||
LOCALE_RU => [' ', ',']
|
||||
);
|
||||
|
||||
return number_format($number, $decimals, $seps[User::$localeId][1], $no1k ? '' : $seps[User::$localeId][0]);
|
||||
}
|
||||
|
||||
public static function typeName(int $type) : string
|
||||
{
|
||||
return Util::ucFirst(self::game(Type::getFileString($type)));
|
||||
}
|
||||
|
||||
|
||||
private static function vspf($var, $args)
|
||||
{
|
||||
if (is_array($var))
|
||||
{
|
||||
foreach ($var as &$v)
|
||||
$v == self::vspf($v, $args);
|
||||
|
||||
return $var;
|
||||
}
|
||||
|
||||
if ($args)
|
||||
$var = vsprintf($var, $args);
|
||||
|
||||
// line break
|
||||
// |n
|
||||
$var = str_replace('|n', '<br />', $var);
|
||||
|
||||
// color
|
||||
// |c<aarrggbb><word>|r
|
||||
$var = preg_replace('/\|cff([a-f0-9]{6})(.+?)\|r/i', '<span style="color: #$1;">$2</span>', $var);
|
||||
|
||||
// icon
|
||||
// |T<imgPath>:0:0:0:-1|t - not used, skip if found
|
||||
$var = preg_replace('/\|T[^\|]+\|t/', '', $var);
|
||||
|
||||
// hyperlink
|
||||
// |H<hyperlinkStruct>|h<name>|h - not used, truncate structure if found
|
||||
$var = preg_replace('/\|H[^\|]+\|h([^\|]+)\|h/', '$1', $var);
|
||||
|
||||
// french preposition : de
|
||||
// |2 <word>
|
||||
$var = preg_replace_callback('/\|2\s(\w)/i', function ($m) {
|
||||
if (in_array(strtolower($m[1]), ['a', 'e', 'h', 'i', 'o', 'u']))
|
||||
return "d'".$m[1];
|
||||
else
|
||||
return 'de '.$m[1];
|
||||
}, $var);
|
||||
|
||||
// russian word cunjugation thingy
|
||||
// |3-<number>(<word>)
|
||||
$var = preg_replace_callback('/\|3-(\d)\(([^\)]+)\)/i', function ($m) {
|
||||
switch ($m[0])
|
||||
{
|
||||
case 1: // seen cases
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
default: // passthrough .. unk case
|
||||
return $m[1];
|
||||
}
|
||||
|
||||
}, $var);
|
||||
|
||||
// numeric switch
|
||||
// <number> |4<singular>:<plural>[:<plural2>];
|
||||
$var = preg_replace_callback('/([\d\.\,]+)([^\d]*)\|4([^:]*):([^;]*);/i', function ($m) {
|
||||
$plurals = explode(':', $m[4]);
|
||||
$result = '';
|
||||
|
||||
if (count($plurals) == 2) // special case: ruRU
|
||||
{
|
||||
switch (substr($m[1], -1)) // check last digit of number
|
||||
{
|
||||
case 1:
|
||||
// but not 11 (teen number)
|
||||
if (!in_array($m[1], [11]))
|
||||
{
|
||||
$result = $m[3];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
// but not 12, 13, 14 (teen number) [11 is passthrough]
|
||||
if (!in_array($m[1], [11, 12, 13, 14]))
|
||||
{
|
||||
$result = $plurals[0];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$result = $plurals[1];
|
||||
}
|
||||
}
|
||||
else
|
||||
$result = ($m[1] == 1 ? $m[3] : $plurals[0]);
|
||||
|
||||
return $m[1].$m[2].$result;
|
||||
}, $var);
|
||||
|
||||
return $var;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,8 @@ if (!defined('AOWOW_REVISION'))
|
||||
class AccountPage extends GenericPage
|
||||
{
|
||||
protected $tpl = 'acc-dashboard';
|
||||
protected $js = [[JS_FILE, 'user.js'], [JS_FILE, 'profile.js']];
|
||||
protected $css = [[CSS_FILE, 'Profiler.css']];
|
||||
protected $js = ['user.js', 'profile.js'];
|
||||
protected $css = [['path' => 'Profiler.css']];
|
||||
protected $mode = CACHE_TYPE_NONE;
|
||||
protected $category = null;
|
||||
protected $validCats = array(
|
||||
@@ -27,18 +27,13 @@ class AccountPage extends GenericPage
|
||||
protected $lvTabs = [];
|
||||
protected $banned = [];
|
||||
|
||||
protected $_get = array(
|
||||
'token' => ['filter' => FILTER_SANITIZE_SPECIAL_CHARS, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'next' => ['filter' => FILTER_SANITIZE_SPECIAL_CHARS, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
);
|
||||
|
||||
protected $_post = array(
|
||||
'username' => ['filter' => FILTER_SANITIZE_SPECIAL_CHARS, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'password' => ['filter' => FILTER_UNSAFE_RAW],
|
||||
'c_password' => ['filter' => FILTER_UNSAFE_RAW],
|
||||
'token' => ['filter' => FILTER_UNSAFE_RAW],
|
||||
'remember_me' => ['filter' => FILTER_CALLBACK, 'options' => 'AccountPage::rememberCallback'],
|
||||
'email' => ['filter' => FILTER_SANITIZE_EMAIL]
|
||||
private $_post = array(
|
||||
'username' => [FILTER_SANITIZE_SPECIAL_CHARS, 0xC], // FILTER_FLAG_STRIP_LOW | *_HIGH
|
||||
'password' => [FILTER_UNSAFE_RAW, null],
|
||||
'c_password' => [FILTER_UNSAFE_RAW, null],
|
||||
'token' => [FILTER_UNSAFE_RAW, null],
|
||||
'remember_me' => [FILTER_CALLBACK, ['options' => 'AccountPage::rememberCallback']],
|
||||
'email' => [FILTER_SANITIZE_EMAIL, null]
|
||||
);
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
@@ -48,6 +43,9 @@ class AccountPage extends GenericPage
|
||||
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
foreach ($this->_post as $k => &$v)
|
||||
$v = !empty($_POST[$k]) ? filter_input(INPUT_POST, $k, $v[0], $v[1]) : null;
|
||||
|
||||
if ($pageParam)
|
||||
{
|
||||
// requires auth && not authed
|
||||
@@ -59,7 +57,7 @@ class AccountPage extends GenericPage
|
||||
}
|
||||
}
|
||||
|
||||
protected static function rememberCallback($val)
|
||||
private function rememberCallback($val)
|
||||
{
|
||||
return $val == 'yes' ? $val : null;
|
||||
}
|
||||
@@ -75,13 +73,8 @@ class AccountPage extends GenericPage
|
||||
switch ($this->category[0])
|
||||
{
|
||||
case 'forgotpassword':
|
||||
if (CFG_ACC_AUTH_MODE != AUTH_MODE_SELF)
|
||||
{
|
||||
if (CFG_ACC_EXT_RECOVER_URL)
|
||||
header('Location: '.CFG_ACC_EXT_RECOVER_URL, true, 302);
|
||||
else
|
||||
if (CFG_AUTH_MODE != AUTH_MODE_SELF) // only recover own accounts
|
||||
$this->error();
|
||||
}
|
||||
|
||||
$this->tpl = 'acc-recover';
|
||||
$this->resetPass = false;
|
||||
@@ -92,13 +85,8 @@ class AccountPage extends GenericPage
|
||||
$this->head = sprintf(Lang::account('recoverPass'), $nStep);
|
||||
break;
|
||||
case 'forgotusername':
|
||||
if (CFG_ACC_AUTH_MODE != AUTH_MODE_SELF)
|
||||
{
|
||||
if (CFG_ACC_EXT_RECOVER_URL)
|
||||
header('Location: '.CFG_ACC_EXT_RECOVER_URL, true, 302);
|
||||
else
|
||||
if (CFG_AUTH_MODE != AUTH_MODE_SELF) // only recover own accounts
|
||||
$this->error();
|
||||
}
|
||||
|
||||
$this->tpl = 'acc-recover';
|
||||
$this->resetPass = false;
|
||||
@@ -130,22 +118,14 @@ class AccountPage extends GenericPage
|
||||
header('Location: '.$this->getNext(true), true, 302);
|
||||
}
|
||||
}
|
||||
else if ($this->_get['token'] && ($_ = DB::Aowow()->selectCell('SELECT user FROM ?_account WHERE status IN (?a) AND token = ? AND statusTimer > UNIX_TIMESTAMP()', [ACC_STATUS_RECOVER_USER, ACC_STATUS_OK], $this->_get['token'])))
|
||||
else if (!empty($_GET['token']) && ($_ = DB::Aowow()->selectCell('SELECT user FROM ?_account WHERE status IN (?a) AND token = ? AND statusTimer > UNIX_TIMESTAMP()', [ACC_STATUS_RECOVER_USER, ACC_STATUS_OK], $_GET['token'])))
|
||||
$this->user = $_;
|
||||
|
||||
break;
|
||||
case 'signup':
|
||||
if (!CFG_ACC_ALLOW_REGISTER)
|
||||
if (!CFG_ALLOW_REGISTER || CFG_AUTH_MODE != AUTH_MODE_SELF)
|
||||
$this->error();
|
||||
|
||||
if (CFG_ACC_AUTH_MODE != AUTH_MODE_SELF)
|
||||
{
|
||||
if (CFG_ACC_EXT_CREATE_URL)
|
||||
header('Location: '.CFG_ACC_EXT_CREATE_URL, true, 302);
|
||||
else
|
||||
$this->error();
|
||||
}
|
||||
|
||||
$this->tpl = 'acc-signUp';
|
||||
$nStep = 1;
|
||||
if ($this->_post['username'] || $this->_post['password'] || $this->_post['c_password'] || $this->_post['email'])
|
||||
@@ -158,13 +138,15 @@ class AccountPage extends GenericPage
|
||||
$this->text = sprintf(Lang::account('createAccSent'), $this->_post['email']);
|
||||
}
|
||||
}
|
||||
else if ($this->_get['token'] && ($newId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE status = ?d AND token = ?', ACC_STATUS_NEW, $this->_get['token'])))
|
||||
else if (!empty($_GET['token']) && ($newId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE status = ?d AND token = ?', ACC_STATUS_NEW, $_GET['token'])))
|
||||
{
|
||||
$nStep = 2;
|
||||
DB::Aowow()->query('UPDATE ?_account SET status = ?d, statusTimer = 0, token = 0, userGroups = ?d WHERE token = ?', ACC_STATUS_OK, U_GROUP_NONE, $this->_get['token']);
|
||||
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (ip, type, count, unbanDate) VALUES (?, 1, ?d + 1, UNIX_TIMESTAMP() + ?d)', User::$ip, CFG_ACC_FAILED_AUTH_COUNT, CFG_ACC_FAILED_AUTH_BLOCK);
|
||||
DB::Aowow()->query('UPDATE ?_account SET status = ?d WHERE token = ?', ACC_STATUS_OK, $_GET['token']);
|
||||
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (ip, type, count, unbanDate) VALUES (?, 1, ?d + 1, UNIX_TIMESTAMP() + ?d)', User::$ip, CFG_FAILED_AUTH_COUNT, CFG_FAILED_AUTH_EXCLUSION);
|
||||
|
||||
$this->text = sprintf(Lang::account('accActivated'), $this->_get['token']);
|
||||
Util::gainSiteReputation($newId, SITEREP_ACTION_REGISTER);
|
||||
|
||||
$this->text = sprintf(Lang::account('accActivated'), $_GET['token']);
|
||||
}
|
||||
else
|
||||
$this->next = $this->getNext();
|
||||
@@ -236,6 +218,7 @@ class AccountPage extends GenericPage
|
||||
/* Listview */
|
||||
/************/
|
||||
|
||||
$this->lvTabs = [];
|
||||
$this->forceTabs = true;
|
||||
|
||||
// Reputation changelog (params only for comment-events)
|
||||
@@ -244,7 +227,11 @@ class AccountPage extends GenericPage
|
||||
foreach ($repData as &$r)
|
||||
$r['when'] = date(Util::$dateFormatInternal, $r['when']);
|
||||
|
||||
$this->lvTabs[] = ['reputationhistory', ['data' => $repData]];
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'reputationhistory',
|
||||
'data' => $repData,
|
||||
'params' => []
|
||||
);
|
||||
}
|
||||
|
||||
// comments
|
||||
@@ -254,11 +241,14 @@ class AccountPage extends GenericPage
|
||||
// _totalCount: 377,
|
||||
// note: $WH.sprintf(LANG.lvnote_usercomments, 377),
|
||||
|
||||
$this->lvTabs[] = ['commentpreview', array(
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'commentpreview',
|
||||
'data' => $_,
|
||||
'hiddenCols' => ['author'],
|
||||
'params' => array(
|
||||
'hiddenCols' => "$['author']",
|
||||
'onBeforeCreate' => '$Listview.funcBox.beforeUserComments'
|
||||
)];
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// replies
|
||||
@@ -269,10 +259,13 @@ class AccountPage extends GenericPage
|
||||
// _totalCount: 377,
|
||||
// note: $WH.sprintf(LANG.lvnote_usercomments, 377),
|
||||
|
||||
$this->lvTabs[] = ['replypreview', array(
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'replypreview',
|
||||
'data' => $_,
|
||||
'hiddenCols' => ['author']
|
||||
)];
|
||||
'params' => array(
|
||||
'hiddenCols' => "$['author']"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -315,17 +308,17 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
$this->text = sprintf(Lang::account('recovPassSent'), $this->_post['email']);
|
||||
}
|
||||
}
|
||||
else if ($this->_get['token']) // step 2
|
||||
else if (isset($_GET['token'])) // step 2
|
||||
{
|
||||
$step = 2;
|
||||
$this->resetPass = true;
|
||||
$this->token = $this->_get['token'];
|
||||
$this->token = $_GET['token'];
|
||||
}
|
||||
else if ($this->_post['token'] && $this->_post['email'] && $this->_post['password'] && $this->_post['c_password'])
|
||||
{
|
||||
$step = 2;
|
||||
$this->resetPass = true;
|
||||
$this->token = $this->_post['token']; // insecure source .. that sucks; but whats the worst that could happen .. this account cannot be recovered for some minutes
|
||||
$this->token = $_GET['token']; // insecure source .. that sucks; but whats the worst that could happen .. this account cannot be recovered for some minutes
|
||||
|
||||
if ($err = $this->doResetPass())
|
||||
$this->error = $err;
|
||||
@@ -353,10 +346,9 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
return Lang::main('intError');
|
||||
|
||||
// reset account status, update expiration
|
||||
DB::Aowow()->query('UPDATE ?_account SET prevIP = IF(curIp = ?, prevIP, curIP), curIP = IF(curIp = ?, curIP, ?), allowExpire = ?d, status = IF(status = ?d, status, 0), statusTimer = IF(status = ?d, statusTimer, 0), token = IF(status = ?d, token, "") WHERE user = ?',
|
||||
DB::Aowow()->query('UPDATE ?_account SET prevIP = IF(curIp = ?, prevIP, curIP), curIP = IF(curIp = ?, curIP, ?), allowExpire = ?d, status = 0, statusTimer = 0, token = "" WHERE user = ?',
|
||||
User::$ip, User::$ip, User::$ip,
|
||||
$this->_post['remember_me'] != 'yes',
|
||||
ACC_STATUS_NEW, ACC_STATUS_NEW, ACC_STATUS_NEW,
|
||||
$this->_post['username']
|
||||
);
|
||||
|
||||
@@ -374,9 +366,12 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
case AUTH_WRONGPASS:
|
||||
User::destroy();
|
||||
return Lang::account('wrongPass');
|
||||
case AUTH_ACC_INACTIVE:
|
||||
User::destroy();
|
||||
return Lang::account('accInactive');
|
||||
case AUTH_IPBANNED:
|
||||
User::destroy();
|
||||
return sprintf(Lang::account('loginExceeded'), Util::formatTime(CFG_ACC_FAILED_AUTH_BLOCK * 1000));
|
||||
return sprintf(Lang::account('loginExceeded'), Util::formatTime(CFG_FAILED_AUTH_EXCLUSION * 1000));
|
||||
case AUTH_INTERNAL_ERR:
|
||||
User::destroy();
|
||||
return Lang::main('intError');
|
||||
@@ -408,19 +403,19 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
|
||||
// limit account creation
|
||||
$ip = DB::Aowow()->selectRow('SELECT ip, count, unbanDate FROM ?_account_bannedips WHERE type = 1 AND ip = ?', User::$ip);
|
||||
if ($ip && $ip['count'] >= CFG_ACC_FAILED_AUTH_COUNT && $ip['unbanDate'] >= time())
|
||||
if ($ip && $ip['count'] >= CFG_FAILED_AUTH_COUNT && $ip['unbanDate'] >= time())
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_account_bannedips SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ? AND type = 1', CFG_ACC_FAILED_AUTH_BLOCK, User::$ip);
|
||||
return sprintf(Lang::account('signupExceeded'), Util::formatTime(CFG_ACC_FAILED_AUTH_BLOCK * 1000));
|
||||
DB::Aowow()->query('UPDATE ?_account_bannedips SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ? AND type = 1', CFG_FAILED_AUTH_EXCLUSION, User::$ip);
|
||||
return sprintf(Lang::account('signupExceeded'), Util::formatTime(CFG_FAILED_AUTH_EXCLUSION * 1000));
|
||||
}
|
||||
|
||||
// username taken
|
||||
if ($_ = DB::Aowow()->SelectCell('SELECT user FROM ?_account WHERE (user = ? OR email = ?) AND (status <> ?d OR (status = ?d AND statusTimer > UNIX_TIMESTAMP()))', $this->_post['username'], $this->_post['email'], ACC_STATUS_NEW, ACC_STATUS_NEW))
|
||||
if ($_ = DB::Aowow()->SelectCell('SELECT user FROM ?_account WHERE (user = ? OR email = ?) AND (status <> ?d OR (status = ?d AND statusTimer > UNIX_TIMESTAMP()))', $this->_post['username'], $email, ACC_STATUS_NEW, ACC_STATUS_NEW))
|
||||
return $_ == $this->_post['username'] ? Lang::account('nameInUse') : Lang::account('mailInUse');
|
||||
|
||||
// create..
|
||||
$token = Util::createHash();
|
||||
$ok = DB::Aowow()->query('REPLACE INTO ?_account (user, passHash, displayName, email, joindate, curIP, allowExpire, locale, userGroups, status, statusTimer, token) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(), ?, ?d, ?d, ?d, ?d, UNIX_TIMESTAMP() + ?d, ?)',
|
||||
$id = DB::Aowow()->query('REPLACE INTO ?_account (user, passHash, displayName, email, joindate, curIP, allowExpire, locale, status, statusTimer, token) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(), ?, ?d, ?d, ?d, UNIX_TIMESTAMP() + ?d, ?)',
|
||||
$this->_post['username'],
|
||||
User::hashCrypt($this->_post['password']),
|
||||
Util::ucFirst($this->_post['username']),
|
||||
@@ -428,23 +423,19 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
User::$ip,
|
||||
$this->_post['remember_me'] != 'yes',
|
||||
User::$localeId,
|
||||
U_GROUP_PENDING,
|
||||
ACC_STATUS_NEW,
|
||||
CFG_ACC_CREATE_SAVE_DECAY,
|
||||
CFG_ACCOUNT_CREATE_SAVE_DECAY,
|
||||
$token
|
||||
);
|
||||
if (!$ok)
|
||||
if (!$id) // something went wrong
|
||||
return Lang::main('intError');
|
||||
else if ($_ = $this->sendMail(Lang::user('accConfirm', 0), sprintf(Lang::user('accConfirm', 1), $token), CFG_ACC_CREATE_SAVE_DECAY))
|
||||
else if ($_ = $this->sendMail(Lang::mail('accConfirm', 0), sprintf(Lang::mail('accConfirm', 1), $token), CFG_ACCOUNT_CREATE_SAVE_DECAY))
|
||||
{
|
||||
if ($id = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE token = ?', $token))
|
||||
Util::gainSiteReputation($id, SITEREP_ACTION_REGISTER);
|
||||
|
||||
// success:: update ip-bans
|
||||
if (!$ip || $ip['unbanDate'] < time())
|
||||
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (ip, type, count, unbanDate) VALUES (?, 1, 1, UNIX_TIMESTAMP() + ?d)', User::$ip, CFG_ACC_FAILED_AUTH_BLOCK);
|
||||
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (ip, type, count, unbanDate) VALUES (?, 1, 1, UNIX_TIMESTAMP() + ?d)', User::$ip, CFG_FAILED_AUTH_EXCLUSION);
|
||||
else
|
||||
DB::Aowow()->query('UPDATE ?_account_bannedips SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ? AND type = 1', CFG_ACC_FAILED_AUTH_BLOCK, User::$ip);
|
||||
DB::Aowow()->query('UPDATE ?_account_bannedips SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ? AND type = 1', CFG_FAILED_AUTH_EXCLUSION, User::$ip);
|
||||
|
||||
return $_;
|
||||
}
|
||||
@@ -452,11 +443,11 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
|
||||
private function doRecoverPass()
|
||||
{
|
||||
if ($_ = $this->initRecovery(ACC_STATUS_RECOVER_PASS, CFG_ACC_RECOVERY_DECAY, $token))
|
||||
if ($_ = $this->initRecovery(ACC_STATUS_RECOVER_PASS, CFG_ACCOUNT_RECOVERY_DECAY, $token))
|
||||
return $_;
|
||||
|
||||
// send recovery mail
|
||||
return $this->sendMail(Lang::user('resetPass', 0), sprintf(Lang::user('resetPass', 1), $token), CFG_ACC_RECOVERY_DECAY);
|
||||
return $this->sendMail(Lang::mail('resetPass', 0), sprintf(Lang::mail('resetPass', 1), $token), CFG_ACCOUNT_RECOVERY_DECAY);
|
||||
}
|
||||
|
||||
private function doResetPass()
|
||||
@@ -475,20 +466,20 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
if (!$uId)
|
||||
return Lang::account('emailNotFound'); // assume they didn't meddle with the token
|
||||
|
||||
if (!User::verifyCrypt($this->_post['c_password']))
|
||||
if (!User::verifyCrypt($newPass))
|
||||
return Lang::account('newPassDiff');
|
||||
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET passHash = ?, status = ?d WHERE id = ?d', User::hashCrypt($this->_post['c_password']), ACC_STATUS_OK, $uId))
|
||||
if (!DB::Aowow()->query('UPDATE ?_account SET passHash = ?, status = ?d WHERE id = ?d', User::hashcrypt($newPass), ACC_STATUS_OK, $uId))
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
private function doRecoverUser()
|
||||
{
|
||||
if ($_ = $this->initRecovery(ACC_STATUS_RECOVER_USER, CFG_ACC_RECOVERY_DECAY, $token))
|
||||
if ($_ = $this->initRecovery(ACC_STATUS_RECOVER_USER, CFG_ACCOUNT_RECOVERY_DECAY, $token))
|
||||
return $_;
|
||||
|
||||
// send recovery mail
|
||||
return $this->sendMail(Lang::user('recoverUser', 0), sprintf(Lang::user('recoverUser', 1), $token), CFG_ACC_RECOVERY_DECAY);
|
||||
return $this->sendMail(Lang::mail('recoverUser', 0), sprintf(Lang::mail('recoverUser', 1), $token), CFG_ACCOUNT_RECOVERY_DECAY);
|
||||
}
|
||||
|
||||
private function initRecovery($type, $delay, &$token)
|
||||
@@ -510,7 +501,7 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
{
|
||||
// send recovery mail
|
||||
$subj = CFG_NAME_SHORT.Lang::main('colon') . $subj;
|
||||
$msg .= "\r\n\r\n".sprintf(Lang::user('tokenExpires'), Util::formatTime($delay * 1000))."\r\n";
|
||||
$msg .= "\r\n\r\n".sprintf(Lang::mail('tokenExpires'), Util::formatTime($delay * 1000))."\r\n";
|
||||
$header = 'From: '.CFG_CONTACT_EMAIL . "\r\n" .
|
||||
'Reply-To: '.CFG_CONTACT_EMAIL . "\r\n" .
|
||||
'X-Mailer: PHP/' . phpversion();
|
||||
@@ -522,8 +513,8 @@ Markup.printHtml("description text here", "description-generic", { allow: Markup
|
||||
private function getNext($forHeader = false)
|
||||
{
|
||||
$next = $forHeader ? '.' : '';
|
||||
if ($this->_get['next'])
|
||||
$next = $this->_get['next'];
|
||||
if (isset($_GET['next']))
|
||||
$next = $_GET['next'];
|
||||
else if (isset($_SERVER['HTTP_REFERER']) && strstr($_SERVER['HTTP_REFERER'], '?'))
|
||||
$next = explode('?', $_SERVER['HTTP_REFERER'])[1];
|
||||
|
||||
|
||||
@@ -23,32 +23,28 @@ if (!defined('AOWOW_REVISION'))
|
||||
// tabId 0: Database g_initHeader()
|
||||
class AchievementPage extends GenericPage
|
||||
{
|
||||
use TrDetailPage;
|
||||
use DetailPage;
|
||||
|
||||
protected $type = Type::ACHIEVEMENT;
|
||||
protected $type = TYPE_ACHIEVEMENT;
|
||||
protected $typeId = 0;
|
||||
protected $tpl = 'achievement';
|
||||
protected $path = [0, 9];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
|
||||
protected $_get = ['domain' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkDomain']];
|
||||
|
||||
private $powerTpl = '$WowheadPower.registerAchievement(%d, %d, %s);';
|
||||
|
||||
public function __construct($pageCall, $id)
|
||||
{
|
||||
parent::__construct($pageCall, $id);
|
||||
|
||||
// temp locale
|
||||
if ($this->mode == CACHE_TYPE_TOOLTIP && $this->_get['domain'])
|
||||
Util::powerUseLocale($this->_get['domain']);
|
||||
if ($this->mode == CACHE_TYPE_TOOLTIP && isset($_GET['domain']))
|
||||
Util::powerUseLocale($_GET['domain']);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
|
||||
$this->subject = new AchievementList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->notFound(Lang::game('achievement'), Lang::achievement('notFound'));
|
||||
$this->notFound();
|
||||
|
||||
$this->extendGlobalData($this->subject->getJSGlobals(GLOBALINFO_REWARDS));
|
||||
|
||||
@@ -62,7 +58,7 @@ class AchievementPage extends GenericPage
|
||||
do
|
||||
{
|
||||
array_unshift($this->path, $curCat);
|
||||
$curCat = DB::Aowow()->SelectCell('SELECT parentCat FROM ?_achievementcategory WHERE id = ?d', $curCat);
|
||||
$curCat = DB::Aowow()->SelectCell('SELECT parentCategory FROM ?_achievementcategory WHERE id = ?d', $curCat);
|
||||
}
|
||||
while ($curCat > 0);
|
||||
|
||||
@@ -103,20 +99,18 @@ class AchievementPage extends GenericPage
|
||||
$infobox[] = Lang::main('side').Lang::main('colon').Lang::game('si', SIDE_BOTH);
|
||||
}
|
||||
|
||||
// icon
|
||||
if ($_ = $this->subject->getField('iconId'))
|
||||
{
|
||||
$infobox[] = Util::ucFirst(lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$this->extendGlobalIds(Type::ICON, $_);
|
||||
}
|
||||
|
||||
// realm first available?
|
||||
if ($this->subject->getField('flags') & 0x100 && DB::isConnectable(DB_AUTH))
|
||||
{
|
||||
$avlb = [];
|
||||
foreach (Profiler::getRealms() AS $rId => $rData)
|
||||
foreach (DB::Auth()->selectCol('SELECT id AS ARRAY_KEY, name FROM realmlist WHERE allowedSecurityLevel = 0 AND gamebuild = ?d', WOW_VERSION) AS $rId => $name)
|
||||
{
|
||||
if (!DB::isConnectable(DB_CHARACTERS . $rId))
|
||||
continue;
|
||||
|
||||
if (!DB::Characters($rId)->selectCell('SELECT 1 FROM character_achievement WHERE achievement = ?d LIMIT 1', $this->typeId))
|
||||
$avlb[] = Util::ucWords($rData['name']);
|
||||
$avlb[] = $name;
|
||||
}
|
||||
|
||||
if ($avlb)
|
||||
$infobox[] = Lang::achievement('rfAvailable').implode(', ', $avlb);
|
||||
@@ -140,7 +134,7 @@ class AchievementPage extends GenericPage
|
||||
|
||||
$series[$pos][] = array(
|
||||
'side' => $chainAcv->getField('faction'),
|
||||
'typeStr' => Type::getFileString(Type::ACHIEVEMENT),
|
||||
'typeStr' => Util::$typeStrings[TYPE_ACHIEVEMENT],
|
||||
'typeId' => $aId,
|
||||
'name' => $chainAcv->getField('name', true)
|
||||
);
|
||||
@@ -154,17 +148,11 @@ class AchievementPage extends GenericPage
|
||||
$this->mail = $this->createMail($reqBook);
|
||||
$this->headIcons = [$this->subject->getField('iconString')];
|
||||
$this->infobox = $infobox ? '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]' : null;
|
||||
$this->series = $series ? [[array_values($series), null]] : null;
|
||||
$this->series = $series ? [[$series, null]] : null;
|
||||
$this->description = $this->subject->getField('description', true);
|
||||
$this->redButtons = array(
|
||||
BUTTON_WOWHEAD => !($this->subject->getField('cuFlags') & CUSTOM_SERVERSIDE),
|
||||
BUTTON_LINKS => array(
|
||||
'linkColor' => 'ffffff00',
|
||||
'linkId' => Type::getFileString(Type::ACHIEVEMENT).':'.$this->typeId.':"..UnitGUID("player")..":0:0:0:0:0:0:0:0',
|
||||
'linkName' => $this->name,
|
||||
'type' => $this->type,
|
||||
'typeId' => $this->typeId
|
||||
)
|
||||
BUTTON_LINKS => ['color' => 'ffffff00', 'linkId' => Util::$typeStrings[TYPE_ACHIEVEMENT].':'.$this->typeId.':"..UnitGUID("player")..":0:0:0:0:0:0:0:0'],
|
||||
BUTTON_WOWHEAD => !($this->subject->getField('cuFlags') & CUSTOM_SERVERSIDE)
|
||||
);
|
||||
$this->criteria = array(
|
||||
'reqQty' => $this->subject->getField('reqCriteriaCount'),
|
||||
@@ -173,13 +161,13 @@ class AchievementPage extends GenericPage
|
||||
);
|
||||
|
||||
if ($reqBook)
|
||||
$this->addScript([CSS_FILE, 'Book.css']);
|
||||
$this->addCss(['path' => 'Book.css']);
|
||||
|
||||
// create rewards
|
||||
if ($foo = $this->subject->getField('rewards'))
|
||||
{
|
||||
array_walk($foo, function(&$item) {
|
||||
$item = $item[0] != Type::ITEM ? null : $item[1];
|
||||
$item = $item[0] != TYPE_ITEM ? null : $item[1];
|
||||
});
|
||||
|
||||
$bar = new ItemList(array(['i.id', $foo]));
|
||||
@@ -188,9 +176,9 @@ class AchievementPage extends GenericPage
|
||||
$this->rewards['item'][] = array(
|
||||
'name' => $bar->getField('name', true),
|
||||
'quality' => $bar->getField('quality'),
|
||||
'typeStr' => Type::getFileString(Type::ITEM),
|
||||
'typeStr' => Util::$typeStrings[TYPE_ITEM],
|
||||
'id' => $id,
|
||||
'globalStr' => Type::getJSGlobalString(Type::ITEM)
|
||||
'globalStr' => 'g_items'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -198,7 +186,7 @@ class AchievementPage extends GenericPage
|
||||
if ($foo = $this->subject->getField('rewards'))
|
||||
{
|
||||
array_walk($foo, function(&$item) {
|
||||
$item = $item[0] != Type::TITLE ? null : $item[1];
|
||||
$item = $item[0] != TYPE_TITLE ? null : $item[1];
|
||||
});
|
||||
|
||||
$bar = new TitleList(array(['id', $foo]));
|
||||
@@ -236,12 +224,15 @@ class AchievementPage extends GenericPage
|
||||
['id', $this->typeId, '!']
|
||||
);
|
||||
$saList = new AchievementList($conditions);
|
||||
$this->lvTabs[] = ['achievement', array(
|
||||
'data' => array_values($saList->getListviewData()),
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'achievement',
|
||||
'data' => $saList->getListviewData(),
|
||||
'params' => array(
|
||||
'id' => 'see-also',
|
||||
'name' => '$LANG.tab_seealso',
|
||||
'visibleCols' => ['category']
|
||||
)];
|
||||
'visibleCols' => "$['category']"
|
||||
)
|
||||
);
|
||||
$this->extendGlobalData($saList->getJSGlobals());
|
||||
|
||||
// tab: criteria of
|
||||
@@ -252,12 +243,15 @@ class AchievementPage extends GenericPage
|
||||
if (!empty($refs))
|
||||
{
|
||||
$coList = new AchievementList(array(['id', $refs]));
|
||||
$this->lvTabs[] = ['achievement', array(
|
||||
'data' => array_values($coList->getListviewData()),
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'achievement',
|
||||
'data' => $coList->getListviewData(),
|
||||
'params' => array(
|
||||
'id' => 'criteria-of',
|
||||
'name' => '$LANG.tab_criteriaof',
|
||||
'visibleCols' => ['category']
|
||||
)];
|
||||
'visibleCols' => "$['category']"
|
||||
)
|
||||
);
|
||||
$this->extendGlobalData($coList->getJSGlobals());
|
||||
}
|
||||
|
||||
@@ -267,16 +261,6 @@ class AchievementPage extends GenericPage
|
||||
|
||||
$iconId = 1;
|
||||
$rightCol = [];
|
||||
$scripts = [];
|
||||
|
||||
// serverside extra-Data
|
||||
if ($crtIds = array_column($this->subject->getCriteria(), 'id'))
|
||||
{
|
||||
Util::checkNumeric($crtIds);
|
||||
$crtExtraData = DB::World()->select('SELECT criteria_id AS ARRAY_KEY, type AS ARRAY_KEY2, value1, value2, ScriptName FROM achievement_criteria_data WHERE criteria_id IN (?a)', $crtIds);
|
||||
}
|
||||
else
|
||||
$crtExtraData = [];
|
||||
|
||||
foreach ($this->subject->getCriteria() as $i => $crt)
|
||||
{
|
||||
@@ -366,10 +350,10 @@ class AchievementPage extends GenericPage
|
||||
$tmp['icon'] = $iconId;
|
||||
$this->criteria['icons'][] = array(
|
||||
'itr' => $iconId++,
|
||||
'type' => Type::getJSGlobalString(Type::ACHIEVEMENT),
|
||||
'type' => 'g_achievements',
|
||||
'id' => $obj,
|
||||
);
|
||||
$this->extendGlobalIds(Type::ACHIEVEMENT, $obj);
|
||||
$this->extendGlobalIds(TYPE_ACHIEVEMENT, $obj);
|
||||
break;
|
||||
// link to quest
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
|
||||
@@ -389,11 +373,11 @@ class AchievementPage extends GenericPage
|
||||
'href' => '?spell='.$obj,
|
||||
'text' => ($crtName ?: SpellList::getName($obj))
|
||||
);
|
||||
$this->extendGlobalIds(Type::SPELL, $obj);
|
||||
$this->extendGlobalIds(TYPE_SPELL, $obj);
|
||||
$tmp['icon'] = $iconId;
|
||||
$this->criteria['icons'][] = array(
|
||||
'itr' => $iconId++,
|
||||
'type' => Type::getJSGlobalString(Type::SPELL),
|
||||
'type' => 'g_spells',
|
||||
'id' => $obj,
|
||||
);
|
||||
break;
|
||||
@@ -413,7 +397,7 @@ class AchievementPage extends GenericPage
|
||||
$tmp['icon'] = $iconId;
|
||||
$this->criteria['icons'][] = array(
|
||||
'itr' => $iconId++,
|
||||
'type' => Type::getJSGlobalString(Type::ITEM),
|
||||
'type' => 'g_items',
|
||||
'id' => $obj,
|
||||
'count' => $qty,
|
||||
);
|
||||
@@ -434,84 +418,11 @@ class AchievementPage extends GenericPage
|
||||
'text' => $crtName,
|
||||
);
|
||||
break;
|
||||
// link to emote
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
|
||||
$tmp['link'] = array(
|
||||
'href' => '?emote='.$obj,
|
||||
'text' => $crtName,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
// Add a gold coin icon if required
|
||||
$tmp['extraText'] = $displayMoney ? Util::formatMoney($qty) : $crtName;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($crtExtraData[$crt['id']]))
|
||||
{
|
||||
$tmp['extraData'] = [];
|
||||
foreach ($crtExtraData[$crt['id']] as $xType => $xData)
|
||||
{
|
||||
// just pick stuff, that can actually be linked
|
||||
switch ($xType)
|
||||
{
|
||||
case 1: // TYPE_T_CREATURE
|
||||
$tmp['extraData'][] = ['?npc='.$xData['value1'], CreatureList::getName($xData['value1'])];
|
||||
break;
|
||||
case 2: // TYPE_T_PLAYER_CLASS_RACE
|
||||
case 21: // TYPE_S_PLAYER_CLASS_RACE
|
||||
if ($xData['value1'])
|
||||
$tmp['extraData'][] = ['?class='.$xData['value1'], (new CharClassList(array(['id', $xData['value1']])))->getField('name', true)];
|
||||
|
||||
if ($xData['value2'])
|
||||
$tmp['extraData'][] = ['?race='.$xData['value2'], (new CharRaceList(array(['id', $xData['value2']])))->getField('name', true)];
|
||||
|
||||
break;
|
||||
// case 3: // TYPE_T_PLAYER_LESS_HEALTH
|
||||
// case 4: // TYPE_T_PLAYER_DEAD
|
||||
case 5: // TYPE_S_AURA
|
||||
case 7: // TYPE_T_AURA
|
||||
$tmp['extraData'][] = ['?spell='.$xData['value1'], SpellList::getName($xData['value1'])];
|
||||
break;
|
||||
case 6: // TYPE_S_AREA
|
||||
$tmp['extraData'][] = ['?zone='.$xData['value1'], ZoneList::getName($xData['value1'])];
|
||||
break;
|
||||
// case 8: // TYPE_VALUE
|
||||
// case 9: // TYPE_T_LEVEL
|
||||
// case 10: // TYPE_T_GENDER
|
||||
case 11: // TYPE_SCRIPT
|
||||
if ($xData['ScriptName'])
|
||||
$scripts[] = $xData['ScriptName'];
|
||||
|
||||
break;
|
||||
// case 12: // TYPE_MAP_DIFFICULTY
|
||||
// case 13: // TYPE_MAP_PLAYER_COUNT
|
||||
// case 14: // TYPE_T_TEAM
|
||||
// case 15: // TYPE_S_DRUNK
|
||||
case 16: // TYPE_HOLIDAY
|
||||
if ($we = new WorldEventList(array(['holidayId', $xData['value1']])))
|
||||
$tmp['extraData'][] = ['?event='.$we->id, $we->getField('name', true)];
|
||||
|
||||
break;
|
||||
// case 17: // TYPE_BG_LOSS_TEAM_SCORE
|
||||
// case 18: // TYPE_INSTANCE_SCRIPT
|
||||
// case 19: // TYPE_S_EQUIPED_ITEM
|
||||
case 20: // TYPE_MAP_ID
|
||||
if ($z = new ZoneList(array(['mapIdBak', $xData['value1']])))
|
||||
$tmp['extraData'][] = ['?zone='.$z->id, $z->getField('name', true)];
|
||||
|
||||
break;
|
||||
// case 22: // TYPE_NTH_BIRTHDAY
|
||||
case 23: // TYPE_S_KNOWN_TITLE
|
||||
$tmp['extraData'][] = ['?title='.$xData['value1'], trim(str_replace('%s', '', (new TitleList(array(['id', $xData['value1']])))->getField('male', true)))];
|
||||
break;
|
||||
}
|
||||
|
||||
// moar stuffz
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// If the right column
|
||||
if ($i % 2)
|
||||
$this->criteria['data'][] = $tmp;
|
||||
@@ -522,26 +433,45 @@ class AchievementPage extends GenericPage
|
||||
// If you found the second column - merge data from it to the end of the main body
|
||||
if ($rightCol)
|
||||
$this->criteria['data'] = array_merge($this->criteria['data'], $rightCol);
|
||||
|
||||
// criteria have scripts
|
||||
if (User::isInGroup(U_GROUP_EMPLOYEE) && $scripts)
|
||||
{
|
||||
$s = '[li]Script'.Lang::main('colon').'[ul][li]'.implode('[/li][li]', array_unique($scripts)).'[/li][/ul][/li]';
|
||||
$this->infobox = substr_replace($this->infobox, $s, -5, 0);
|
||||
}
|
||||
}
|
||||
|
||||
protected function generateTooltip()
|
||||
protected function generateTooltip($asError = false)
|
||||
{
|
||||
$power = new StdClass();
|
||||
if (!$this->subject->error)
|
||||
{
|
||||
$power->{'name_'.User::$localeString} = $this->subject->getField('name', true);
|
||||
$power->icon = rawurlencode($this->subject->getField('iconString', true, true));
|
||||
$power->{'tooltip_'.User::$localeString} = $this->subject->renderTooltip();
|
||||
if ($asError)
|
||||
return '$WowheadPower.registerAchievement('.$this->typeId.', '.User::$localeId.', {});';
|
||||
|
||||
$x = '$WowheadPower.registerAchievement('.$this->typeId.', '.User::$localeId.",{\n";
|
||||
$x .= "\tname_".User::$localeString.": '".Util::jsEscape($this->subject->getField('name', true))."',\n";
|
||||
$x .= "\ticon: '".urlencode($this->subject->getField('iconString'))."',\n";
|
||||
$x .= "\ttooltip_".User::$localeString.": '".$this->subject->renderTooltip()."'\n";
|
||||
$x .= "});";
|
||||
|
||||
return $x;
|
||||
}
|
||||
|
||||
return sprintf($this->powerTpl, $this->typeId, User::$localeId, Util::toJSON($power, JSON_AOWOW_POWER));
|
||||
public function display($override = '')
|
||||
{
|
||||
if ($this->mode != CACHE_TYPE_TOOLTIP)
|
||||
return parent::display($override);
|
||||
|
||||
if (!$this->loadCache($tt))
|
||||
{
|
||||
$tt = $this->generateTooltip();
|
||||
$this->saveCache($tt);
|
||||
}
|
||||
|
||||
header('Content-type: application/x-javascript; charset=utf-8');
|
||||
die($tt);
|
||||
}
|
||||
|
||||
public function notFound()
|
||||
{
|
||||
if ($this->mode != CACHE_TYPE_TOOLTIP)
|
||||
return parent::notFound(Lang::game('achievement'), Lang::achievement('notFound'));
|
||||
|
||||
header('Content-type: application/x-javascript; charset=utf-8');
|
||||
echo $this->generateTooltip(true);
|
||||
exit();
|
||||
}
|
||||
|
||||
private function createMail(&$reqCss = false)
|
||||
@@ -550,16 +480,14 @@ class AchievementPage extends GenericPage
|
||||
|
||||
if ($_ = $this->subject->getField('mailTemplate'))
|
||||
{
|
||||
$letter = DB::Aowow()->selectRow('SELECT * FROM ?_mails WHERE id = ?d', $_);
|
||||
$letter = DB::Aowow()->selectRow('SELECT * FROM ?_mailtemplate WHERE id = ?d', $_);
|
||||
if (!$letter)
|
||||
return [];
|
||||
|
||||
$reqCss = true;
|
||||
$mail = array(
|
||||
'id' => $_,
|
||||
'delay' => null,
|
||||
'sender' => null,
|
||||
'attachments' => [],
|
||||
'subject' => Util::parseHtmlText(Util::localizedString($letter, 'subject', true)),
|
||||
'text' => Util::parseHtmlText(Util::localizedString($letter, 'text', true))
|
||||
);
|
||||
@@ -568,17 +496,15 @@ class AchievementPage extends GenericPage
|
||||
{
|
||||
$reqCss = true;
|
||||
$mail = array(
|
||||
'id' => -$this->typeId,
|
||||
'delay' => null,
|
||||
'sender' => null,
|
||||
'attachments' => [],
|
||||
'subject' => Util::parseHtmlText($this->subject->getField('subject', true, true)),
|
||||
'text' => $_
|
||||
);
|
||||
}
|
||||
|
||||
if ($_ = CreatureList::getName($this->subject->getField('sender')))
|
||||
$mail['sender'] = sprintf(Lang::mail('mailBy'), $this->subject->getField('sender'), $_);
|
||||
$mail['sender'] = sprintf(Lang::quest('mailBy'), $this->subject->getField('sender'), $_);
|
||||
|
||||
return $mail;
|
||||
}
|
||||
|
||||
@@ -8,17 +8,14 @@ if (!defined('AOWOW_REVISION'))
|
||||
// tabId 0: Database g_initHeader()
|
||||
class AchievementsPage extends GenericPage
|
||||
{
|
||||
use TrListPage;
|
||||
use ListPage;
|
||||
|
||||
protected $type = Type::ACHIEVEMENT;
|
||||
protected $type = TYPE_ACHIEVEMENT;
|
||||
protected $tpl = 'achievements';
|
||||
protected $path = [0, 9];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
protected $js = [[JS_FILE, 'filters.js']];
|
||||
|
||||
protected $_get = ['filter' => ['filter' => FILTER_UNSAFE_RAW]];
|
||||
|
||||
protected $js = ['filters.js'];
|
||||
protected $validCats = array(
|
||||
92 => true,
|
||||
96 => [14861, 14862, 14863],
|
||||
@@ -45,8 +42,8 @@ class AchievementsPage extends GenericPage
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
$this->filterObj = new AchievementListFilter();
|
||||
$this->getCategoryFromUrl($pageParam);
|
||||
$this->filterObj = new AchievementListFilter(false, $this->category);
|
||||
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
@@ -66,12 +63,9 @@ class AchievementsPage extends GenericPage
|
||||
$conditions[] = ['category', (int)end($this->category)];
|
||||
|
||||
// recreate form selection
|
||||
$this->filter = $this->filterObj->getForm();
|
||||
$this->filter['query'] = $this->_get['filter'];
|
||||
$this->filter['initData'] = ['init' => 'achievements'];
|
||||
|
||||
if ($x = $this->filterObj->getSetCriteria())
|
||||
$this->filter['initData']['sc'] = $x;
|
||||
$this->filter = $this->filterObj->getForm('form');
|
||||
$this->filter['query'] = isset($_GET['filter']) ? $_GET['filter'] : null;
|
||||
$this->filter['fi'] = $this->filterObj->getForm();
|
||||
|
||||
if ($fiCnd = $this->filterObj->getConditions())
|
||||
$conditions[] = $fiCnd;
|
||||
@@ -79,43 +73,52 @@ class AchievementsPage extends GenericPage
|
||||
$acvList = new AchievementList($conditions);
|
||||
if (!$acvList->getMatches())
|
||||
{
|
||||
$category = [!empty($this->category) ? (int)end($this->category) : 0];
|
||||
$curCats = $catList = [!empty($this->category) ? (int)end($this->category) : 0];
|
||||
while ($curCats)
|
||||
{
|
||||
$curCats = DB::Aowow()->SelectCol('SELECT Id FROM ?_achievementcategory WHERE parentCategory IN (?a)', $curCats);
|
||||
$catList = array_merge($catList, $curCats);
|
||||
}
|
||||
$conditions = [];
|
||||
if ($fiCnd)
|
||||
$conditions[] = $fiCnd;
|
||||
if ($catList = DB::Aowow()->SelectCol('SELECT Id FROM ?_achievementcategory WHERE parentCat IN (?a) OR parentCat2 IN (?a) ', $category, $category))
|
||||
if ($catList)
|
||||
$conditions[] = ['category', $catList];
|
||||
|
||||
$acvList = new AchievementList($conditions);
|
||||
}
|
||||
|
||||
$tabData = [];
|
||||
$params = $data = [];
|
||||
if (!$acvList->error)
|
||||
{
|
||||
$tabData['data'] = array_values($acvList->getListviewData());
|
||||
$data = $acvList->getListviewData();
|
||||
|
||||
// fill g_items, g_titles, g_achievements
|
||||
$this->extendGlobalData($acvList->getJSGlobals());
|
||||
|
||||
// if we are have different cats display field
|
||||
if ($acvList->hasDiffFields(['category']))
|
||||
$tabData['visibleCols'] = ['category'];
|
||||
$params['visibleCols'] = "$['category']";
|
||||
|
||||
if (!empty($this->filter['fi']['extraCols']))
|
||||
$tabData['extraCols'] = '$fi_getExtraCols(fi_extraCols, 0, 0)';
|
||||
$params['extraCols'] = '$fi_getExtraCols(fi_extraCols, 0, 0)';
|
||||
|
||||
// create note if search limit was exceeded
|
||||
if ($acvList->getMatches() > CFG_SQL_LIMIT_DEFAULT)
|
||||
{
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_achievementsfound', $acvList->getMatches(), CFG_SQL_LIMIT_DEFAULT);
|
||||
$tabData['_truncated'] = 1;
|
||||
$params['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_achievementsfound', $acvList->getMatches(), CFG_SQL_LIMIT_DEFAULT);
|
||||
$params['_truncated'] = 1;
|
||||
}
|
||||
|
||||
if ($this->filterObj->error)
|
||||
$tabData['_errors'] = 1;
|
||||
$params['_errors'] = '$1';
|
||||
}
|
||||
|
||||
$this->lvTabs[] = ['achievement', $tabData];
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'achievement',
|
||||
'data' => $data,
|
||||
'params' => $params
|
||||
);
|
||||
|
||||
// sort for dropdown-menus in filter
|
||||
Lang::sort('game', 'si');
|
||||
@@ -125,15 +128,21 @@ class AchievementsPage extends GenericPage
|
||||
{
|
||||
array_unshift($this->title, Util::ucFirst(Lang::game('achievements')));
|
||||
if ($this->category)
|
||||
array_unshift($this->title, Lang::achievement('cat', end($this->category)));
|
||||
{
|
||||
$catrow = DB::Aowow()->SelectRow('SELECT * FROM ?_achievementcategory WHERE id = ?d', end($this->category));
|
||||
array_unshift($this->title, Util::localizedString($catrow, 'name'));
|
||||
}
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
{
|
||||
if ($this->category)
|
||||
foreach ($this->category as $cat)
|
||||
{
|
||||
$catrows = DB::Aowow()->SelectCol('SELECT id FROM ?_achievementcategory WHERE id IN (?a)', $this->category);
|
||||
foreach ($catrows as $cat)
|
||||
$this->path[] = $cat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
476
pages/admin.php
476
pages/admin.php
@@ -6,19 +6,13 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class AdminPage extends GenericPage
|
||||
{
|
||||
|
||||
protected $tpl = null; // depends on the subject
|
||||
protected $reqUGroup = U_GROUP_NONE; // actual group dependant on the subPage
|
||||
protected $reqAuth = true;
|
||||
protected $path = [4];
|
||||
protected $tabId = 4;
|
||||
|
||||
protected $_get = array(
|
||||
'all' => ['filter' => FILTER_UNSAFE_RAW],
|
||||
'type' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkInt'],
|
||||
'typeid' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkInt'],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'urldecode'],
|
||||
);
|
||||
|
||||
private $generator = '';
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
@@ -26,7 +20,7 @@ class AdminPage extends GenericPage
|
||||
switch ($pageParam)
|
||||
{
|
||||
case 'screenshots':
|
||||
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
$this->reqUGroup = U_GROUP_STAFF | U_GROUP_SCREENSHOT;
|
||||
$this->generator = 'handleScreenshots';
|
||||
$this->tpl = 'admin/screenshots';
|
||||
|
||||
@@ -44,34 +38,18 @@ class AdminPage extends GenericPage
|
||||
case 'siteconfig':
|
||||
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_DEV;
|
||||
$this->generator = 'handleConfig';
|
||||
$this->tpl = 'admin/siteconfig';
|
||||
$this->tpl = 'list-page-generic';
|
||||
|
||||
array_push($this->path, 2, 18);
|
||||
$this->name = 'Site Configuration';
|
||||
break;
|
||||
case 'weight-presets':
|
||||
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_DEV | U_GROUP_BUREAU;
|
||||
$this->generator = 'handleWeightPresets';
|
||||
$this->tpl = 'admin/weight-presets';
|
||||
|
||||
array_push($this->path, 2, 16);
|
||||
$this->name = 'Weight Presets';
|
||||
break;
|
||||
case 'guides':
|
||||
$this->reqUGroup = U_GROUP_STAFF;
|
||||
$this->generator = 'handleGuideApprove';
|
||||
$this->tpl = 'list-page-generic';
|
||||
|
||||
array_push($this->path, 1, 25);
|
||||
$this->name = 'Pending Guides';
|
||||
break;
|
||||
default: // error out through unset template
|
||||
}
|
||||
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
}
|
||||
|
||||
protected function generateContent() : void
|
||||
protected function generateContent()
|
||||
{
|
||||
if (!$this->generator || function_exists($this->generator))
|
||||
return;
|
||||
@@ -79,60 +57,330 @@ class AdminPage extends GenericPage
|
||||
$this->{$this->generator}();
|
||||
}
|
||||
|
||||
private function handleConfig() : void
|
||||
private function handleConfig()
|
||||
{
|
||||
$this->addScript(
|
||||
[CSS_STRING, '.grid input[type=\'text\'], .grid input[type=\'number\'] { width:250px; text-align:left; }'],
|
||||
[CSS_STRING, '.grid input[type=\'button\'] { width:65px; padding:2px; }'],
|
||||
[CSS_STRING, '.grid a.tip { margin:0px 5px; opacity:0.8; }'],
|
||||
[CSS_STRING, '.grid a.tip:hover { opacity:1; }'],
|
||||
[CSS_STRING, '.grid tr { height:30px; }'],
|
||||
[CSS_STRING, '.grid .disabled { opacity:0.4 !important; }'],
|
||||
[CSS_STRING, '.grid .status { position:absolute; right:5px; }'],
|
||||
);
|
||||
$this->addCSS(array(
|
||||
['string' => '.grid input[type=\'text\'] { width:250px; }'],
|
||||
['string' => '.grid input[type=\'button\'] { width:65px; padding:2px; }'],
|
||||
['string' => '.disabled { opacity:0.4 !important; }'],
|
||||
['string' => '.grid a.tip { margin:0px 5px; opacity:0.8; }'],
|
||||
['string' => '.grid a.tip:hover { opacity:1; }'],
|
||||
['string' => '.status { position:absolute; right:5px; }'],
|
||||
));
|
||||
|
||||
// well .. fuck!
|
||||
ob_start();
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
function createStatusIcon(errTxt)
|
||||
{
|
||||
function fadeout()
|
||||
{
|
||||
$(this).animate({ opacity: '0.0' }, 250, null, function() {
|
||||
$WH.de(this);
|
||||
$WH.Tooltip.hide()
|
||||
});
|
||||
}
|
||||
|
||||
var a = $WH.ce('a');
|
||||
a.style.opacity = 0;
|
||||
a.className = errTxt ? 'icon-report' : 'icon-tick';
|
||||
g_addTooltip(a, errTxt || 'success', 'q');
|
||||
a.onclick = fadeout.bind(a);
|
||||
setTimeout(function () { $(a).animate({ opacity: '1.0' }, 250); }, 50);
|
||||
setTimeout(fadeout.bind(a), 10000);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
function cfg_add(el)
|
||||
{
|
||||
_self = el.parentNode.parentNode;
|
||||
|
||||
var tr = $WH.ce('tr');
|
||||
|
||||
tr.style.position = 'relative';
|
||||
|
||||
var td = $WH.ce('td'),
|
||||
key = $WH.ce('input');
|
||||
|
||||
key.type = 'text';
|
||||
key.name = 'key';
|
||||
$WH.ae(td, key);
|
||||
$WH.ae(tr, td);
|
||||
|
||||
var td = $WH.ce('td'),
|
||||
val = $WH.ce('input');
|
||||
|
||||
val.type = 'text';
|
||||
val.name = 'value';
|
||||
$WH.ae(td, val);
|
||||
$WH.ae(tr, td);
|
||||
|
||||
var td = $WH.ce('td'),
|
||||
aCancel = $WH.ce('a'),
|
||||
aSubmit = $WH.ce('a'),
|
||||
status = $WH.ce('span');
|
||||
|
||||
aSubmit.className = 'icon-save tip';
|
||||
g_addTooltip(aSubmit, 'Submit Setting', 'q');
|
||||
|
||||
aCancel.className = 'icon-delete tip';
|
||||
g_addTooltip(aCancel, 'Cancel', 'q');
|
||||
|
||||
aSubmit.onclick = cfg_new.bind(aSubmit, key, val);
|
||||
aCancel.onclick = function () {
|
||||
$WH.Tooltip.hide();
|
||||
$WH.de(this.parentNode.parentNode);
|
||||
};
|
||||
|
||||
status.className = 'status';
|
||||
|
||||
$WH.ae(td, aSubmit);
|
||||
$WH.ae(td, $WH.ct('|'));
|
||||
$WH.ae(td, aCancel);
|
||||
$WH.ae(td, status);
|
||||
$WH.ae(tr, td);
|
||||
|
||||
_self.parentNode.insertBefore(tr, _self);
|
||||
key.focus();
|
||||
}
|
||||
|
||||
function cfg_new(elKey, elVal)
|
||||
{
|
||||
var
|
||||
_td = this.parentNode,
|
||||
_row = this.parentNode.parentNode,
|
||||
_status = $(_td).find('.status')[0];
|
||||
|
||||
// already performing action
|
||||
if (_status.lastChild && _status.lastChild.tagName == 'IMG')
|
||||
return;
|
||||
else if (_status.lastChild && _status.lastChild.tagName == 'A')
|
||||
$WH.ee(_status);
|
||||
|
||||
if (!elKey.value || !elVal.value)
|
||||
{
|
||||
$WH.ae(_status, createStatusIcon('key or value are empty'));
|
||||
return;
|
||||
}
|
||||
|
||||
var
|
||||
key = elKey.value.toLowerCase().trim(),
|
||||
value = elVal.value.trim();
|
||||
|
||||
$(_status).append(CreateAjaxLoader());
|
||||
|
||||
new Ajax('?admin=siteconfig&action=add&id=' + key + '&val=' + value, {
|
||||
method: 'get',
|
||||
onSuccess: function(xhr) {
|
||||
$WH.ee(_status);
|
||||
|
||||
if (!xhr.responseText) {
|
||||
$WH.ee(_row);
|
||||
$(_row).append($('<td>' + key + '</td>')).append($('<td><input id="' + key + '" type="text" name="' + key + '" value="' + value + '" /></td>'));
|
||||
|
||||
var
|
||||
td = $WH.ce('td'),
|
||||
a = $WH.ce('a'),
|
||||
sp = $WH.ce('span');
|
||||
|
||||
g_addTooltip(a, 'Save Changes', 'q');
|
||||
a.onclick = cfg_submit.bind(a, key);
|
||||
a.className = 'icon-save tip';
|
||||
$WH.ae(td, a);
|
||||
|
||||
a = $WH.ce('a');
|
||||
a.className = 'icon-refresh tip disabled';
|
||||
$WH.ae(td, $WH.ct('|'));
|
||||
$WH.ae(td, a);
|
||||
|
||||
a = $WH.ce('a');
|
||||
g_addTooltip(a, 'Remove Setting', 'q');
|
||||
a.onclick = cfg_remove.bind(a, key);
|
||||
a.className = 'icon-delete tip';
|
||||
$WH.ae(td, $WH.ct('|'));
|
||||
$WH.ae(td, a);
|
||||
|
||||
sp.className = 'status';
|
||||
$WH.ae(sp, createStatusIcon());
|
||||
$WH.ae(td, sp);
|
||||
$WH.ae(_row, td);
|
||||
}
|
||||
else {
|
||||
$WH.ae(_status, createStatusIcon(xhr.responseText));
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cfg_submit(id)
|
||||
{
|
||||
var
|
||||
node = $WH.ge(id),
|
||||
_td = this.parentNode,
|
||||
_status = $(_td).find('.status')[0];
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
var value = 0;
|
||||
|
||||
// already performing action
|
||||
if (_status.lastChild && _status.lastChild.tagName == 'IMG')
|
||||
return;
|
||||
else if (_status.lastChild && _status.lastChild.tagName == 'A')
|
||||
$WH.ee(_status);
|
||||
|
||||
if (node.tagName == 'DIV')
|
||||
{
|
||||
// bitmask
|
||||
$(node).find('input[type="checkbox"]').each(function(idx, opt) {
|
||||
if (opt.checked)
|
||||
value |= (1 << opt.value);
|
||||
});
|
||||
|
||||
// boolean
|
||||
$(node).find('input[type="radio"]').each(function(idx, opt) {
|
||||
if (opt.checked)
|
||||
value = opt.value;
|
||||
});
|
||||
}
|
||||
else if (node.tagName == 'SELECT') // opt-list
|
||||
{
|
||||
$(node).find('option').each(function(idx, opt) {
|
||||
if (opt.selected)
|
||||
value = opt.value;
|
||||
});
|
||||
}
|
||||
else if (node.tagName == 'INPUT') // string or numeric
|
||||
{
|
||||
if (node.value.search(/[^\d\s\/\*\-\+\.]/i) == -1)
|
||||
node.value = eval(node.value);
|
||||
|
||||
value = node.value;
|
||||
}
|
||||
|
||||
value = value.toString().trim();
|
||||
|
||||
if (!value.length)
|
||||
{
|
||||
$WH.ae(_status, createStatusIcon('value is empty'));
|
||||
return;
|
||||
}
|
||||
|
||||
$(_status).append(CreateAjaxLoader());
|
||||
|
||||
new Ajax('?admin=siteconfig&action=update&id=' + id + '&val=' + value, {
|
||||
method: 'get',
|
||||
onSuccess: function(xhr) {
|
||||
$WH.ee(_status);
|
||||
$WH.ae(_status, createStatusIcon(xhr.responseText));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cfg_default(id, val)
|
||||
{
|
||||
var node = $WH.ge(id);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
if (node.tagName == 'DIV')
|
||||
{
|
||||
// bitmask
|
||||
$(node).find('input[type="checkbox"]').each(function(idx, opt) { opt.checked = !!(val & (1 << opt.value)); });
|
||||
|
||||
// boolean
|
||||
$(node).find('input[type="radio"]').each(function(idx, opt) { opt.checked = !!opt.value == !!val; });
|
||||
}
|
||||
else if (node.tagName == 'SELECT') // opt-list
|
||||
$(node).find('option').each(function(idx, opt) { opt.selected = opt.value == val; });
|
||||
else if (node.tagName == 'INPUT') // string or numeric
|
||||
node.value = val;
|
||||
}
|
||||
|
||||
function cfg_remove(id)
|
||||
{
|
||||
var
|
||||
_td = this.parentNode,
|
||||
_status = $(_td).find('.status')[0];
|
||||
|
||||
// already performing action
|
||||
if (_status.lastChild && _status.lastChild.tagName == 'IMG')
|
||||
return;
|
||||
else if (_status.lastChild && _status.lastChild.tagName == 'A')
|
||||
$WH.ee(_status);
|
||||
|
||||
if (!confirm('Confirm remove'))
|
||||
return;
|
||||
|
||||
$(_status).append(CreateAjaxLoader());
|
||||
|
||||
new Ajax('?admin=siteconfig&action=remove&id=' + id, {
|
||||
method: 'get',
|
||||
onSuccess: function(xhr) {
|
||||
if (!xhr.responseText)
|
||||
$WH.de(_td.parentNode);
|
||||
else {
|
||||
$WH.ee(_status);
|
||||
$WH.ae(_status, createStatusIcon(xhr.responseText));
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
$this->extraHTML = ob_get_contents();
|
||||
ob_end_clean();
|
||||
// eof (end of fuckup)
|
||||
|
||||
$head = '<table class="grid"><tr><th><b>Key</b></th><th><b>Value</b></th><th style="width:150px;"><b>Options</b></th></tr>';
|
||||
$mainTab = [];
|
||||
$miscTab = [];
|
||||
foreach (Util::$configCats as $idx => $catName)
|
||||
{
|
||||
if ($rows = DB::Aowow()->select('SELECT * FROM ?_config WHERE cat = ?d ORDER BY `flags` DESC, `key` ASC', $idx))
|
||||
|
||||
// for aowow
|
||||
if ($rows = DB::Aowow()->select('SELECT * FROM ?_config WHERE (flags & ?d) = 0 ORDER BY `key` ASC', CON_FLAG_PHP))
|
||||
{
|
||||
$buff = $head;
|
||||
foreach ($rows as $r)
|
||||
$buff .= $this->configAddRow($r);
|
||||
|
||||
if (!$idx) //cat: misc
|
||||
$buff .= '<tr><td colspan="3"><a class="icon-add" onclick="cfg_add(this)">new configuration</a></td></tr>';
|
||||
|
||||
$buff .= '</table>';
|
||||
|
||||
if ($idx)
|
||||
$mainTab[$catName] = $buff;
|
||||
else
|
||||
$miscTab[$catName] = $buff;
|
||||
}
|
||||
$this->lvTabs[] = array(
|
||||
'file' => null,
|
||||
'data' => $buff,
|
||||
'params' => array(
|
||||
'name' => 'Aowow',
|
||||
'id' => 'aowow'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($mainTab as $n => $t)
|
||||
$this->lvTabs[] = [null, array(
|
||||
'data' => $t,
|
||||
'name' => $n,
|
||||
'id' => Profiler::urlize($n)
|
||||
)];
|
||||
// for php
|
||||
$rows = DB::Aowow()->select('SELECT * FROM ?_config WHERE flags & ?d ORDER BY `key` ASC', CON_FLAG_PHP);
|
||||
$buff = $head;
|
||||
foreach ($rows as $r)
|
||||
$buff .= $this->configAddRow($r);
|
||||
|
||||
foreach ($miscTab as $n => $t)
|
||||
$this->lvTabs[] = [null, array(
|
||||
'data' => $t,
|
||||
'name' => $n,
|
||||
'id' => Profiler::urlize($n)
|
||||
)];
|
||||
$buff .= '<tr><td colspan="3"><a class="icon-add" onclick="cfg_add(this)">new configuration</a></td></tr>';
|
||||
$buff .= '</table>';
|
||||
|
||||
$this->lvTabs[] = array(
|
||||
'file' => null,
|
||||
'data' => $buff,
|
||||
'params' => array(
|
||||
'name' => 'PHP',
|
||||
'id' => 'php'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function handlePhpInfo() : void
|
||||
private function handlePhpInfo()
|
||||
{
|
||||
$this->addScript([
|
||||
CSS_STRING, "\npre {margin: 0px; font-family: monospace;}\n" .
|
||||
$this->addCSS([
|
||||
'string' => "\npre {margin: 0px; font-family: monospace;}\n" .
|
||||
"td, th { border: 1px solid #000000; vertical-align: baseline;}\n" .
|
||||
".p {text-align: left;}\n" .
|
||||
".e {background-color: #ccccff; font-weight: bold; color: #000000;}\n" .
|
||||
@@ -175,47 +423,54 @@ class AdminPage extends GenericPage
|
||||
else
|
||||
$name .= $p[0];
|
||||
|
||||
$this->lvTabs[] = [null, array(
|
||||
$this->lvTabs[] = array(
|
||||
'file' => null,
|
||||
'data' => $body,
|
||||
'params' => array(
|
||||
'id' => strtolower(strtr($name, [' ' => ''])),
|
||||
'name' => $name
|
||||
)];
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->lvTabs[] = [null, array(
|
||||
$this->lvTabs[] = array(
|
||||
'file' => null,
|
||||
'data' => $buff,
|
||||
'params' => array(
|
||||
'id' => strtolower($names[$i]),
|
||||
'name' => $names[$i]
|
||||
)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function handleScreenshots() : void
|
||||
{
|
||||
$this->addScript(
|
||||
[JS_FILE, 'screenshot.js'],
|
||||
[CSS_STRING, '.layout {margin: 0px 25px; max-width: inherit; min-width: 1200px; }'],
|
||||
[CSS_STRING, '#highlightedRow { background-color: #322C1C; }'],
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ssGetAll = $this->_get['all'];
|
||||
private function handleScreenshots()
|
||||
{
|
||||
$this->addJS('screenshot.js');
|
||||
$this->addCSS(array(
|
||||
['string' => '.layout {margin: 0px 25px; max-width: inherit; min-width: 1200px; }'],
|
||||
['string' => '#highlightedRow { background-color: #322C1C; }']
|
||||
));
|
||||
|
||||
$ssGetAll = isset($_GET['all']) && empty($_GET['all']);
|
||||
$ssPages = [];
|
||||
$ssData = [];
|
||||
$nMatches = 0;
|
||||
|
||||
if ($this->_get['type'] && $this->_get['typeId'])
|
||||
if (!empty($_GET['type']) && !empty($_GET['typeid']))
|
||||
{
|
||||
$ssData = CommunityContent::getScreenshotsForManager($this->_get['type'], $this->_get['typeid']);
|
||||
$ssData = CommunityContent::getScreenshotsForManager(intVal($_GET['type']), intVal($_GET['typeid']));
|
||||
$nMatches = count($ssData);
|
||||
}
|
||||
else if ($this->_get['user'])
|
||||
else if (!empty($_GET['user']))
|
||||
{
|
||||
if (mb_strlen($this->_get['user']) >= 3)
|
||||
$name = urldecode($_GET['user']);
|
||||
if (strlen($name) > 3)
|
||||
{
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE displayName = ?', ucFirst($this->_get['user'])))
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE displayName = ?', ucFirst($name)))
|
||||
{
|
||||
$ssData = CommunityContent::getScreenshotsForManager(0, 0, $uId);
|
||||
$nMatches = count($ssData);
|
||||
@@ -231,60 +486,11 @@ class AdminPage extends GenericPage
|
||||
$this->ssNFound = $nMatches; // ssm_numPagesFound
|
||||
}
|
||||
|
||||
private function handleWeightPresets() : void
|
||||
{
|
||||
$this->addScript(
|
||||
[JS_FILE, 'filters.js'],
|
||||
[CSS_STRING, '.wt-edit {display:inline-block; vertical-align:top; width:350px;}'],
|
||||
);
|
||||
|
||||
$head = $body = '';
|
||||
|
||||
$scales = DB::Aowow()->select('SELECT class AS ARRAY_KEY, id AS ARRAY_KEY2, name, icon FROM ?_account_weightscales WHERE userId = 0');
|
||||
$weights = DB::Aowow()->selectCol('SELECT awd.id AS ARRAY_KEY, awd.field AS ARRAY_KEY2, awd.val FROM ?_account_weightscale_data awd JOIN ?_account_weightscales ad ON awd.id = ad.id WHERE ad.userId = 0');
|
||||
foreach ($scales as $cl => $data)
|
||||
{
|
||||
$ul = '';
|
||||
foreach ($data as $id => $s)
|
||||
{
|
||||
$weights[$id]['__icon'] = $s['icon'];
|
||||
$ul .= '[url=# onclick="loadScale.bind(this, '.$id.')();"]'.$s['name'].'[/url][br]';
|
||||
}
|
||||
|
||||
$head .= '[td=header]'.Lang::game('cl', $cl).'[/td]';
|
||||
$body .= '[td valign=top]'.$ul.'[/td]';
|
||||
}
|
||||
|
||||
$this->extraText = '[table class=grid][tr]'.$head.'[/tr][tr]'.$body.'[/tr][/table]';
|
||||
|
||||
$this->extraHTML = '<script type="text/javascript">var wt_presets = '.Util::toJSON($weights).";</script>\n\n";
|
||||
}
|
||||
|
||||
private function handleGuideApprove() : void
|
||||
{
|
||||
$pending = new GuideList([['status', GUIDE_STATUS_REVIEW]]);
|
||||
if ($pending->error)
|
||||
$data = [];
|
||||
else
|
||||
{
|
||||
$data = $pending->getListviewData();
|
||||
$latest = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, MAX(`rev`) FROM ?_articles WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `rev`', Type::GUIDE, $pending->getFoundIDs());
|
||||
foreach ($latest as $id => $rev)
|
||||
$data[$id]['rev'] = $rev;
|
||||
}
|
||||
|
||||
$this->lvTabs[] = ['guide', array(
|
||||
'data' => array_values($data),
|
||||
'hiddenCols' => ['patch', 'comments', 'views', 'rating'],
|
||||
'extraCols' => '$_'
|
||||
), 'guideAdminCol'];
|
||||
}
|
||||
|
||||
private function configAddRow($r)
|
||||
{
|
||||
$buff = '<tr>';
|
||||
$info = explode(' - ', $r['comment']);
|
||||
$key = $r['flags'] & CON_FLAG_PHP ? strtolower($r['key']) : strtoupper($r['key']);
|
||||
$key = $r['flags'] & CON_FLAG_PHP ? strtolower($r['key']) : 'CFG_'.strtoupper($r['key']);
|
||||
|
||||
// name
|
||||
if (!empty($info[1]))
|
||||
@@ -316,7 +522,7 @@ class AdminPage extends GenericPage
|
||||
$buff .= '</div></td>';
|
||||
}
|
||||
else
|
||||
$buff .= '<td><input id="'.$key.'" type="'.($r['flags'] & CON_FLAG_TYPE_STRING ? 'text" placeholder="<empty>' : 'number'.($r['flags'] & CON_FLAG_TYPE_FLOAT ? '" step="any' : '')).'" name="'.$key.'" value="'.$r['value'].'" /></td>';
|
||||
$buff .= '<td><input id="'.$key.'" type="text" name="'.$key.'" value="'.$r['value'].'" /></td>';
|
||||
|
||||
// actions
|
||||
$buff .= '<td style="position:relative;">';
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 102: Areatrigger g_initPath()
|
||||
// tabid 0: Database g_initHeader()
|
||||
class AreaTriggerPage extends GenericPage
|
||||
{
|
||||
use TrDetailPage;
|
||||
|
||||
protected $type = Type::AREATRIGGER;
|
||||
protected $typeId = 0;
|
||||
protected $tpl = 'detail-page-generic';
|
||||
protected $path = [0, 102];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
protected $reqUGroup = U_GROUP_STAFF;
|
||||
|
||||
public function __construct($pageCall, $id)
|
||||
{
|
||||
$this->contribute = CONTRIBUTE_NONE;
|
||||
|
||||
parent::__construct($pageCall, $id);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
|
||||
$this->subject = new AreaTriggerList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->notFound(Lang::game('areatrigger'), Lang::areatrigger('notFound'));
|
||||
|
||||
$this->name = $this->subject->getField('name') ?: 'AT #'.$this->typeId;
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
{
|
||||
$this->path[] = $this->subject->getField('type');
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
array_unshift($this->title, $this->name, Util::ucFirst(Lang::game('areatrigger')));
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$this->addScript([JS_FILE, '?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']]);
|
||||
|
||||
$_type = $this->subject->getField('type');
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
// get spawns
|
||||
$map = null;
|
||||
if ($spawns = $this->subject->getSpawns(SPAWNINFO_FULL))
|
||||
{
|
||||
$ta = $this->subject->getField('teleportA');
|
||||
$tf = $this->subject->getField('teleportF');
|
||||
$tx = $this->subject->getField('teleportX');
|
||||
$ty = $this->subject->getField('teleportY');
|
||||
$to = $this->subject->getField('teleportO');
|
||||
|
||||
// add teleport target
|
||||
if ($ta && $tx && $ty)
|
||||
{
|
||||
$o = Util::O2Deg($to);
|
||||
$endPoint = array($tx, $ty, array(
|
||||
'type' => 4,
|
||||
'tooltip' => array(
|
||||
'Teleport Destination' => array(
|
||||
'info' => ['Orientation'.Lang::main('colon').$o[0].'° ('.$o[1].')']
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
if (isset($spawns[$ta][$tf]))
|
||||
$spawns[$ta][$tf]['coords'][] = $endPoint;
|
||||
else
|
||||
$spawns[$ta][$tf]['coords'] = [$endPoint];
|
||||
}
|
||||
|
||||
$map = array(
|
||||
'data' => ['parent' => 'mapper-generic'],
|
||||
'mapperData' => &$spawns
|
||||
);
|
||||
|
||||
foreach ($spawns as $areaId => &$areaData)
|
||||
$map['extra'][$areaId] = ZoneList::getName($areaId);
|
||||
}
|
||||
|
||||
// smart AI
|
||||
$sai = null;
|
||||
if ($_type == AT_TYPE_SMART)
|
||||
{
|
||||
$sai = new SmartAI(SAI_SRC_TYPE_AREATRIGGER, $this->typeId, ['name' => $this->name, 'teleportA' => $this->subject->getField('teleportA')]);
|
||||
if ($sai->prepare())
|
||||
$this->extendGlobalData($sai->getJSGlobals());
|
||||
}
|
||||
|
||||
|
||||
$this->map = $map;
|
||||
$this->infobox = false;
|
||||
$this->smartAI = $sai ? $sai->getMarkdown() : null;
|
||||
$this->redButtons = array(
|
||||
BUTTON_LINKS => false,
|
||||
BUTTON_WOWHEAD => false
|
||||
);
|
||||
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
if ($_type == AT_TYPE_OBJECTIVE)
|
||||
{
|
||||
$relQuest = new QuestList(array(['id', $this->subject->getField('quest')]));
|
||||
if (!$relQuest->error)
|
||||
{
|
||||
$this->extendGlobalData($relQuest->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
|
||||
$this->lvTabs[] = ['quest', ['data' => array_values($relQuest->getListviewData())]];
|
||||
}
|
||||
}
|
||||
else if ($_type == AT_TYPE_TELEPORT)
|
||||
{
|
||||
$relZone = new ZoneList(array(['id', $this->subject->getField('teleportA')]));
|
||||
if (!$relZone->error)
|
||||
{
|
||||
$this->lvTabs[] = ['zone', ['data' => array_values($relZone->getListviewData())]];
|
||||
}
|
||||
}
|
||||
else if ($_type == AT_TYPE_SCRIPT)
|
||||
{
|
||||
$relTrigger = new AreaTriggerList(array(['id', $this->typeId, '!'], ['name', $this->subject->getField('name')]));
|
||||
if (!$relTrigger->error)
|
||||
{
|
||||
$this->lvTabs[] = ['areatrigger', ['data' => array_values($relTrigger->getListviewData()), 'name' => Util::ucFirst(Lang::game('areatrigger'))], 'areatrigger'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,89 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 102: Areatrigger g_initPath()
|
||||
// tabid 0: Database g_initHeader()
|
||||
class AreaTriggersPage extends GenericPage
|
||||
{
|
||||
use TrListPage;
|
||||
|
||||
protected $type = Type::AREATRIGGER;
|
||||
protected $tpl = 'areatriggers';
|
||||
protected $path = [0, 102];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
protected $validCats = [0, 1, 2, 3, 4, 5];
|
||||
protected $js = [[JS_FILE, 'filters.js']];
|
||||
protected $reqUGroup = U_GROUP_STAFF;
|
||||
|
||||
protected $_get = ['filter' => ['filter' => FILTER_UNSAFE_RAW]];
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);;
|
||||
if (isset($this->category[0]))
|
||||
header('Location: ?areatriggers&filter=ty='.$this->category[0], true, 302);
|
||||
|
||||
$this->filterObj = new AreaTriggerListFilter();
|
||||
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
$this->name = Util::ucFirst(Lang::game('areatriggers'));
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
// recreate form selection
|
||||
$this->filter = $this->filterObj->getForm();
|
||||
$this->filter['query'] = $this->_get['filter'];
|
||||
$this->filter['initData'] = ['init' => 'areatrigger'];
|
||||
|
||||
if ($x = $this->filterObj->getSetCriteria())
|
||||
$this->filter['initData']['sc'] = $x;
|
||||
|
||||
$conditions = [];
|
||||
if ($_ = $this->filterObj->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$tabData = [];
|
||||
$trigger = new AreaTriggerList($conditions);
|
||||
if (!$trigger->error)
|
||||
{
|
||||
$tabData['data'] = array_values($trigger->getListviewData());
|
||||
|
||||
// create note if search limit was exceeded; overwriting 'note' is intentional
|
||||
if ($trigger->getMatches() > CFG_SQL_LIMIT_DEFAULT)
|
||||
{
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringEntityString, $trigger->getMatches(), '"'.Lang::game('areatriggers').'"', CFG_SQL_LIMIT_DEFAULT);
|
||||
$tabData['_truncated'] = 1;
|
||||
}
|
||||
|
||||
if ($this->filterObj->error)
|
||||
$tabData['_errors'] = 1;
|
||||
|
||||
}
|
||||
|
||||
$this->lvTabs[] = ['areatrigger', $tabData, 'areatrigger'];
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
array_unshift($this->title, $this->name);
|
||||
|
||||
$form = $this->filterObj->getForm();
|
||||
if (isset($form['ty']) && count($form['ty']) == 1)
|
||||
array_unshift($this->title, Lang::areatrigger('types', $form['ty'][0]));
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
{
|
||||
$form = $this->filterObj->getForm();
|
||||
if (isset($form['ty']) && count($form['ty']) == 1)
|
||||
$this->path[] = $form['ty'];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,144 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 5: Profiler g_initPath()
|
||||
// tabId 1: Tools g_initHeader()
|
||||
class ArenaTeamPage extends GenericPage
|
||||
{
|
||||
use TrProfiler;
|
||||
|
||||
protected $lvTabs = [];
|
||||
|
||||
protected $type = Type::ARENA_TEAM;
|
||||
|
||||
protected $tabId = 1;
|
||||
protected $path = [1, 5, 3];
|
||||
protected $tpl = 'roster';
|
||||
protected $js = [[JS_FILE, 'profile_all.js'], [JS_FILE, 'profile.js']];
|
||||
protected $css = [[CSS_FILE, 'Profiler.css']];
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
if (!CFG_PROFILER_ENABLE)
|
||||
$this->error();
|
||||
|
||||
$params = array_map('urldecode', explode('.', $pageParam));
|
||||
if ($params[0])
|
||||
$params[0] = Profiler::urlize($params[0]);
|
||||
if (isset($params[1]))
|
||||
$params[1] = Profiler::urlize($params[1]);
|
||||
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
if (count($params) == 1 && intval($params[0]))
|
||||
{
|
||||
$this->subject = new LocalArenaTeamList(array(['at.id', intval($params[0])]));
|
||||
if ($this->subject->error)
|
||||
$this->notFound();
|
||||
|
||||
header('Location: '.$this->subject->getProfileUrl(), true, 302);
|
||||
}
|
||||
else if (count($params) == 3)
|
||||
{
|
||||
$this->getSubjectFromUrl($pageParam);
|
||||
if (!$this->subjectName)
|
||||
$this->notFound();
|
||||
|
||||
// 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['cuFlags'] & PROFILER_CU_NEEDS_RESYNC)
|
||||
{
|
||||
$this->handleIncompleteData($subject['realmGUID']);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->subjectGUID = $subject['id'];
|
||||
$this->subject = new LocalArenaTeamList(array(['id', $subject['id']]));
|
||||
if ($this->subject->error)
|
||||
$this->notFound();
|
||||
|
||||
$this->profile = $params;
|
||||
$this->name = sprintf(Lang::profiler('arenaRoster'), $this->subject->getField('name'));
|
||||
}
|
||||
// 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 ($team = 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)))
|
||||
{
|
||||
$team['realm'] = $this->realmId;
|
||||
$team['cuFlags'] = PROFILER_CU_NEEDS_RESYNC;
|
||||
|
||||
// create entry from realm with basic info
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_profiler_arena_team (?#) VALUES (?a)', array_keys($team), array_values($team));
|
||||
|
||||
$this->handleIncompleteData($team['realmGUID']);
|
||||
}
|
||||
// 3) does not exist at all
|
||||
else
|
||||
$this->notFound();
|
||||
}
|
||||
else
|
||||
$this->notFound();
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
$team = !empty($this->subject) ? $this->subject->getField('name') : $this->subjectName;
|
||||
$team .= ' ('.$this->realm.' - '.Lang::profiler('regions', $this->region).')';
|
||||
|
||||
array_unshift($this->title, $team, Util::ucFirst(Lang::profiler('profiler')));
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
if ($this->doResync)
|
||||
return;
|
||||
|
||||
$this->addScript([JS_FILE, '?data=realms.weight-presets&locale='.User::$localeId.'&t='.$_SESSION['dataKey']]);
|
||||
|
||||
$this->redButtons[BUTTON_RESYNC] = [$this->subjectGUID, 'arena-team'];
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
|
||||
// statistic calculations here
|
||||
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
// tab: members
|
||||
$member = new LocalProfileList(array(['atm.arenaTeamId', $this->subjectGUID]));
|
||||
if (!$member->error)
|
||||
{
|
||||
$this->lvTabs[] = ['profile', array(
|
||||
'data' => array_values($member->getListviewData(PROFILEINFO_CHARACTER | PROFILEINFO_ARENA)),
|
||||
'sort' => [-15],
|
||||
'visibleCols' => ['race', 'classs', 'level', 'talents', 'gearscore', 'rating', 'wins', 'losses'],
|
||||
'hiddenCols' => ['guild', 'location']
|
||||
)];
|
||||
}
|
||||
}
|
||||
|
||||
public function notFound(string $title = '', string $msg = '') : void
|
||||
{
|
||||
parent::notFound($title ?: Util::ucFirst(Lang::profiler('profiler')), $msg ?: Lang::profiler('notFound', 'arenateam'));
|
||||
}
|
||||
|
||||
private function handleIncompleteData($teamGuid)
|
||||
{
|
||||
//display empty page and queue status
|
||||
$newId = Profiler::scheduleResync(Type::ARENA_TEAM, $this->realmId, $teamGuid);
|
||||
|
||||
$this->doResync = ['arena-team', $newId];
|
||||
$this->initialSync();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,123 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 5: Profiler g_initPath()
|
||||
// tabId 1: Tools g_initHeader()
|
||||
class ArenaTeamsPage extends GenericPage
|
||||
{
|
||||
use TrProfiler;
|
||||
|
||||
protected $type = Type::ARENA_TEAM;
|
||||
|
||||
protected $tabId = 1;
|
||||
protected $path = [1, 5, 3];
|
||||
protected $tpl = 'arena-teams';
|
||||
protected $js = [[JS_FILE, 'filters.js'], [JS_FILE, 'profile_all.js'], [JS_FILE, 'profile.js']];
|
||||
|
||||
protected $_get = ['filter' => ['filter' => FILTER_UNSAFE_RAW]];
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
if (!CFG_PROFILER_ENABLE)
|
||||
$this->error();
|
||||
|
||||
$this->getSubjectFromUrl($pageParam);
|
||||
|
||||
$this->filterObj = new ArenaTeamListFilter();
|
||||
|
||||
foreach (Profiler::getRealms() as $idx => $r)
|
||||
{
|
||||
if ($this->region && $r['region'] != $this->region)
|
||||
continue;
|
||||
|
||||
if ($this->realm && $r['name'] != $this->realm)
|
||||
continue;
|
||||
|
||||
$this->sumSubjects += DB::Characters($idx)->selectCell('SELECT count(*) FROM arena_team');
|
||||
}
|
||||
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
$this->name = Lang::profiler('arenaTeams');
|
||||
$this->subCat = $pageParam ? '='.$pageParam : '';
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
if ($this->realm)
|
||||
array_unshift($this->title, $this->realm,/* CFG_BATTLEGROUP,*/ Lang::profiler('regions', $this->region), Lang::profiler('arenaTeams'));
|
||||
else if ($this->region)
|
||||
array_unshift($this->title, Lang::profiler('regions', $this->region), Lang::profiler('arenaTeams'));
|
||||
else
|
||||
array_unshift($this->title, Lang::profiler('arenaTeams'));
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$this->addScript([JS_FILE, '?data=realms&locale='.User::$localeId.'&t='.$_SESSION['dataKey']]);
|
||||
|
||||
$conditions = [];
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = ['at.rating', 1000, '>'];
|
||||
|
||||
if ($_ = $this->filterObj->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
// recreate form selection
|
||||
$this->filter = $this->filterObj->getForm();
|
||||
$this->filter['query'] = $this->_get['filter'];
|
||||
$this->filter['initData'] = ['type' => 'arenateams'];
|
||||
|
||||
$tabData = array(
|
||||
'id' => 'arena-teams',
|
||||
'hideCount' => 1,
|
||||
'sort' => [-16],
|
||||
'extraCols' => ['$Listview.extraCols.members'],
|
||||
'visibleCols' => ['rank', 'wins', 'losses', 'rating'],
|
||||
'hiddenCols' => ['arenateam', 'guild'],
|
||||
);
|
||||
|
||||
if (empty($this->filter['sz']))
|
||||
$tabData['visibleCols'][] = 'size';
|
||||
|
||||
$miscParams = [];
|
||||
if ($this->realm)
|
||||
$miscParams['sv'] = $this->realm;
|
||||
if ($this->region)
|
||||
$miscParams['rg'] = $this->region;
|
||||
|
||||
$teams = new RemoteArenaTeamList($conditions, $miscParams);
|
||||
if (!$teams->error)
|
||||
{
|
||||
$teams->initializeLocalEntries();
|
||||
|
||||
$dFields = $teams->hasDiffFields(['faction', 'type']);
|
||||
if (!($dFields & 0x1))
|
||||
$tabData['hiddenCols'][] = 'faction';
|
||||
|
||||
$tabData['data'] = array_values($teams->getListviewData());
|
||||
|
||||
// create note if search limit was exceeded
|
||||
if ($this->filter['query'] && $teams->getMatches() > CFG_SQL_LIMIT_DEFAULT)
|
||||
{
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_arenateamsfound2', $this->sumSubjects, $teams->getMatches());
|
||||
$tabData['_truncated'] = 1;
|
||||
}
|
||||
else if ($teams->getMatches() > CFG_SQL_LIMIT_DEFAULT)
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_arenateamsfound', $this->sumSubjects, 0);
|
||||
|
||||
if ($this->filterObj->error)
|
||||
$tabData['_errors'] = 1;
|
||||
}
|
||||
|
||||
$this->lvTabs[] = ['profile', $tabData, 'membersCol'];
|
||||
|
||||
Lang::sort('game', 'cl');
|
||||
Lang::sort('game', 'ra');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -8,15 +8,15 @@ if (!defined('AOWOW_REVISION'))
|
||||
// tabId 0: Database g_initHeader()
|
||||
class ClassPage extends GenericPage
|
||||
{
|
||||
use TrDetailPage;
|
||||
use DetailPage;
|
||||
|
||||
protected $type = Type::CHR_CLASS;
|
||||
protected $type = TYPE_CLASS;
|
||||
protected $typeId = 0;
|
||||
protected $tpl = 'detail-page-generic';
|
||||
protected $path = [0, 12];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
protected $js = [[JS_FILE, 'swfobject.js']];
|
||||
protected $js = ['swfobject.js'];
|
||||
|
||||
public function __construct($pageCall, $id)
|
||||
{
|
||||
@@ -43,7 +43,7 @@ class ClassPage extends GenericPage
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$this->addScript([JS_FILE, '?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']]);
|
||||
$this->addJS('?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']);
|
||||
|
||||
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
|
||||
$_mask = 1 << ($this->typeId - 1);
|
||||
@@ -96,7 +96,7 @@ class ClassPage extends GenericPage
|
||||
$this->expansion = Util::$expansionString[$this->subject->getField('expansion')];
|
||||
$this->headIcons = ['class_'.strtolower($this->subject->getField('fileString'))];
|
||||
$this->redButtons = array(
|
||||
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId],
|
||||
BUTTON_LINKS => ['color' => '', 'linkId' => ''],
|
||||
BUTTON_WOWHEAD => true,
|
||||
BUTTON_TALENT => ['href' => '?talent#'.Util::$tcEncoding[$tcClassId[$this->typeId] * 3], 'pet' => false],
|
||||
BUTTON_FORUM => false // todo (low): CFG_BOARD_URL + X
|
||||
@@ -126,25 +126,27 @@ class ClassPage extends GenericPage
|
||||
'OR',
|
||||
['s.cuFlags', SPELL_CU_LAST_RANK, '&'],
|
||||
['s.rankNo', 0]
|
||||
],
|
||||
CFG_SQL_LIMIT_NONE
|
||||
]
|
||||
);
|
||||
|
||||
$genSpells = new SpellList($conditions);
|
||||
if (!$genSpells->error)
|
||||
{
|
||||
$this->extendGlobalData($genSpells->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
|
||||
$this->extendGlobalData($genSpells->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$this->lvTabs[] = ['spell', array(
|
||||
'data' => array_values($genSpells->getListviewData()),
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'spell',
|
||||
'data' => $genSpells->getListviewData(),
|
||||
'params' => array(
|
||||
'id' => 'spells',
|
||||
'name' => '$LANG.tab_spells',
|
||||
'visibleCols' => ['level', 'schools', 'type', 'classes'],
|
||||
'hiddenCols' => ['reagents', 'skill'],
|
||||
'sort' => ['-level', 'type', 'name'],
|
||||
'visibleCols' => "$['level', 'schools', 'type', 'classes']",
|
||||
'hiddenCols' => "$['reagents', 'skill']",
|
||||
'sort' => "$['-level', 'type', 'name']",
|
||||
'computeDataFunc' => '$Listview.funcBox.initSpellFilter',
|
||||
'onAfterCreate' => '$Listview.funcBox.addSpellIndicator'
|
||||
)];
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Tab: Items (grouped)
|
||||
@@ -153,7 +155,7 @@ class ClassPage extends GenericPage
|
||||
['requiredClass', $_mask, '&'],
|
||||
[['requiredClass', CLASS_MASK_ALL, '&'], CLASS_MASK_ALL, '!'],
|
||||
['itemset', 0], // hmm, do or dont..?
|
||||
CFG_SQL_LIMIT_NONE
|
||||
0
|
||||
);
|
||||
|
||||
$items = new ItemList($conditions);
|
||||
@@ -161,21 +163,23 @@ class ClassPage extends GenericPage
|
||||
{
|
||||
$this->extendGlobalData($items->getJSGlobals());
|
||||
|
||||
$hiddenCols = null;
|
||||
if ($items->hasDiffFields(['requiredRace']))
|
||||
$hiddenCols = ['side'];
|
||||
if (!$items->hasDiffFields(['requiredRace']))
|
||||
$hidden = "$['side']";
|
||||
|
||||
$this->lvTabs[] = ['item', array(
|
||||
'data' => array_values($items->getListviewData()),
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'item',
|
||||
'data' => $items->getListviewData(),
|
||||
'params' => array(
|
||||
'id' => 'items',
|
||||
'name' => '$LANG.tab_items',
|
||||
'visibleCols' => ['dps', 'armor', 'slot'],
|
||||
'hiddenCols' => $hiddenCols,
|
||||
'visibleCols' => "$['dps', 'armor', 'slot']",
|
||||
'hiddenCols' => isset($hidden) ? $hidden : null,
|
||||
'computeDataFunc' => '$Listview.funcBox.initSubclassFilter',
|
||||
'onAfterCreate' => '$Listview.funcBox.addSubclassIndicator',
|
||||
'note' => sprintf(Util::$filterResultString, '?items&filter=cr=152;crs='.$this->typeId.';crv=0'),
|
||||
'_truncated' => 1
|
||||
)];
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Tab: Quests
|
||||
@@ -189,10 +193,11 @@ class ClassPage extends GenericPage
|
||||
{
|
||||
$this->extendGlobalData($quests->getJSGlobals());
|
||||
|
||||
$this->lvTabs[] = ['quest', array(
|
||||
'data' => array_values($quests->getListviewData()),
|
||||
'sort' => ['reqlevel', 'name']
|
||||
)];
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'quest',
|
||||
'data' => $quests->getListviewData(),
|
||||
'params' => ['sort' => "$['reqlevel', 'name']"]
|
||||
);
|
||||
}
|
||||
|
||||
// Tab: Itemsets
|
||||
@@ -201,35 +206,47 @@ class ClassPage extends GenericPage
|
||||
{
|
||||
$this->extendGlobalData($sets->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$this->lvTabs[] = ['itemset', array(
|
||||
'data' => array_values($sets->getListviewData()),
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'itemset',
|
||||
'data' => $sets->getListviewData(),
|
||||
'params' => array(
|
||||
'note' => sprintf(Util::$filterResultString, '?itemsets&filter=cl='.$this->typeId),
|
||||
'hiddenCols' => ['classes'],
|
||||
'sort' => ['-level', 'name']
|
||||
)];
|
||||
'hiddenCols' => "$['classes']",
|
||||
'sort' => "$['-level', 'name']"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Tab: Trainer
|
||||
$conditions = array(
|
||||
['npcflag', 0x30, '&'], // is trainer
|
||||
['trainerType', 0], // trains class spells
|
||||
['trainerRequirement', $this->typeId]
|
||||
['trainerClass', $this->typeId]
|
||||
);
|
||||
|
||||
$trainer = new CreatureList($conditions);
|
||||
if (!$trainer->error)
|
||||
{
|
||||
$this->lvTabs[] = ['creature', array(
|
||||
'data' => array_values($trainer->getListviewData()),
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'creature',
|
||||
'data' => $trainer->getListviewData(),
|
||||
'params' => array(
|
||||
'id' => 'trainers',
|
||||
'name' => '$LANG.tab_trainers'
|
||||
)];
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Tab: Races
|
||||
$races = new CharRaceList(array(['classMask', $_mask, '&']));
|
||||
if (!$races->error)
|
||||
$this->lvTabs[] = ['race', ['data' => array_values($races->getListviewData())]];
|
||||
{
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'race',
|
||||
'data' => $races->getListviewData(),
|
||||
'params' => []
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ if (!defined('AOWOW_REVISION'))
|
||||
// tabId 0: Database g_initHeader()
|
||||
class ClassesPage extends GenericPage
|
||||
{
|
||||
use TrListPage;
|
||||
use ListPage;
|
||||
|
||||
protected $type = Type::CHR_CLASS;
|
||||
protected $type = TYPE_CLASS;
|
||||
protected $tpl = 'list-page-generic';
|
||||
protected $path = [0, 12];
|
||||
protected $tabId = 0;
|
||||
@@ -27,7 +27,13 @@ class ClassesPage extends GenericPage
|
||||
{
|
||||
$classes = new CharClassList();
|
||||
if (!$classes->error)
|
||||
$this->lvTabs[] = ['class', ['data' => array_values($classes->getListviewData())]];
|
||||
{
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'class',
|
||||
'data' => $classes->getListviewData(),
|
||||
'params' => []
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
die('invalid access');
|
||||
|
||||
|
||||
// tabId 1: Tools g_initHeader()
|
||||
@@ -12,31 +12,28 @@ class ComparePage extends GenericPage
|
||||
protected $path = [1, 3];
|
||||
protected $mode = CACHE_TYPE_NONE;
|
||||
protected $js = array(
|
||||
[JS_FILE, 'profile.js'],
|
||||
[JS_FILE, 'Draggable.js'],
|
||||
[JS_FILE, 'filters.js'],
|
||||
[JS_FILE, 'Summary.js'],
|
||||
[JS_FILE, 'swfobject.js'],
|
||||
'profile.js',
|
||||
'Draggable.js',
|
||||
'filters.js',
|
||||
'Summary.js',
|
||||
'swfobject.js',
|
||||
);
|
||||
protected $css = [[CSS_FILE, 'Summary.css']];
|
||||
protected $css = [['path' => 'Summary.css']];
|
||||
|
||||
protected $summary = [];
|
||||
protected $cmpItems = [];
|
||||
|
||||
protected $_get = ['compare' => ['filter' => FILTER_CALLBACK, 'options' => 'ComparePage::checkCompareString']];
|
||||
protected $_cookie = ['compare_groups' => ['filter' => FILTER_CALLBACK, 'options' => 'ComparePage::checkCompareString']];
|
||||
|
||||
private $compareString = '';
|
||||
|
||||
public function __construct($pageCall, $__)
|
||||
{
|
||||
parent::__construct($pageCall, $__);
|
||||
|
||||
// prefer GET over COOKIE
|
||||
if ($this->_get['compare'])
|
||||
$this->compareString = $this->_get['compare'];
|
||||
else if ($this->_cookie['compare_groups'])
|
||||
$this->compareString = $this->_cookie['compare_groups'];
|
||||
// prefer $_GET over $_COOKIE
|
||||
if (!empty($_GET['compare']))
|
||||
$this->compareString = $_GET['compare'];
|
||||
else if (!empty($_COOKIE['compare_groups']))
|
||||
$this->compareString = urldecode($_COOKIE['compare_groups']);
|
||||
|
||||
$this->name = Lang::main('compareTool');
|
||||
}
|
||||
@@ -44,13 +41,7 @@ class ComparePage extends GenericPage
|
||||
protected function generateContent()
|
||||
{
|
||||
// add conditional js
|
||||
$this->addScript([JS_FILE, '?data=weight-presets.gems.enchants.itemsets&locale='.User::$localeId.'&t='.$_SESSION['dataKey']]);
|
||||
|
||||
$this->summary = array(
|
||||
'template' => 'compare',
|
||||
'id' => 'compare',
|
||||
'parent' => 'compare-generic'
|
||||
);
|
||||
$this->addJS('?data=weight-presets.gems.enchants.itemsets&locale='.User::$localeId.'&t='.$_SESSION['dataKey']);
|
||||
|
||||
if (!$this->compareString)
|
||||
return;
|
||||
@@ -59,20 +50,21 @@ class ComparePage extends GenericPage
|
||||
$items = $outSet = [];
|
||||
foreach ($sets as $set)
|
||||
{
|
||||
$itemString = explode(':', $set);
|
||||
$itemSting = explode(':', $set);
|
||||
$outString = [];
|
||||
foreach ($itemString as $is)
|
||||
foreach ($itemSting as $substring)
|
||||
{
|
||||
$params = array_pad(explode('.', $is), 7, 0);
|
||||
$params = explode('.', $substring);
|
||||
$items[] = (int)$params[0];
|
||||
while (sizeof($params) < 7)
|
||||
$params[] = 0;
|
||||
|
||||
$outString[] = $params;
|
||||
}
|
||||
|
||||
$outSet[] = $outString;
|
||||
}
|
||||
|
||||
$this->summary['groups'] = $outSet;
|
||||
$this->summary = $outSet;
|
||||
|
||||
$iList = new ItemList(array(['i.id', $items]));
|
||||
$data = $iList->getListviewData(ITEMINFO_SUBITEMS | ITEMINFO_JSON);
|
||||
@@ -82,15 +74,12 @@ class ComparePage extends GenericPage
|
||||
if (empty($data[$itemId]))
|
||||
continue;
|
||||
|
||||
if (!empty($data[$itemId]['subitems']))
|
||||
foreach ($data[$itemId]['subitems'] as &$si)
|
||||
$si['enchantment'] = implode(', ', $si['enchantment']);
|
||||
|
||||
$this->cmpItems[$itemId] = [
|
||||
'name_'.User::$localeString => $iList->getField('name', true),
|
||||
'quality' => $iList->getField('quality'),
|
||||
'icon' => $iList->getField('iconString'),
|
||||
'jsonequip' => $data[$itemId]
|
||||
$this->cmpItems[] = [
|
||||
$itemId,
|
||||
$iList->getField('name', true),
|
||||
$iList->getField('quality'),
|
||||
$iList->getField('iconString'),
|
||||
$data[$itemId]
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -101,15 +90,6 @@ class ComparePage extends GenericPage
|
||||
}
|
||||
|
||||
protected function generatePath() {}
|
||||
|
||||
protected static function checkCompareString(string $val) : string
|
||||
{
|
||||
$val = urldecode($val);
|
||||
if (preg_match('/[^\d\.:;]/', $val))
|
||||
return '';
|
||||
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -8,9 +8,9 @@ if (!defined('AOWOW_REVISION'))
|
||||
// tabId 0: Database g_initHeader()
|
||||
class CurrenciesPage extends GenericPage
|
||||
{
|
||||
use TrListPage;
|
||||
use ListPage;
|
||||
|
||||
protected $type = Type::CURRENCY;
|
||||
protected $type = TYPE_CURRENCY;
|
||||
protected $tpl = 'list-page-generic';
|
||||
protected $path = [0, 15];
|
||||
protected $tabId = 0;
|
||||
@@ -37,7 +37,11 @@ class CurrenciesPage extends GenericPage
|
||||
$conditions[] = ['category', (int)$this->category[0]];
|
||||
|
||||
$money = new CurrencyList($conditions);
|
||||
$this->lvTabs[] = ['currency', ['data' => array_values($money->getListviewData())]];
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'currency',
|
||||
'data' => $money->getListviewData(),
|
||||
'params' => []
|
||||
);
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
|
||||
@@ -8,27 +8,19 @@ if (!defined('AOWOW_REVISION'))
|
||||
// tabId 0: Database g_initHeader()
|
||||
class CurrencyPage extends GenericPage
|
||||
{
|
||||
use TrDetailPage;
|
||||
use DetailPage;
|
||||
|
||||
protected $type = Type::CURRENCY;
|
||||
protected $type = TYPE_CURRENCY;
|
||||
protected $typeId = 0;
|
||||
protected $tpl = 'detail-page-generic';
|
||||
protected $path = [0, 15];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
|
||||
protected $_get = ['domain' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkDomain']];
|
||||
|
||||
private $powerTpl = '$WowheadPower.registerCurrency(%d, %d, %s);';
|
||||
|
||||
public function __construct($pageCall, $id)
|
||||
{
|
||||
parent::__construct($pageCall, $id);
|
||||
|
||||
// temp locale
|
||||
if ($this->mode == CACHE_TYPE_TOOLTIP && $this->_get['domain'])
|
||||
Util::powerUseLocale($this->_get['domain']);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
|
||||
$this->subject = new CurrencyList(array(['id', $this->typeId]));
|
||||
@@ -50,7 +42,7 @@ class CurrencyPage extends GenericPage
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$this->addScript([JS_FILE, '?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']]);
|
||||
$this->addJS('?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']);
|
||||
|
||||
$_itemId = $this->subject->getField('itemId');
|
||||
|
||||
@@ -58,18 +50,12 @@ class CurrencyPage extends GenericPage
|
||||
/* Infobox */
|
||||
/**********/
|
||||
|
||||
$infobox = Lang::getInfoBoxForFlags(intval($this->subject->getField('cuFlags')));
|
||||
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
|
||||
|
||||
// cap
|
||||
if ($_ = $this->subject->getField('cap'))
|
||||
$infobox[] = Lang::currency('cap').Lang::main('colon').Lang::nf($_);
|
||||
|
||||
// icon
|
||||
if ($_ = $this->subject->getField('iconId'))
|
||||
{
|
||||
$infobox[] = Util::ucFirst(lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
|
||||
$this->extendGlobalIds(Type::ICON, $_);
|
||||
}
|
||||
if ($this->typeId == 103) // Arena Points
|
||||
$infobox[] = Lang::currency('cap').Lang::main('colon').'10\'000';
|
||||
else if ($this->typeId == 104) // Honor
|
||||
$infobox[] = Lang::currency('cap').Lang::main('colon').'75\'000';
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
@@ -83,9 +69,6 @@ class CurrencyPage extends GenericPage
|
||||
BUTTON_LINKS => true
|
||||
);
|
||||
|
||||
if ($_ = $this->subject->getField('description', true))
|
||||
$this->extraText = $_;
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
@@ -99,8 +82,20 @@ class CurrencyPage extends GenericPage
|
||||
{
|
||||
$this->extendGlobalData($lootTabs->jsGlobals);
|
||||
|
||||
foreach ($lootTabs->iterate() as [$file, $tabData])
|
||||
$this->lvTabs[] = [$file, $tabData];
|
||||
foreach ($lootTabs->iterate() as $tab)
|
||||
{
|
||||
$this->lvTabs[] = array(
|
||||
'file' => $tab[0],
|
||||
'data' => $tab[1],
|
||||
'params' => [
|
||||
'name' => $tab[2],
|
||||
'id' => $tab[3],
|
||||
'extraCols' => $tab[4] ? '$['.implode(', ', array_unique($tab[4])).']' : null,
|
||||
'hiddenCols' => $tab[5] ? '$['.implode(', ', array_unique($tab[5])).']' : null,
|
||||
'visibleCols' => $tab[6] ? '$'. Util::toJSON( array_unique($tab[6])) : null
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tab: sold by
|
||||
@@ -114,15 +109,14 @@ class CurrencyPage extends GenericPage
|
||||
if (!$soldBy->error)
|
||||
{
|
||||
$sbData = $soldBy->getListviewData();
|
||||
$extraCols = ['$Listview.extraCols.stock', "\$Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')", '$Listview.extraCols.cost'];
|
||||
$extraCols = ['Listview.extraCols.stock', "Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')", 'Listview.extraCols.cost'];
|
||||
$holidays = [];
|
||||
|
||||
foreach ($sbData as $k => &$row)
|
||||
{
|
||||
$items = [];
|
||||
$tokens = [];
|
||||
// note: can only display one entry per row, so only use first entry of each vendor
|
||||
foreach ($vendors[$k][0] as $id => $qty)
|
||||
foreach ($vendors[$k] as $id => $qty)
|
||||
{
|
||||
if (is_string($id))
|
||||
continue;
|
||||
@@ -133,16 +127,16 @@ class CurrencyPage extends GenericPage
|
||||
$items[] = [-$id, $qty];
|
||||
}
|
||||
|
||||
if ($vendors[$k][0]['event'])
|
||||
if ($vendors[$k]['event'])
|
||||
{
|
||||
if (count($extraCols) == 3) // not already pushed
|
||||
$extraCols[] = '$Listview.extraCols.condition';
|
||||
$extraCols[] = 'Listview.extraCols.condition';
|
||||
|
||||
$this->extendGlobalIds(Type::WORLDEVENT, $vendors[$k][0]['event']);
|
||||
$row['condition'][0][$this->typeId][] = [[CND_ACTIVE_EVENT, $vendors[$k][0]['event']]];
|
||||
$this->extendGlobalIds(TYPE_WORLDEVENT, $vendors[$k]['event']);
|
||||
$row['condition'][0][$this->typeId][] = [[CND_ACTIVE_EVENT, $vendors[$k]['event']]];
|
||||
}
|
||||
|
||||
$row['stock'] = $vendors[$k][0]['stock'];
|
||||
$row['stock'] = $vendors[$k]['stock'];
|
||||
$row['stack'] = $itemObj->getField('buyCount');
|
||||
$row['cost'] = array(
|
||||
$itemObj->getField('buyPrice'),
|
||||
@@ -151,13 +145,16 @@ class CurrencyPage extends GenericPage
|
||||
);
|
||||
}
|
||||
|
||||
$this->lvTabs[] = ['creature', array(
|
||||
'data' => array_values($sbData),
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'creature',
|
||||
'data' => $sbData,
|
||||
'params' => [
|
||||
'name' => '$LANG.tab_soldby',
|
||||
'id' => 'sold-by-npc',
|
||||
'extraCols' => $extraCols,
|
||||
'hiddenCols' => ['level', 'type']
|
||||
)];
|
||||
'extraCols' => '$['.implode(', ', $extraCols).']',
|
||||
'hiddenCols' => "$['level', 'type']"
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,16 +167,18 @@ class CurrencyPage extends GenericPage
|
||||
{
|
||||
$this->extendGlobalData($createdBy->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
|
||||
|
||||
$tabData = array(
|
||||
'data' => array_values($createdBy->getListviewData()),
|
||||
if ($createdBy->hasSetFields(['reagent1']))
|
||||
$visCols = ['reagents'];
|
||||
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'spell',
|
||||
'data' => $createdBy->getListviewData(),
|
||||
'params' => [
|
||||
'name' => '$LANG.tab_createdby',
|
||||
'id' => 'created-by',
|
||||
'visibleCols' => isset($visCols) ? '$'.Util::toJSON($visCols) : null
|
||||
]
|
||||
);
|
||||
|
||||
if ($createdBy->hasSetFields(['reagent1']))
|
||||
$tabData['visibleCols'] = ['reagents'];
|
||||
|
||||
$this->lvTabs[] = ['spell', $tabData];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,35 +206,24 @@ class CurrencyPage extends GenericPage
|
||||
$boughtBy = new ItemList(array(['id', $boughtBy]));
|
||||
if (!$boughtBy->error)
|
||||
{
|
||||
$tabData = array(
|
||||
'data' => array_values($boughtBy->getListviewData(ITEMINFO_VENDOR, [Type::CURRENCY => $this->typeId])),
|
||||
if ($boughtBy->getMatches() <= CFG_SQL_LIMIT_DEFAULT)
|
||||
$n = null;
|
||||
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'item',
|
||||
'data' => $boughtBy->getListviewData(ITEMINFO_VENDOR, [TYPE_CURRENCY => $this->typeId]),
|
||||
'params' => [
|
||||
'name' => '$LANG.tab_currencyfor',
|
||||
'id' => 'currency-for',
|
||||
'extraCols' => ["\$Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')", '$Listview.extraCols.cost'],
|
||||
'extraCols' => "$[Listview.funcBox.createSimpleCol('stack', 'stack', '10%', 'stack')]",
|
||||
'note' => $n ? sprintf(Util::$filterResultString, $n) : null
|
||||
]
|
||||
);
|
||||
|
||||
if ($boughtBy->getMatches() > CFG_SQL_LIMIT_DEFAULT)
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, $n);
|
||||
|
||||
$this->lvTabs[] = ['item', $tabData];
|
||||
|
||||
$this->extendGlobalData($boughtBy->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function generateTooltip()
|
||||
{
|
||||
$power = new StdClass();
|
||||
if (!$this->subject->error)
|
||||
{
|
||||
$power->{'name_'.User::$localeString} = $this->subject->getField('name', true);
|
||||
$power->icon = rawurlencode($this->subject->getField('iconString', true, true));
|
||||
$power->{'tooltip_'.User::$localeString} = $this->subject->renderTooltip();
|
||||
}
|
||||
|
||||
return sprintf($this->powerTpl, $this->typeId, User::$localeId, Util::toJSON($power, JSON_AOWOW_POWER));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
128
pages/emote.php
128
pages/emote.php
@@ -1,128 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 100: Emotes g_initPath()
|
||||
// tabid 0: Database g_initHeader()
|
||||
class EmotePage extends GenericPage
|
||||
{
|
||||
use TrDetailPage;
|
||||
|
||||
protected $type = Type::EMOTE;
|
||||
protected $typeId = 0;
|
||||
protected $tpl = 'detail-page-generic';
|
||||
protected $path = [0, 100];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
|
||||
public function __construct($pageCall, $id)
|
||||
{
|
||||
parent::__construct($pageCall, $id);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
|
||||
$this->subject = new EmoteList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->notFound(Lang::game('emote'), Lang::emote('notFound'));
|
||||
|
||||
$this->name = Util::ucFirst($this->subject->getField('cmd'));
|
||||
}
|
||||
|
||||
protected function generatePath() { }
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
array_unshift($this->title, $this->name, Util::ucFirst(Lang::game('emote')));
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
/***********/
|
||||
/* Infobox */
|
||||
/***********/
|
||||
|
||||
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
|
||||
|
||||
// has Animation
|
||||
if ($this->subject->getField('isAnimated'))
|
||||
$infobox[] = Lang::emote('isAnimated');
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
$text = '';
|
||||
if ($aliasses = DB::Aowow()->selectCol('SELECT command FROM ?_emotes_aliasses WHERE id = ?d AND locales & ?d', $this->typeId, 1 << User::$localeId))
|
||||
{
|
||||
$text .= '[h3]'.Lang::emote('aliases').'[/h3][ul]';
|
||||
foreach ($aliasses as $a)
|
||||
$text .= '[li]/'.$a.'[/li]';
|
||||
|
||||
$text .= '[/ul][br][br]';
|
||||
}
|
||||
|
||||
$texts = [];
|
||||
if ($_ = $this->subject->getField('self', true))
|
||||
$texts[Lang::emote('self')] = $_;
|
||||
|
||||
if ($_ = $this->subject->getField('target', true))
|
||||
$texts[Lang::emote('target')] = $_;
|
||||
|
||||
if ($_ = $this->subject->getField('noTarget', true))
|
||||
$texts[Lang::emote('noTarget')] = $_;
|
||||
|
||||
if (!$texts)
|
||||
$text .= '[div][i class=q0]'.Lang::emote('noText').'[/i][/div]';
|
||||
else
|
||||
foreach ($texts as $h => $t)
|
||||
$text .= '[pad][b]'.$h.'[/b][ul][li][span class=s4]'.preg_replace('/%\d?\$?s/', '<'.Util::ucFirst(Lang::main('name')).'>', $t).'[/span][/li][/ul]';
|
||||
|
||||
$this->extraText = $text;
|
||||
$this->infobox = $infobox ? '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]' : null;
|
||||
$this->redButtons = array(
|
||||
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId],
|
||||
BUTTON_WOWHEAD => false
|
||||
);
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
// tab: achievement
|
||||
$condition = array(
|
||||
['ac.type', ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE],
|
||||
['ac.value1', $this->typeId],
|
||||
);
|
||||
$acv = new AchievementList($condition);
|
||||
|
||||
$this->lvTabs[] = ['achievement', ['data' => array_values($acv->getListviewData())]];
|
||||
|
||||
$this->extendGlobalData($acv->getJsGlobals());
|
||||
|
||||
// tab: sound
|
||||
if ($em = DB::Aowow()->select('SELECT soundId AS ARRAY_KEY, BIT_OR(1 << (raceId - 1)) AS raceMask, BIT_OR(1 << (gender - 1)) AS gender FROM aowow_emotes_sounds WHERE emoteId = ?d GROUP BY soundId', $this->typeId))
|
||||
{
|
||||
$sounds = new SoundList(array(['id', array_keys($em)]));
|
||||
if (!$sounds->error)
|
||||
{
|
||||
$this->extendGlobalData($sounds->getJSGlobals(GLOBALINFO_SELF));
|
||||
$data = $sounds->getListviewData();
|
||||
foreach($data as $id => &$d)
|
||||
{
|
||||
$d['races'] = $em[$id]['raceMask'];
|
||||
$d['gender'] = $em[$id]['gender'];
|
||||
}
|
||||
|
||||
$this->lvTabs[] = ['sound', array(
|
||||
'data' => array_values($data),
|
||||
// gender races
|
||||
'extraCols' => ['$Listview.templates.title.columns[1]', '$Listview.templates.classs.columns[1]']
|
||||
)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 100: Emotes g_initPath()
|
||||
// tabid 0: Database g_initHeader()
|
||||
class EmotesPage extends GenericPage
|
||||
{
|
||||
use TrListPage;
|
||||
|
||||
protected $type = Type::EMOTE;
|
||||
protected $tpl = 'list-page-generic';
|
||||
protected $path = [0, 100];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
$this->name = Util::ucFirst(Lang::game('emotes'));
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$tabData = array(
|
||||
'data' => array_values((new EmoteList())->getListviewData()),
|
||||
'name' => Util::ucFirst(Lang::game('emotes'))
|
||||
);
|
||||
|
||||
$this->lvTabs[] = ['emote', $tabData, 'emote'];
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
array_unshift($this->title, $this->name);
|
||||
}
|
||||
|
||||
protected function generatePath() { }
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,324 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 101: Enchantment g_initPath()
|
||||
// tabId 0: Database g_initHeader()
|
||||
class EnchantmentPage extends GenericPage
|
||||
{
|
||||
use TrDetailPage;
|
||||
|
||||
protected $type = Type::ENCHANTMENT;
|
||||
protected $typeId = 0;
|
||||
protected $tpl = 'enchantment';
|
||||
protected $path = [0, 101];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
|
||||
public function __construct($pageCall, $id)
|
||||
{
|
||||
parent::__construct($pageCall, $id);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
|
||||
$this->subject = new EnchantmentList(array(['id', $this->typeId]));
|
||||
if ($this->subject->error)
|
||||
$this->notFound(Lang::game('enchantment'), Lang::enchantment('notFound'));
|
||||
|
||||
$this->extendGlobalData($this->subject->getJSGlobals());
|
||||
|
||||
$this->name = Util::ucFirst($this->subject->getField('name', true));
|
||||
}
|
||||
|
||||
private function getDistinctType()
|
||||
{
|
||||
$type = 0;
|
||||
for ($i = 1; $i < 4; $i++)
|
||||
{
|
||||
if ($_ = $this->subject->getField('type'.$i))
|
||||
{
|
||||
if ($type) // already set
|
||||
return 0;
|
||||
else
|
||||
$type = $_;
|
||||
}
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
/***********/
|
||||
/* Infobox */
|
||||
/***********/
|
||||
|
||||
$infobox = Lang::getInfoBoxForFlags($this->subject->getField('cuFlags'));
|
||||
|
||||
// reqLevel
|
||||
if ($_ = $this->subject->getField('requiredLevel'))
|
||||
$infobox[] = sprintf(Lang::game('reqLevel'), $_);
|
||||
|
||||
// reqskill
|
||||
if ($_ = $this->subject->getField('skillLine'))
|
||||
{
|
||||
$this->extendGlobalIds(Type::SKILL, $_);
|
||||
|
||||
$foo = sprintf(Lang::game('requires'), ' [skill='.$_.']');
|
||||
if ($_ = $this->subject->getField('skillLevel'))
|
||||
$foo .= ' ('.$_.')';
|
||||
|
||||
$infobox[] = $foo;
|
||||
}
|
||||
|
||||
|
||||
/****************/
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
|
||||
$this->infobox = $infobox ? '[ul][li]'.implode('[/li][li]', $infobox).'[/li][/ul]' : null;
|
||||
$this->redButtons = array(
|
||||
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId],
|
||||
BUTTON_WOWHEAD => false
|
||||
);
|
||||
|
||||
$this->effects = [];
|
||||
// 3 effects
|
||||
for ($i = 1; $i < 4; $i++)
|
||||
{
|
||||
$_ty = $this->subject->getField('type'.$i);
|
||||
$_qty = $this->subject->getField('amount'.$i);
|
||||
$_obj = $this->subject->getField('object'.$i);
|
||||
|
||||
switch ($_ty)
|
||||
{
|
||||
case 1:
|
||||
case 3:
|
||||
case 7:
|
||||
$sArr = $this->subject->getField('spells')[$i];
|
||||
$spl = $this->subject->getRelSpell($sArr[0]);
|
||||
$this->effects[$i]['name'] = User::isInGroup(U_GROUP_EMPLOYEE) ? sprintf(Util::$dfnString, 'Type: '.$_ty, Lang::item('trigger', $sArr[1])) : Lang::item('trigger', $sArr[1]);
|
||||
$this->effects[$i]['proc'] = $sArr[3];
|
||||
$this->effects[$i]['value'] = $_qty ?: null;
|
||||
$this->effects[$i]['icon'] = array(
|
||||
'name' => !$spl ? Util::ucFirst(Lang::game('spell')).' #'.$sArr[0] : Util::localizedString($spl, 'name'),
|
||||
'id' => $sArr[0],
|
||||
'count' => $sArr[2]
|
||||
);
|
||||
break;
|
||||
case 5:
|
||||
if ($_obj < 2) // [mana, health] are on [0, 1] respectively and are expected on [1, 2] ..
|
||||
$_obj++; // 0 is weaponDmg .. ehh .. i messed up somewhere
|
||||
|
||||
$this->effects[$i]['tip'] = [$_obj, Game::$itemMods[$_obj]];
|
||||
// DO NOT BREAK!
|
||||
case 2:
|
||||
case 6:
|
||||
case 8:
|
||||
case 4:
|
||||
$this->effects[$i]['name'] = User::isInGroup(U_GROUP_EMPLOYEE) ? sprintf(Util::$dfnString, 'Type: '.$_ty, Lang::enchantment('types', $_ty)) : Lang::enchantment('types', $_ty);
|
||||
$this->effects[$i]['value'] = $_qty;
|
||||
if ($_ty == 4)
|
||||
$this->effects[$i]['name'] .= Lang::main('colon').'('.(User::isInGroup(U_GROUP_EMPLOYEE) ? sprintf(Util::$dfnString, 'Object: '.$_obj, Lang::getMagicSchools(1 << $_obj)) : Lang::getMagicSchools(1 << $_obj)).')';
|
||||
}
|
||||
}
|
||||
|
||||
// activation conditions
|
||||
if ($_ = $this->subject->getField('conditionId'))
|
||||
{
|
||||
$x = '';
|
||||
|
||||
if ($gemCnd = DB::Aowow()->selectRow('SELECT * FROM ?_itemenchantmentcondition WHERE id = ?d', $_))
|
||||
{
|
||||
for ($i = 1; $i < 6; $i++)
|
||||
{
|
||||
if (!$gemCnd['color'.$i])
|
||||
continue;
|
||||
|
||||
$fiColors = function ($idx)
|
||||
{
|
||||
$foo = '';
|
||||
switch ($idx)
|
||||
{
|
||||
case 2: $foo = '0:3:5'; break; // red
|
||||
case 3: $foo = '2:4:5'; break; // yellow
|
||||
case 4: $foo = '1:3:4'; break; // blue
|
||||
}
|
||||
|
||||
return $foo;
|
||||
};
|
||||
|
||||
$bLink = $gemCnd['color'.$i] ? '<a class="tip" href="?items=3&filter=ty='.$fiColors($gemCnd['color'.$i]).'">'.Lang::item('gemColors', $gemCnd['color'.$i] - 1).'</a>' : '';
|
||||
$cLink = $gemCnd['cmpColor'.$i] ? '<a class="tip" href="?items=3&filter=ty='.$fiColors($gemCnd['cmpColor'.$i]).'">'.Lang::item('gemColors', $gemCnd['cmpColor'.$i] - 1).'</a>' : '';
|
||||
|
||||
switch ($gemCnd['comparator'.$i])
|
||||
{
|
||||
case 2: // requires less <color> than (<value> || <comparecolor>) gems
|
||||
case 5: // requires at least <color> than (<value> || <comparecolor>) gems
|
||||
$sp = (int)$gemCnd['value'.$i] > 1;
|
||||
$x .= '<span class="q0">'.Lang::achievement('reqNumCrt').' '.Lang::item('gemConditions', $gemCnd['comparator'.$i], [$gemCnd['value'.$i], $bLink]).'</span><br />';
|
||||
break;
|
||||
case 3: // requires more <color> than (<value> || <comparecolor>) gems
|
||||
$link = '<a href="?items=3&filter=ty='.$fiColors($gemCnd['cmpColor'.$i]).'">'.Lang::item('gemColors', $gemCnd['cmpColor'.$i] - 1).'</a>';
|
||||
$x .= '<span class="q0">'.Lang::achievement('reqNumCrt').' '.Lang::item('gemConditions', $gemCnd['comparator'.$i], [$bLink, $cLink]).'</span><br />';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->activateCondition = $x;
|
||||
}
|
||||
|
||||
/**************/
|
||||
/* Extra Tabs */
|
||||
/**************/
|
||||
|
||||
// used by gem
|
||||
$gemList = new ItemList(array(['gemEnchantmentId', $this->typeId]));
|
||||
if (!$gemList->error)
|
||||
{
|
||||
$this->lvTabs[] = ['item', array(
|
||||
'data' => array_values($gemList->getListviewData()),
|
||||
'name' => '$LANG.tab_usedby + \' \' + LANG.gems',
|
||||
'id' => 'used-by-gem',
|
||||
)];
|
||||
|
||||
$this->extendGlobalData($gemList->getJsGlobals());
|
||||
}
|
||||
|
||||
// used by socket bonus
|
||||
$socketsList = new ItemList(array(['socketBonus', $this->typeId]));
|
||||
if (!$socketsList->error)
|
||||
{
|
||||
$this->lvTabs[] = ['item', array(
|
||||
'data' => array_values($socketsList->getListviewData()),
|
||||
'name' => '$LANG.tab_socketbonus',
|
||||
'id' => 'used-by-socketbonus',
|
||||
)];
|
||||
|
||||
$this->extendGlobalData($socketsList->getJsGlobals());
|
||||
}
|
||||
|
||||
// used by spell
|
||||
// used by useItem
|
||||
$cnd = array(
|
||||
'OR',
|
||||
['AND', ['effect1Id', [53, 54, 156, 92]], ['effect1MiscValue', $this->typeId]],
|
||||
['AND', ['effect2Id', [53, 54, 156, 92]], ['effect2MiscValue', $this->typeId]],
|
||||
['AND', ['effect3Id', [53, 54, 156, 92]], ['effect3MiscValue', $this->typeId]],
|
||||
);
|
||||
$spellList = new SpellList($cnd);
|
||||
if (!$spellList->error)
|
||||
{
|
||||
$spellData = $spellList->getListviewData();
|
||||
$this->extendGlobalData($spellList->getJsGlobals());
|
||||
|
||||
$spellIds = $spellList->getFoundIDs();
|
||||
$conditions = array(
|
||||
'OR', // [use, useUndelayed]
|
||||
['AND', ['spellTrigger1', [0, 5]], ['spellId1', $spellIds]],
|
||||
['AND', ['spellTrigger2', [0, 5]], ['spellId2', $spellIds]],
|
||||
['AND', ['spellTrigger3', [0, 5]], ['spellId3', $spellIds]],
|
||||
['AND', ['spellTrigger4', [0, 5]], ['spellId4', $spellIds]],
|
||||
['AND', ['spellTrigger5', [0, 5]], ['spellId5', $spellIds]]
|
||||
);
|
||||
|
||||
$ubItems = new ItemList($conditions);
|
||||
if (!$ubItems->error)
|
||||
{
|
||||
$this->lvTabs[] = ['item', array(
|
||||
'data' => array_values($ubItems->getListviewData()),
|
||||
'name' => '$LANG.tab_usedby + \' \' + LANG.types[3][0]',
|
||||
'id' => 'used-by-item',
|
||||
)];
|
||||
|
||||
$this->extendGlobalData($ubItems->getJSGlobals(GLOBALINFO_SELF));
|
||||
}
|
||||
|
||||
// remove found spells if they are used by an item
|
||||
if (!$ubItems->error)
|
||||
{
|
||||
foreach ($spellList->iterate() as $sId => $__)
|
||||
{
|
||||
// if Perm. Enchantment has a createItem its a Scroll of Enchantment (display both)
|
||||
for ($i = 1; $i < 4; $i++)
|
||||
if ($spellList->getField('effect'.$i.'Id') == 53 && $spellList->getField('effect'.$i.'CreateItemId'))
|
||||
continue 2;
|
||||
|
||||
foreach ($ubItems->iterate() as $__)
|
||||
{
|
||||
for ($i = 1; $i < 6; $i++)
|
||||
{
|
||||
if ($ubItems->getField('spellId'.$i) == $sId)
|
||||
{
|
||||
unset($spellData[$sId]);
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->lvTabs[] = ['spell', array(
|
||||
'data' => array_values($spellData),
|
||||
'name' => '$LANG.tab_usedby + \' \' + LANG.types[6][0]',
|
||||
'id' => 'used-by-spell',
|
||||
)];
|
||||
}
|
||||
|
||||
// used by randomAttrItem
|
||||
$ire = DB::Aowow()->select(
|
||||
'SELECT *, ABS(id) AS ARRAY_KEY FROM ?_itemrandomenchant WHERE enchantId1 = ?d OR enchantId2 = ?d OR enchantId3 = ?d OR enchantId4 = ?d OR enchantId5 = ?d',
|
||||
$this->typeId, $this->typeId, $this->typeId, $this->typeId, $this->typeId
|
||||
);
|
||||
if ($ire)
|
||||
{
|
||||
if ($iet = DB::World()->select('SELECT entry AS ARRAY_KEY, ench, chance FROM item_enchantment_template WHERE ench IN (?a)', array_keys($ire)))
|
||||
{
|
||||
$randIds = []; // transform back to signed format
|
||||
foreach ($iet as $tplId => $data)
|
||||
$randIds[$ire[$data['ench']]['id'] > 0 ? $tplId : -$tplId] = $ire[$data['ench']]['id'];
|
||||
|
||||
$randItems = new ItemList(array(CFG_SQL_LIMIT_NONE, ['randomEnchant', array_keys($randIds)]));
|
||||
if (!$randItems->error)
|
||||
{
|
||||
$data = $randItems->getListviewData();
|
||||
foreach ($randItems->iterate() as $iId => $__)
|
||||
{
|
||||
$re = $randItems->getField('randomEnchant');
|
||||
|
||||
$data[$iId]['percent'] = $iet[abs($re)]['chance'];
|
||||
$data[$iId]['count'] = 1; // expected by js or the pct-col becomes unsortable
|
||||
$data[$iId]['rel'] = 'rand='.$ire[$iet[abs($re)]['ench']]['id'];
|
||||
$data[$iId]['name'] .= ' '.Util::localizedString($ire[$iet[abs($re)]['ench']], 'name');
|
||||
}
|
||||
|
||||
$this->lvTabs[] = ['item', array(
|
||||
'data' => array_values($data),
|
||||
'id' => 'used-by-rand',
|
||||
'name' => '$LANG.tab_usedby + \' \' + \''.Lang::item('_rndEnchants').'\'',
|
||||
'extraCols' => ['$Listview.extraCols.percent']
|
||||
)];
|
||||
|
||||
$this->extendGlobalData($randItems->getJSGlobals(GLOBALINFO_SELF));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
array_unshift($this->title, $this->name, Util::ucFirst(Lang::game('enchantment')));
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
{
|
||||
if ($_ = $this->getDistinctType())
|
||||
$this->path[] = $_;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,110 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 101: Enchantment g_initPath()
|
||||
// tabId 0: Database g_initHeader()
|
||||
class EnchantmentsPage extends GenericPage
|
||||
{
|
||||
use TrListPage;
|
||||
|
||||
protected $type = Type::ENCHANTMENT;
|
||||
protected $tpl = 'enchantments';
|
||||
protected $path = [0, 101];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
protected $js = [[JS_FILE, 'filters.js']];
|
||||
|
||||
protected $_get = ['filter' => ['filter' => FILTER_UNSAFE_RAW]];
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
$this->getCategoryFromUrl($pageParam);;
|
||||
$this->filterObj = new EnchantmentListFilter(false, ['parentCats' => $this->category]);
|
||||
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
$this->name = Util::ucFirst(Lang::game('enchantments'));
|
||||
$this->subCat = $pageParam !== '' ? '='.$pageParam : '';
|
||||
}
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$tabData = array(
|
||||
'data' => [],
|
||||
'name' => Util::ucFirst(Lang::game('enchantments'))
|
||||
);
|
||||
|
||||
$conditions = [];
|
||||
|
||||
if (!User::isInGroup(U_GROUP_EMPLOYEE))
|
||||
$conditions[] = [['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0];
|
||||
|
||||
if ($_ = $this->filterObj->getConditions())
|
||||
$conditions[] = $_;
|
||||
|
||||
$ench = new EnchantmentList($conditions);
|
||||
|
||||
$tabData['data'] = array_values($ench->getListviewData());
|
||||
$this->extendGlobalData($ench->getJSGlobals());
|
||||
|
||||
// recreate form selection
|
||||
$this->filter = $this->filterObj->getForm();
|
||||
$this->filter['query'] = $this->_get['filter'];
|
||||
$this->filter['initData'] = ['init' => 'enchantments'];
|
||||
|
||||
if ($x = $this->filterObj->getSetCriteria())
|
||||
$this->filter['initData']['sc'] = $x;
|
||||
|
||||
$xCols = $this->filterObj->getExtraCols();
|
||||
foreach (Util::$itemFilter as $fiId => $str)
|
||||
if (array_column($tabData['data'], $str))
|
||||
$xCols[] = $fiId;
|
||||
|
||||
if (array_column($tabData['data'], 'dmg'))
|
||||
$xCols[] = 34;
|
||||
|
||||
if ($xCols)
|
||||
$this->filter['initData']['ec'] = array_values(array_unique($xCols));
|
||||
|
||||
if ($xCols)
|
||||
$tabData['extraCols'] = '$fi_getExtraCols(fi_extraCols, 0, 0)';
|
||||
|
||||
if ($ench->getMatches() > CFG_SQL_LIMIT_DEFAULT)
|
||||
{
|
||||
$tabData['note'] = sprintf(Util::$tryFilteringString, 'LANG.lvnote_enchantmentsfound', $ench->getMatches(), CFG_SQL_LIMIT_DEFAULT);
|
||||
$tabData['_truncated'] = 1;
|
||||
}
|
||||
|
||||
if (array_filter(array_column($tabData['data'], 'spells')))
|
||||
$tabData['visibleCols'] = ['trigger'];
|
||||
|
||||
if (!$ench->hasSetFields(['skillLine']))
|
||||
$tabData['hiddenCols'] = ['skill'];
|
||||
|
||||
if ($this->filterObj->error)
|
||||
$tabData['_errors'] = '$1';
|
||||
|
||||
$this->lvTabs[] = ['enchantment', $tabData, 'enchantment'];
|
||||
}
|
||||
|
||||
protected function generateTitle()
|
||||
{
|
||||
$form = $this->filterObj->getForm('form');
|
||||
if (!empty($form['ty']) && intVal($form['ty']) && $form['ty'] > 0 && $form['ty'] < 9)
|
||||
array_unshift($this->title, Lang::enchantment('types', $form['ty']));
|
||||
|
||||
array_unshift($this->title, $this->name);
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
{
|
||||
$form = $this->filterObj->getForm('form');
|
||||
if (isset($form['ty']) && count($form['ty']) == 1)
|
||||
$this->path[] = $form['ty'][0];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
179
pages/event.php
179
pages/event.php
@@ -4,22 +4,19 @@ if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// menuId 11: Worldevent g_initPath()
|
||||
// menuId 11: Object g_initPath()
|
||||
// tabId 0: Database g_initHeader()
|
||||
class EventPage extends GenericPage
|
||||
{
|
||||
use TrDetailPage;
|
||||
use DetailPage;
|
||||
|
||||
protected $type = Type::WORLDEVENT;
|
||||
protected $type = TYPE_WORLDEVENT;
|
||||
protected $typeId = 0;
|
||||
protected $tpl = 'detail-page-generic';
|
||||
protected $path = [0, 11];
|
||||
protected $tabId = 0;
|
||||
protected $mode = CACHE_TYPE_PAGE;
|
||||
|
||||
protected $_get = ['domain' => ['filter' => FILTER_CALLBACK, 'options' => 'GenericPage::checkDomain']];
|
||||
|
||||
private $powerTpl = '$WowheadPower.registerHoliday(%d, %d, %s);';
|
||||
private $hId = 0;
|
||||
private $eId = 0;
|
||||
|
||||
@@ -27,25 +24,22 @@ class EventPage extends GenericPage
|
||||
{
|
||||
parent::__construct($pageCall, $id);
|
||||
|
||||
// temp locale
|
||||
if ($this->mode == CACHE_TYPE_TOOLTIP && $this->_get['domain'])
|
||||
Util::powerUseLocale($this->_get['domain']);
|
||||
|
||||
$this->typeId = intVal($id);
|
||||
|
||||
$this->subject = new WorldEventList(array(['id', $this->typeId]));
|
||||
$conditions = $this->typeId < 0 ? [['id', -$this->typeId]] : [['holidayId', $this->typeId]];
|
||||
|
||||
$this->subject = new WorldEventList($conditions);
|
||||
if ($this->subject->error)
|
||||
$this->notFound(Lang::game('event'), Lang::event('notFound'));
|
||||
|
||||
$this->hId = $this->subject->getField('holidayId');
|
||||
$this->eId = $this->typeId;
|
||||
$this->eId = $this->subject->getField('eventBak');
|
||||
|
||||
// redirect if associated with a holiday
|
||||
if ($this->hId && $this->typeId != $this->hId)
|
||||
header('Location: '.HOST_URL.'?event='.$this->hId, true, 302);
|
||||
|
||||
$this->name = $this->subject->getField('name', true);
|
||||
$this->dates = array(
|
||||
'firstDate' => $this->subject->getField('startTime'),
|
||||
'lastDate' => $this->subject->getField('endTime'),
|
||||
'length' => $this->subject->getField('length'),
|
||||
'rec' => $this->subject->getField('occurence')
|
||||
);
|
||||
}
|
||||
|
||||
protected function generatePath()
|
||||
@@ -67,7 +61,7 @@ class EventPage extends GenericPage
|
||||
|
||||
protected function generateContent()
|
||||
{
|
||||
$this->addScript([JS_FILE, '?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']]);
|
||||
$this->addJS('?data=zones&locale='.User::$localeId.'&t='.$_SESSION['dataKey']);
|
||||
|
||||
/***********/
|
||||
/* Infobox */
|
||||
@@ -78,7 +72,7 @@ class EventPage extends GenericPage
|
||||
// boss
|
||||
if ($_ = $this->subject->getField('bossCreature'))
|
||||
{
|
||||
$this->extendGlobalIds(Type::NPC, $_);
|
||||
$this->extendGlobalIds(TYPE_NPC, $_);
|
||||
$this->infobox[] = Lang::npc('rank', 3).Lang::main('colon').'[npc='.$_.']';
|
||||
}
|
||||
|
||||
@@ -90,14 +84,16 @@ class EventPage extends GenericPage
|
||||
/* Main Content */
|
||||
/****************/
|
||||
|
||||
// no entry in ?_articles? use default HolidayDescription
|
||||
if ($this->hId && empty($this->article))
|
||||
$this->article = ['text' => Util::jsEscape($this->subject->getField('description', true)), 'params' => []];
|
||||
|
||||
$this->headIcons = [$this->subject->getField('iconString')];
|
||||
$this->redButtons = array(
|
||||
BUTTON_WOWHEAD => $this->hId > 0,
|
||||
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId]
|
||||
BUTTON_WOWHEAD => $this->typeId > 0,
|
||||
BUTTON_LINKS => true
|
||||
);
|
||||
$this->dates = array(
|
||||
'firstDate' => $this->subject->getField('startTime'),
|
||||
'lastDate' => $this->subject->getField('endTime'),
|
||||
'length' => $this->subject->getField('length'),
|
||||
'rec' => $this->subject->getField('occurence')
|
||||
);
|
||||
|
||||
/**************/
|
||||
@@ -116,12 +112,11 @@ class EventPage extends GenericPage
|
||||
foreach ($data as &$d)
|
||||
$d['method'] = $npcIds[$d['id']];
|
||||
|
||||
$tabData = ['data' => array_values($data)];
|
||||
|
||||
if ($hasFilter)
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?npcs&filter=cr=38;crs='.$this->hId.';crv=0');
|
||||
|
||||
$this->lvTabs[] = ['creature', $tabData];
|
||||
$this->lvTabs[] = array(
|
||||
'file' => CreatureList::$brickFile,
|
||||
'data' => $data,
|
||||
'params' => ['note' => $hasFilter ? sprintf(Util::$filterResultString, '?npcs&filter=cr=38;crs='.$this->hId.';crv=0') : null]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,12 +130,11 @@ class EventPage extends GenericPage
|
||||
foreach ($data as &$d)
|
||||
$d['method'] = $objectIds[$d['id']];
|
||||
|
||||
$tabData = ['data' => array_values($data)];
|
||||
|
||||
if ($hasFilter)
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?objects&filter=cr=16;crs='.$this->hId.';crv=0');
|
||||
|
||||
$this->lvTabs[] = ['object', $tabData];
|
||||
$this->lvTabs[] = array(
|
||||
'file' => GameObjectList::$brickFile,
|
||||
'data' => $data,
|
||||
'params' => ['note' => $hasFilter ? sprintf(Util::$filterResultString, '?objects&filter=cr=16;crs='.$this->hId.';crv=0') : null]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,15 +147,14 @@ class EventPage extends GenericPage
|
||||
{
|
||||
$this->extendGlobalData($acvs->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED));
|
||||
|
||||
$tabData = array(
|
||||
'data' => array_values($acvs->getListviewData()),
|
||||
'visibleCols' => ['category']
|
||||
$this->lvTabs[] = array(
|
||||
'file' => AchievementList::$brickFile,
|
||||
'data' => $acvs->getListviewData(),
|
||||
'params' => array(
|
||||
'note' => $hasFilter ? sprintf(Util::$filterResultString, '?achievements&filter=cr=11;crs='.$this->hId.';crv=0') : null,
|
||||
'visibleCols' => "$['category']"
|
||||
)
|
||||
);
|
||||
|
||||
if ($hasFilter)
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?achievements&filter=cr=11;crs='.$this->hId.';crv=0');
|
||||
|
||||
$this->lvTabs[] = ['achievement', $tabData];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,27 +163,26 @@ class EventPage extends GenericPage
|
||||
{
|
||||
$itemCnd = array(
|
||||
'OR',
|
||||
['eventId', $this->eId], // direct requirement on item
|
||||
['holidayId', $this->hId], // direct requirement on item
|
||||
);
|
||||
|
||||
// tab: quests (by table, go & creature)
|
||||
$quests = new QuestList(array(['eventId', $this->eId]));
|
||||
$quests = new QuestList(array(['holidayId', $this->hId]));
|
||||
if (!$quests->error)
|
||||
{
|
||||
$this->extendGlobalData($quests->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_REWARDS));
|
||||
|
||||
$tabData = ['data'=> array_values($quests->getListviewData())];
|
||||
|
||||
if ($hasFilter)
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?quests&filter=cr=33;crs='.$this->hId.';crv=0');
|
||||
|
||||
$this->lvTabs[] = ['quest', $tabData];
|
||||
$this->lvTabs[] = array(
|
||||
'file' => QuestList::$brickFile,
|
||||
'data' => $quests->getListviewData(),
|
||||
'params' => ['note' => $hasFilter ? sprintf(Util::$filterResultString, '?quests&filter=cr=33;crs='.$this->hId.';crv=0') : null]
|
||||
);
|
||||
|
||||
$questItems = [];
|
||||
foreach (array_column($quests->rewards, Type::ITEM) as $arr)
|
||||
foreach (array_column($quests->rewards, TYPE_ITEM) as $arr)
|
||||
$questItems = array_merge($questItems, $arr);
|
||||
|
||||
foreach (array_column($quests->requires, Type::ITEM) as $arr)
|
||||
foreach (array_column($quests->requires, TYPE_ITEM) as $arr)
|
||||
$questItems = array_merge($questItems, $arr);
|
||||
|
||||
if ($questItems)
|
||||
@@ -216,24 +208,23 @@ class EventPage extends GenericPage
|
||||
{
|
||||
$this->extendGlobalData($eventItems->getJSGlobals(GLOBALINFO_SELF));
|
||||
|
||||
$tabData = ['data'=> array_values($eventItems->getListviewData())];
|
||||
|
||||
if ($hasFilter)
|
||||
$tabData['note'] = sprintf(Util::$filterResultString, '?items&filter=cr=160;crs='.$this->hId.';crv=0');
|
||||
|
||||
$this->lvTabs[] = ['item', $tabData];
|
||||
$this->lvTabs[] = array(
|
||||
'file' => ItemList::$brickFile,
|
||||
'data' => $eventItems->getListviewData(),
|
||||
'params' => ['note' => $hasFilter ? sprintf(Util::$filterResultString, '?items&filter=cr=160;crs='.$this->hId.';crv=0') : null]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tab: see also (event conditions)
|
||||
if ($rel = DB::World()->selectCol('SELECT IF(eventEntry = prerequisite_event, NULL, IF(eventEntry = ?d, prerequisite_event, -eventEntry)) FROM game_event_prerequisite WHERE prerequisite_event = ?d OR eventEntry = ?d', $this->eId, $this->eId, $this->eId))
|
||||
if ($rel = DB::World()->selectCol('SELECT IF(eventEntry = prerequisite_event, NULL, IF(eventEntry = ?d, -prerequisite_event, eventEntry)) FROM game_event_prerequisite WHERE prerequisite_event = ?d OR eventEntry = ?d', $this->eId, $this->eId, $this->eId))
|
||||
{
|
||||
$list = [];
|
||||
array_walk($rel, function($v, $k) use (&$list) {
|
||||
if ($v > 0)
|
||||
$list[] = $v;
|
||||
else if ($v === null)
|
||||
trigger_error('game_event_prerequisite: this event has itself as prerequisite', E_USER_WARNING);
|
||||
Util::addNote(U_GROUP_EMPLOYEE, 'game_event_prerequisite: this event has itself as prerequisite');
|
||||
});
|
||||
|
||||
if ($list)
|
||||
@@ -242,70 +233,45 @@ class EventPage extends GenericPage
|
||||
$this->extendGlobalData($relEvents->getJSGlobals());
|
||||
$relData = $relEvents->getListviewData();
|
||||
foreach ($relEvents->getFoundIDs() as $id)
|
||||
$relData[$id]['condition'][0][$this->typeId][] = [[-CND_ACTIVE_EVENT, $this->eId]];
|
||||
$relData[$id]['condition'][0][$this->typeId][] = [[-CND_ACTIVE_EVENT, -$this->eId]];
|
||||
|
||||
$this->extendGlobalData($this->subject->getJSGlobals());
|
||||
foreach ($rel as $r)
|
||||
{
|
||||
if ($r <= 0)
|
||||
if ($r >= 0)
|
||||
continue;
|
||||
|
||||
$this->extendGlobalIds(Type::WORLDEVENT, $r);
|
||||
$this->extendGlobalIds(TYPE_WORLDEVENT, $r);
|
||||
|
||||
$d = $this->subject->getListviewData();
|
||||
$d[$this->eId]['condition'][0][$this->typeId][] = [[-CND_ACTIVE_EVENT, $r]];
|
||||
$d[-$this->eId]['condition'][0][$this->typeId][] = [[-CND_ACTIVE_EVENT, $r]];
|
||||
|
||||
$relData = array_merge($relData, $d);
|
||||
}
|
||||
|
||||
$this->lvTabs[] = ['event', array(
|
||||
'data' => array_values($relData),
|
||||
$this->lvTabs[] = array(
|
||||
'file' => WorldEventList::$brickFile,
|
||||
'data' => $relData,
|
||||
'params' => array(
|
||||
'id' => 'see-also',
|
||||
'name' => '$LANG.tab_seealso',
|
||||
'hiddenCols' => ['date'],
|
||||
'extraCols' => ['$Listview.extraCols.condition']
|
||||
)];
|
||||
'hiddenCols' => "$['date']",
|
||||
'extraCols' => '$[Listview.extraCols.condition]'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function generateTooltip() : string
|
||||
{
|
||||
$power = new StdClass();
|
||||
if (!$this->subject->error)
|
||||
{
|
||||
$power->{'name_'.User::$localeString} = $this->subject->getField('name', true);
|
||||
|
||||
if ($this->subject->getField('iconString') != 'trade_engineering')
|
||||
$power->icon = rawurlencode($this->subject->getField('iconString', true, true));
|
||||
|
||||
$power->{'tooltip_'.User::$localeString} = $this->subject->renderTooltip();
|
||||
}
|
||||
|
||||
return sprintf($this->powerTpl, $this->typeId, User::$localeId, Util::toJSON($power, JSON_AOWOW_POWER));
|
||||
}
|
||||
|
||||
protected function postCache()
|
||||
{
|
||||
// update dates to now()
|
||||
$updated = WorldEventList::updateDates($this->dates);
|
||||
|
||||
if ($this->mode == CACHE_TYPE_TOOLTIP)
|
||||
{
|
||||
return array(
|
||||
date(Lang::main('dateFmtLong'), $updated['start']),
|
||||
date(Lang::main('dateFmtLong'), $updated['end'])
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->hId)
|
||||
Util::$wowheadLink = 'http://'.Util::$subDomains[User::$localeId].'.wowhead.com/event='.$this->hId;
|
||||
|
||||
/********************/
|
||||
/* finalize infobox */
|
||||
/********************/
|
||||
|
||||
// update dates to now()
|
||||
$updated = WorldEventList::updateDates($this->dates);
|
||||
|
||||
// start
|
||||
if ($updated['start'])
|
||||
array_push($this->infobox, Lang::event('start').Lang::main('colon').date(Lang::main('dateFmtLong'), $updated['start']));
|
||||
@@ -330,10 +296,10 @@ class EventPage extends GenericPage
|
||||
|
||||
foreach ($this->lvTabs as &$view)
|
||||
{
|
||||
if ($view[0] != WorldEventList::$brickFile)
|
||||
if ($view['file'] != WorldEventList::$brickFile)
|
||||
continue;
|
||||
|
||||
foreach ($view[1]['data'] as &$data)
|
||||
foreach ($view['data'] as &$data)
|
||||
{
|
||||
$updated = WorldEventList::updateDates($data['_date']);
|
||||
unset($data['_date']);
|
||||
@@ -345,6 +311,5 @@ class EventPage extends GenericPage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -8,9 +8,9 @@ if (!defined('AOWOW_REVISION'))
|
||||
// tabId 0: Database g_initHeader()
|
||||
class EventsPage extends GenericPage
|
||||
{
|
||||
use TrListPage;
|
||||
use ListPage;
|
||||
|
||||
protected $type = Type::WORLDEVENT;
|
||||
protected $type = TYPE_WORLDEVENT;
|
||||
protected $tpl = 'list-page-generic';
|
||||
protected $path = [0, 11];
|
||||
protected $tabId = 0;
|
||||
@@ -52,16 +52,19 @@ class EventsPage extends GenericPage
|
||||
if ($d = $events->getField('requires'))
|
||||
$this->deps[$events->id] = $d;
|
||||
|
||||
$data = array_values($events->getListviewData());
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'event',
|
||||
'data' => $events->getListviewData(),
|
||||
'params' => []
|
||||
);
|
||||
|
||||
$this->lvTabs[] = ['event', ['data' => $data]];
|
||||
|
||||
if ($_ = array_values(array_filter($data, function($x) {return $x['category'] > 0;})))
|
||||
if ($_ = array_filter($events->getListviewData(), function($x) {return $x['id'] > 0;}))
|
||||
{
|
||||
$this->lvTabs[] = ['calendar', array(
|
||||
$this->lvTabs[] = array(
|
||||
'file' => 'calendar',
|
||||
'data' => $_,
|
||||
'hideCount' => 1
|
||||
)];
|
||||
'params' => ['hideCount' => 1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +86,7 @@ class EventsPage extends GenericPage
|
||||
// recalculate dates with now()
|
||||
foreach ($this->lvTabs as &$views)
|
||||
{
|
||||
foreach ($views[1]['data'] as &$data)
|
||||
foreach ($views['data'] as &$data)
|
||||
{
|
||||
// is a followUp-event
|
||||
if (!empty($this->deps[$data['id']]))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user