diff --git a/config/extAuth.php.in b/config/extAuth.php.in index 1181c946..5be443b9 100644 --- a/config/extAuth.php.in +++ b/config/extAuth.php.in @@ -16,4 +16,4 @@ if (!defined('AOWOW_REVISION')) return AUTH_INTERNAL_ERR; } -?> \ No newline at end of file +?> diff --git a/includes/ajaxHandler.class.php b/includes/ajaxHandler.class.php index 1463d15a..38e4a665 100644 --- a/includes/ajaxHandler.class.php +++ b/includes/ajaxHandler.class.php @@ -33,21 +33,6 @@ class AjaxHandler return $this->$f(); } - private function isLoadOnDemand() - { - return substr(@$this->get['callback'], 0, 29) == '$WowheadProfiler.loadOnDemand'; - } - - private function loadProfilerData($file, $catg = 'null') - { - $result = ''; - if ($this->isLoadOnDemand()) - if (Util::loadStaticFile('p-'.$file, $result, true)) - $result .= "\n\$WowheadProfiler.loadOnDemand('".$file."', ".$catg.");\n"; - - return $result; - } - /* responses */ @@ -74,13 +59,13 @@ class AjaxHandler loading the data triggers the generation of the catg-tree */ case 'factions': - $result .= $this->loadProfilerData($set); + $result .= $this->data_loadProfilerData($set); break; case 'companions': - $result .= $this->loadProfilerData($set, '778'); + $result .= $this->data_loadProfilerData($set, '778'); break; case 'mounts': - $result .= $this->loadProfilerData($set, '777'); + $result .= $this->data_loadProfilerData($set, '777'); break; case 'quests': // &partial: im not doing this right @@ -88,13 +73,13 @@ class AjaxHandler // 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->isLoadOnDemand()) + $result .= $this->data_loadProfilerData($set); + else if ($this->data_isLoadOnDemand()) $result .= "\n\$WowheadProfiler.loadOnDemand('quests', ".$catg.");\n"; break; case 'recipes': - if (!$this->isLoadOnDemand() || empty($this->get['skill'])) + if (!$this->data_isLoadOnDemand() || empty($this->get['skill'])) break; $skills = array_intersect(explode(',', $this->get['skill']), [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, 185, 129, 356]); @@ -143,6 +128,46 @@ class AjaxHandler return $result; } + private function handleProfile() + { + if (!$this->params) + return null; + + switch ($this->params[0]) + { + case 'link': + case 'unlink': + $this->profile_handleLink(); // always returns null + return ''; + case 'pin': + case 'unpin': + $this->profile_handlePin(); // always returns null + return ''; + case 'public': + case 'private': + $this->profile_handlePrivacy(); // always returns null + return ''; + case 'avatar': + if ($this->profile_handleAvatar()) // sets an image header + die(); // so it has to die here or another header will be set + case 'resync': + case 'status': + return $this->profile_handleResync($this->params[0] == 'resync'); + case 'save': + return $this->profile_handleSave(); + case 'delete': + return $this->profile_handleDelete(); + case 'purge': + return $this->profile_handlePurge(); + case 'summary': // page is generated by jScript + return ''; // just be empty + case 'load': + return $this->profile_handleLoad(); + default: + return null; + } + } + /* responses 0: success $: silent error @@ -297,6 +322,369 @@ class AjaxHandler return null; } + /**********/ + /* Helper */ + /**********/ + + private function data_isLoadOnDemand() + { + return substr(@$this->get['callback'], 0, 29) == '$WowheadProfiler.loadOnDemand'; + } + + private function data_loadProfilerData($file, $catg = 'null') + { + $result = ''; + if ($this->data_isLoadOnDemand()) + if (Util::loadStaticFile('p-'.$file, $result, true)) + $result .= "\n\$WowheadProfiler.loadOnDemand('".$file."', ".$catg.");\n"; + + return $result; + } + + private function profile_handleAvatar() // image + { + // something happened in the last years: those textures do not include tiny icons + $s = [/* 'tiny' => 15, */'small' => 18, 'medium' => 36, 'large' => 56]; + $size = empty($this->get['size']) ? 'medium' : $this->get['size']; + + if (empty($this->get['id']) || !preg_match('/^([0-9]+)\.(jpg|gif)$/', $this->get['id'], $matches) || !in_array($size, array_keys($s))) + return false; + + $id = $matches[1]; + + if (file_exists(CWD.'/uploads/avatars/'.$id.'.jpg')) + { + $offsetX = $offsetY = 0; + + switch ($size) + { + case 'tiny': + $offsetX += $s['small']; + case 'small': + $offsetY += $s['medium']; + case 'medium': + $offsetX += $s['large']; + } + + $src = imageCreateFromJpeg('uploads/avatars/'.$id.'.jpg'); + $dest = imageCreateTruecolor($s[$size], $s[$size]); + + imagecopymerge($dest, $src, 0, 0, $offsetX, $offsetY, $s[$size], $s[$size], 100); + + header('Content-Type: image/'.$matches[2]); + + if ($matches[2] == 'gif') + imageGif($dest); + else + imageJpeg($dest); + + return true; + } + + return false; + } + + private function profile_handlePin($id, $mode) // (un)favorite + { + /* params + id: + user: [optional] + return: null + */ + } + + private function profile_handleLink($id, $mode) // links char with account + { + /* params + id: + user: [optional] + return: null + */ + } + + private function profile_handlePrivacy($id, $mode) // public visibility + { + /* params + id: + user: [optional] + return: null + */ + } + + private function profile_handleResync($initNew = true) // resync init and status requests + { + /* params + id: + user: [optional] + return + null [onOK] + int or str [onError] + */ + + if ($initNew) + return '1'; + else + { + /* + 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 + + [ + processId, + [StatusCode, timeToRefresh, iCount, errorCode, iNResyncs], + []... + ] + */ + return '[0, [4, 10000, 1, 2]]'; + } + } + + private function profile_handleSave() // unKill a profile + { + /* params GET + id: + params POST + name, level, class, race, gender, nomodel, talenttree1, talenttree2, talenttree3, activespec, talentbuild1, glyphs1, talentbuild2, glyphs2, gearscore, icon, public [always] + description, source, copy, inv { inventory: array containing itemLinks } [optional] + } + return + int > 0 [profileId, if we came from an armoryProfile create a new one] + int < 0 [onError] + str [onError] + */ + + return 'NYI'; + } + + private function profile_handleDelete() // kill a profile + { + /* params + id: + return + null + */ + + return 'NYI'; + } + + private function profile_handlePurge() // removes certain saved information but not the entire character + { + /* params + id: + data: [string, tabName?] + return + null + */ + + return 'NYI'; + } + + private function profile_handleLoad() + { + /* params + id: profileId + items: string [itemIds.join(':')] + unnamed: unixtime [only to force the browser to reload instead of cache] + return + lots... + */ + + // titles, achievements, characterData, talents (, pets) + // and some onLoad-hook to .. load it registerProfile($data) + // everything else goes through data.php .. strangely enough + + $char = new ProfileList(array(['id', $this->get['id']])); // or string or whatever + + // modify model from auras with profile_getModelForForm + + $buff = ''; + + if ($it = array_column($char->getField('inventory'), 0)) + { + $itemz = new ItemList(array(['id', $it, CFG_SQL_LIMIT_NONE])); + $data = $itemz->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS); + + // get and apply inventory + foreach ($itemz->iterate() as $iId => $__) + $buff .= 'g_items.add('.$iId.', {name_'.User::$localeString.":'".Util::jsEscape($itemz->getField('name', true))."', quality:".$itemz->getField('quality').", icon:'".$itemz->getField('iconString')."', jsonequip:".json_encode($data[$iId], JSON_NUMERIC_CHECK)."});\n"; + + $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 = @Util::$itemMods[$k]) + $mods[$str] = $v; + } + } + + $buff .= 'g_spells.add('.$id.", {id:".$id.", name:'".Util::jsEscape(substr($data['name'], 1))."', icon:'".$data['icon']."', modifier:".json_encode($mods, JSON_NUMERIC_CHECK)."});\n"; + } + $buff .= "\n"; + } + + /* depending on progress-achievements + // required by progress in JScript move to handleLoad()? + Util::$pageTemplate->extendGlobalIds(TYPE_NPC, [29120, 31134, 29306, 29311, 23980, 27656, 26861, 26723, 28923, 15991]); + */ + + // load available titles + Util::loadStaticFile('p-titles-'.$char->getField('gender'), $buff, true); + + // load available achievements + if (!Util::loadStaticFile('p-achievements', $buff, true)) + { + $buff .= "\n\ng_achievement_catorder = [];"; + $buff .= "\n\ng_achievement_points = [0];"; + } + + // excludes; structure UNK type => [maskBit => [typeIds]] ? + /* + g_user.excludes = [type:[typeIds]] + g_user.includes = [type:[typeIds]] + g_user.excludegroups = groupMask // requires g_user.settings != null + + maskBit are matched against fieldId from excludeGroups + id: 1, label: LANG.dialog_notavail + id: 2, label: LANG.dialog_tcg + id: 4, label: LANG.dialog_collector + id: 8, label: LANG.dialog_promo + id: 16, label: LANG.dialog_nonus + id: 96, label: LANG.dialog_faction + id: 896, label: LANG.dialog_profession + id: 1024, label: LANG.dialog_noexalted + */ + // $buff .= "\n\ng_excludes = {};"; + + // add profile to buffer + $buff .= "\n\n\$WowheadProfiler.registerProfile(".json_encode($char->getEntry(2)).");"; // can't use JSON_NUMERIC_CHECK or the talent-string becomes a float + + return $buff."\n"; + } + + private function profile_getModelForForm($form, $char) + { + switch ($form) + { + case 1: // FORM_CAT + if ($char['race'] == 4) // RACE_NIGHTELF + { + if ($char['hairColor'] >= 0 && $char['hairColor'] <= 2) + return 29407; + else if ($char['hairColor'] == 3) + return 29406; + else if ($char['hairColor'] == 4) + return 29408; + else if ($char['hairColor'] == 7 || $char['hairColor'] == 8) + return 29405; + else + return 892; + } + + if ($char['race'] == 6) // RACE_TAUREN + { + if ($char['gender'] == GENDER_MALE) + { + if ($char['skinColor'] >= 0 && $char['skinColor'] <= 5) + return 29412; + else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 8) + return 29411; + else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 11) + return 29410; + else if (in_array($char['skinColor'], [12, 13, 14, 18])) + return 29410; + else + return 8571; + } + else // if gender == GENDER_FEMALE + { + if ($char['skinColor'] >= 0 && $char['skinColor'] <= 3) + return 29412; + else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 5) + return 29411; + else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 7) + return 29410; + else if ($char['skinColor'] == 10) + return 29410; + else + return 8571; + } + } + case 5: // FORM_DIREBEAR + case 8: // FORM_BEAR + if ($char['race'] == 4) // RACE_NIGHTELF + { + if ($char['hairColor'] >= 0 && $char['hairColor'] <= 2) + return 29413; + else if ($char['hairColor'] == 3) + return 29417; + else if ($char['hairColor'] == 4) + return 29416; + else if ($char['hairColor'] == 6) + return 29414; + else + return 2281; + } + + if ($char['race'] == 6) // RACE_TAUREN + { + if ($char['gender'] == GENDER_MALE) + { + if ($char['skinColor'] >= 0 && $char['skinColor'] <= 2) + return 29415; + else if (in_array($char['skinColor'], [3, 4, 5, 12, 13, 14])) + return 29419; + else if (in_array($char['skinColor'], [9, 10, 11, 15, 16, 17])) + return 29420; + else if ($char['skinColor'] == 18) + return 29421; + else + return 2289; + } + else // if gender == GENDER_FEMALE + { + if ($char['skinColor'] == 0 && $char['skinColor'] == 1) + return 29418; + else if ($char['skinColor'] == 2 && $char['skinColor'] == 3) + return 29419; + else if ($char['skinColor'] >= 6 && $char['skinColor'] <= 9) + return 29420; + else if ($char['skinColor'] == 10) + return 29421; + else + return 2289; + } + } + } + + // hey, still here? you're not a Tauren/Nelf as bear or cat, are you? + return DB::Aowow()->selectCell('SELECT IF(?d == 1, IFNULL(displayIdA, displayIdH), IFNULL(displayIdH, displayIdA)) FROM ?_shapeshiftForm WHERE id = ?d', Util::sideByRaceMask(1 << ($char['race'] - 1)), $form); + } + + } ?> diff --git a/includes/database.class.php b/includes/database.class.php index 3c380b67..99bc1eb7 100644 --- a/includes/database.class.php +++ b/includes/database.class.php @@ -62,6 +62,11 @@ class DB return isset(self::$connectionCache[$idx]); } + public static function isConnectable($idx) + { + return isset(self::$optionsCache[$idx]); + } + private static function safeGetDB($idx) { if(!self::isConnected($idx)) @@ -74,12 +79,12 @@ class DB * @static * @return DbSimple_Mysql */ - public static function Characters($realm_id) + public static function Characters($realm) { - if (!isset(self::$optionsCache[DB_CHARACTERS+$realm_id])) - die('Connection info not found for live database of realm #'.$realm_id.'. Aborted.'); + if (!isset(self::$optionsCache[DB_CHARACTERS.$realm])) + die('Connection info not found for live database of realm #'.$realm.'. Aborted.'); - return self::safeGetDB(DB_CHARACTERS+$realm_id); + return self::safeGetDB(DB_CHARACTERS.$realm); } /** diff --git a/includes/kernel.php b/includes/kernel.php index c239b332..0bd24f04 100644 --- a/includes/kernel.php +++ b/includes/kernel.php @@ -59,7 +59,7 @@ if (!empty($AoWoWconf['auth']['db'])) foreach ($AoWoWconf['characters'] as $realm => $charDBInfo) if (!empty($charDBInfo)) - DB::load(DB_CHARACTERS + $realm, $charDBInfo); + DB::load(DB_CHARACTERS . $realm, $charDBInfo); unset($AoWoWconf); // link set up: delete passwords diff --git a/includes/types/item.class.php b/includes/types/item.class.php index 8bb793af..928a704c 100644 --- a/includes/types/item.class.php +++ b/includes/types/item.class.php @@ -718,7 +718,7 @@ class ItemList extends BaseType $x .= Lang::$item['durability'].' '.$dur.' / '.$dur.'
'; // required classes - if ($classes = Lang::getClassString($this->curTpl['requiredClass'], $jsg, $__, $interactive)) + if ($classes = Lang::getClassString($this->curTpl['requiredClass'], $jsg, $__, !$interactive)) { foreach ($jsg as $js) if (empty($this->jsGlobals[TYPE_CLASS][$js])) @@ -728,7 +728,7 @@ class ItemList extends BaseType } // required races - if ($races = Lang::getRaceString($this->curTpl['requiredRace'], $__, $jsg, $__, $interactive)) + if ($races = Lang::getRaceString($this->curTpl['requiredRace'], $__, $jsg, $__, !$interactive)) { foreach ($jsg as $js) if (empty($this->jsGlobals[TYPE_RACE][$js])) diff --git a/includes/types/profile.class.php b/includes/types/profile.class.php new file mode 100644 index 00000000..cc896157 --- /dev/null +++ b/includes/types/profile.class.php @@ -0,0 +1,233 @@ + use ProfileHelper; +// class GuildList extends BaseType +// class ArenaTeamList extends BaseType +class ProfileList extends BaseType +{ + public static $type = 0; // profiles dont actually have one + public static $brickFile = 'profile'; + + 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 $__) + { + $tDistrib = $this->getTalentDistribution(); + + $data[$this->id] = array( + '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 (!empty($this->curTpl['description'])) + $data[$this->id]['description'] = $this->curTpl['description']; + + if (!empty($this->curTpl['icon'])) + $data[$this->id]['icon'] = $this->curTpl['icon']; + + if ($this->curTpl['cuFlags'] & PROFILE_CU_PUBLISHED) + $data[$this->id]['published'] = 1; + + if ($this->curTpl['cuFlags'] & PROFILE_CU_PINNED) + $data[$this->id]['pinned'] = 1; + + if ($this->curTpl['cuFlags'] & PROFILE_CU_DELETED) + $data[$this->id]['deleted'] = 1; + } + + return $data; + } + + public function renderTooltip($interactive = false) + { + if (!$this->curTpl) + return []; + + if (isset($this->tooltips[$this->id])) + return $this->tooltips[$this->id]; + + $x = ''; + $x .= ''; + if ($g = $this->getField('name')) + $x .= ''; + else if ($d = $this->getField('description')) + $x .= ''; + $x .= ''; + $x .= '
'.$this->getField('name').'
<'.$g.'> ('.$this->getField('guildrank').')
'.$d.'
'.Lang::$game['level'].' '.$this->getField('level').' '.Lang::$game['ra'][$this->curTpl['race']].' '.Lang::$game['cl'][$this->curTpl['classs']].'
'; + + $this->tooltips[$this->id] = $x; + + return $this->tooltips[$this->id]; + } + + public function getJSGlobals($addMask = 0) {} + + private function getTalentDistribution() + { + 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)); + + $result = []; + $start = 0; + foreach ($this->tDistribution[$this->curTpl['classId']] as $len) + { + $result[] = array_sum(str_split(substr($this->curTpl['talentString'], $start, $len))); + $start += $len; + } + + return $result; + } +} + + +class ProfileListFilter extends Filter +{ + public $extraOpts = []; + + protected $genericFilter = array( + ); + + 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]; + } + + switch ($cr[0]) + { + default: + 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; + } +} + +?> diff --git a/includes/types/spell.class.php b/includes/types/spell.class.php index 7a447bb8..35d7c773 100644 --- a/includes/types/spell.class.php +++ b/includes/types/spell.class.php @@ -1694,7 +1694,7 @@ Lasts 5 min. $?$gte($pl,68)[][Cannot be used on items level 138 and higher.] $data[$this->id] = array( 'id' => $this->id, - 'name' => ($quality ? $quality : '@').$this->getField('name', true), + 'name' => ($quality ?: '@').$this->getField('name', true), 'icon' => $this->curTpl['iconStringAlt'] ? $this->curTpl['iconStringAlt'] : $this->curTpl['iconString'], 'level' => $talent ? $this->curTpl['talentLevel'] : $this->curTpl['spellLevel'], 'school' => $this->curTpl['schoolMask'], diff --git a/includes/user.class.php b/includes/user.class.php index 5d275610..1c88ff9b 100644 --- a/includes/user.class.php +++ b/includes/user.class.php @@ -178,7 +178,7 @@ class User } case AUTH_MODE_REALM: { - if (!DB::isConnected(DB_AUTH)) + if (!DB::isConnectable(DB_AUTH)) return AUTH_INTERNAL_ERR; $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 WHERE username = ? AND ORDER BY ab.active DESC LIMIT 1', $name); @@ -189,13 +189,12 @@ class User if (!self::verifySHA1($pass)) return AUTH_WRONGPASS; - if ($wow && !$wow['hasBan']) - if (!self::checkOrCreateInDB($wow['id'], $name)) - return AUTH_INTERNAL_ERR; - - else if ($wow['hasBan']) + if ($wow['hasBan']) return AUTH_BANNED; + if (!self::checkOrCreateInDB($wow['id'], $name)) + return AUTH_INTERNAL_ERR; + $user = $wow['id']; break; } @@ -395,7 +394,9 @@ class User public static function destroy() { + session_regenerate_id(true); // session itself is not destroyed; status changed => regenerate id session_unset(); + $_SESSION['locale'] = self::$localeId; // keep locale $_SESSION['dataKey'] = self::$dataKey; // keep dataKey diff --git a/index.php b/index.php index 864fb7d3..d12973cd 100644 --- a/index.php +++ b/index.php @@ -27,11 +27,6 @@ switch ($pageCall) case '': // no parameter given -> MainPage $altClass = 'main'; case 'account': // account management [nyi] - if (($_ = (new AjaxHandler($pageParam))->handle($pageCall)) !== null) - { - header('Content-type: application/x-javascript; charset=utf-8'); - die((string)$_); - } case 'achievement': case 'achievements': // case 'arena-team': @@ -80,6 +75,15 @@ switch ($pageCall) // case 'user': // tool: user profiles [nyi] case 'zone': case 'zones': + if (in_array($pageCall, ['account', 'profile'])) + { + if (($_ = (new AjaxHandler($pageParam))->handle($pageCall)) !== null) + { + header('Content-type: application/x-javascript; charset=utf-8'); + die((string)$_); + } + } + $_ = ($altClass ?: $pageCall).'Page'; (new $_($pageCall, $pageParam))->display(); break; diff --git a/localization/locale_dede.php b/localization/locale_dede.php index 4de7322f..e9673428 100644 --- a/localization/locale_dede.php +++ b/localization/locale_dede.php @@ -102,6 +102,10 @@ $lang = array( 'chooseClass' => "Wählt eine Klasse", 'chooseFamily' => "Wählt eine Tierart", + // profiler + 'realm' => "Realm", + 'region' => "Region", + // help 'help' => "Hilfe", 'helpTopics' => array( @@ -270,6 +274,7 @@ $lang = array( // creation 'register' => "Registrierung: Schritt %s von 2", + 'passConfirm' => "Kennwort bestätigen", // dashboard 'ipAddress' => "IP-Adresse", diff --git a/localization/locale_enus.php b/localization/locale_enus.php index a8d872c1..7ec8382e 100644 --- a/localization/locale_enus.php +++ b/localization/locale_enus.php @@ -97,6 +97,10 @@ $lang = array( 'chooseClass' => "Choose a class", 'chooseFamily' => "Choose a pet family", + // profiler + 'realm' => "Realm", + 'region' => "Region", + // help 'help' => "Help", 'helpTopics' => array( @@ -243,8 +247,8 @@ $lang = array( 'email' => "Email address", 'continue' => "Continue", 'groups' => array( - -1 => "None", "Tester", "Administrator", "Editor", "Moderator", "Bureaucrat", - "Developer", "VIP", "Blogger", "Premium", "Localizer", "Sales agent", + -1 => "None", "Tester", "Administrator", "Editor", "Moderator", "Bureaucrat", + "Developer", "VIP", "Blogger", "Premium", "Localizer", "Sales agent", "Screenshot manager", "Video manager" ), // signIn @@ -265,6 +269,7 @@ $lang = array( // creation 'register' => "Registration - Step %s of 2", + 'passConfirm' => "Confirm password", // dashboard 'ipAddress' => "IP-Adress", diff --git a/localization/locale_eses.php b/localization/locale_eses.php index 51498214..48c79dc3 100644 --- a/localization/locale_eses.php +++ b/localization/locale_eses.php @@ -102,6 +102,10 @@ $lang = array( 'chooseClass' => "Escoge una clase", 'chooseFamily' => "Escoge una familia de mascota", + // profiler + 'realm' => "Reino", + 'region' => "Región", + // help 'help' => "Ayuda", 'helpTopics' => array( @@ -265,6 +269,7 @@ $lang = array( // creation 'register' => "Inscripción: Paso %s de 2", + 'passConfirm' => "Confirmar contraseña", // dashboard 'ipAddress' => "IP-Adress", diff --git a/localization/locale_frfr.php b/localization/locale_frfr.php index f35ed465..6ea46034 100644 --- a/localization/locale_frfr.php +++ b/localization/locale_frfr.php @@ -102,6 +102,10 @@ $lang = array( 'chooseClass' => "Choisissez une classe", 'chooseFamily' => "Choisissez un familier", + // profiler + 'realm' => "Royaume", + 'region' => "Région", + // help 'help' => "Aide", 'helpTopics' => array( @@ -264,6 +268,7 @@ $lang = array( // creation 'register' => "Enregistrement : Étape %s de 2", + 'passConfirm' => "Confirmez", // dashboard 'ipAddress' => "IP-Adress", diff --git a/localization/locale_ruru.php b/localization/locale_ruru.php index 02af784e..64011efd 100644 --- a/localization/locale_ruru.php +++ b/localization/locale_ruru.php @@ -102,6 +102,10 @@ $lang = array( 'chooseClass' => "Выберите класс", 'chooseFamily' => "Выберите семейство питомцев", + // profiler + 'realm' => "Игровой мир", + 'region' => "Регион", + // help 'help' => "Справка", 'helpTopics' => array( @@ -270,6 +274,7 @@ $lang = array( // creation 'register' => "Регистрация: Шаг %s из 2", + 'passConfirm' => "Повторите пароль", // dashboard 'ipAddress' => "IP-Adress", diff --git a/pages/account.php b/pages/account.php index 7b826a96..1a60227b 100644 --- a/pages/account.php +++ b/pages/account.php @@ -4,35 +4,6 @@ if (!defined('AOWOW_REVISION')) die('illegal access'); -/* -enum(array( // AcctError - 'ACCT_USERNAME_LENGTH' => 'activate_usernamelength', - 'ACCT_PASSWORD_LENGTH' => 'activate_passwordlength', - 'ACCT_USERNAME_SYMBOLS' => 'activate_invalidusername', - 'ACCT_PASSWORD_SYMBOLS' => 'activate_invalidpassword', - 'ACCT_EMAIL_SYMBOLS' => 'signup_emailinvalid', - - 'ACCT_PASSWORDS_NOT_EQUAL' => 'signup_passwordsnotequal', - 'ACCT_USERNAME_EXISTS' => 'activate_usernameinuse', - 'ACCT_NO_SUCH_ACCT' => 'signin_un_or_pass_fail', - 'ACCT_IP_LOCKED' => 'signin_ip_locked', - - 'ACCT_SIGNUP_BLOCKED' => 'signup_blocked', - 'ACCT_SIGNIN_BLOCKED' => 'signin_blocked', - - 'ACCT_INTERNAL_ERROR' => 'internal_error', -)); - -message_emailnotvalid: "That email address is not valid.", -message_newemaildifferent: "Your new email address must be different than your previous one.", -message_newpassdifferent: "Your new password must be different than your previous one.", -message_passwordmin: "Your password must be at least 6 characters long.", -message_passwordsdonotmatch: "Passwords do not match.", -message_usernamemin: "Your username must be at least 4 characters long.", -message_usernamenotvalid: "Your username can only contain letters and numbers.", - -*/ - // exclude & weightscales are handled as Ajax class AccountPage extends GenericPage { @@ -114,12 +85,16 @@ class AccountPage extends GenericPage break; case 'signin': $this->tpl = 'acc-signIn'; + $this->next = $this->getNext(); if (isset($_POST['username']) || isset($_POST['password'])) { if ($err = $this->doSignIn()) $this->error = $err; else + { + session_regenerate_id(true); // user status changed => regenerate id header('Location: '.$this->getNext(true)); + } } 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 = $_; diff --git a/pages/genericPage.class.php b/pages/genericPage.class.php index 11679e3a..c19196bc 100644 --- a/pages/genericPage.class.php +++ b/pages/genericPage.class.php @@ -60,6 +60,7 @@ class GenericPage protected $title = [CFG_NAME]; // for title-Element protected $name = ''; // for h1-Element protected $tabId = 0; + protected $gDataKey = false; // adds the dataKey to the user vars protected $js = []; protected $css = []; @@ -357,8 +358,6 @@ class GenericPage public function display($override = '') // load given template string or GenericPage::$tpl { - session_regenerate_id(true); // can only reagenerate for real pages, otherwise a simple tooltip would be fatal for the session - if ($override) { $this->addAnnouncements(); diff --git a/pages/items.php b/pages/items.php index 61adf210..fde3facf 100644 --- a/pages/items.php +++ b/pages/items.php @@ -101,7 +101,10 @@ class ItemsPage extends GenericPage /* evaluate filter */ /*******************/ - // recreate form selection + // recreate form selection (must be evaluated first via getConditions()) + if ($_ = $this->filterObj->getConditions()) + $conditions[] = $_; + $this->filter = array_merge($this->filterObj->getForm('form'), $this->filter); $this->filter['query'] = @$_GET['filter'] ?: NULL; $this->filter['fi'] = $this->filterObj->getForm(); @@ -128,9 +131,6 @@ class ItemsPage extends GenericPage if (!empty($this->filter['fi']['extraCols'])) $this->sharedLV['extraCols'] = '$fi_getExtraCols(fi_extraCols, '.($this->filter['gm'] ?: 0).', '.(array_intersect([63], $xCols) ? 1 : 0).')'; - if ($_ = $this->filterObj->getConditions()) - $conditions[] = $_; - if ($this->filterObj->error) $this->sharedLV['_errors'] = '$1'; diff --git a/pages/profile.php b/pages/profile.php index e064bf6c..f0dfae6d 100644 --- a/pages/profile.php +++ b/pages/profile.php @@ -4,545 +4,131 @@ if (!defined('AOWOW_REVISION')) die('illegal access'); -$_path = [1, 5, 1]; -$_custom = false; -$_profile = null; -$_profileId = null; - - -/*********************/ -/* Parameter-Handler */ -/*********************/ - -function handlePower($custom, $data) // tooltip +class ProfilePage extends GenericPage { - header('Content-type: application/x-javascript; charsetUTF-8'); - - Util::powerUseLocale(@$_GET['domain']); - -@include('datasets/ProfilerExampleChar'); // tmp char data - - $name = $character['name']; - $guild = $character['guild']; - $gRankName = $character['guildrank']; - $lvl = $character['level']; - $ra = $character['race']; - $cl = $character['classs']; - $gender = $character['gender']; - $desc = $character['description']; - $title = (new TitleList(array(['id', $character['title']])))->getField($gender ? 'female' : 'male', true); - - if ($custom) - $name .= ' (Custom Profile)'; - else if ($title) - $name = sprintf($title, $name); - - $tt = ''; - $tt .= ''; - if ($guild) - $tt .= ''; - else if ($desc) - $tt .= ''; - - $tt .= ''; - $tt .= '
'.$name.'
<'.$guild.'> ('.$gRankName.')
'.$desc.'
'.Lang::$game['level'].' '.$lvl.' '.Lang::$game['ra'][$ra].' '.Lang::$game['cl'][$cl].'
'; - - $x = '$WowheadPower.registerProfile('.($custom ? $data : "'".implode('.', $data)."'").', '.User::$localeId.", {\n"; - $x .= "\tname_".User::$localeString.": '".Util::jsEscape($name)."',\n"; - $x .= "\ttooltip_".User::$localeString.": '".$tt."',\n"; - $x .= "\ticon: \$WH.g_getProfileIcon(".$ra.", ".$cl.", ".$gender.", ".$lvl."),\n"; // (race, class, gender, level, iconOrId, 'medium') - $x .= "});"; - - die($x); -} - -function handleAvatar() // image -{ - // something happened in the last years: those textures do not include tiny icons - $s = [/* 'tiny' => 15, */'small' => 18, 'medium' => 36, 'large' => 56]; - $size = empty($_GET['size']) ? 'medium' : $_GET['size']; - - if (empty($_GET['id']) || !preg_match('/^([0-9]+)\.(jpg|gif)$/', $_GET['id'], $matches) || !in_array($size, array_keys($s))) - return; - - header('Content-Type: image/'.$matches[2]); - - $id = $matches[1]; - - if (file_exists(getcwd().'/uploads/avatars/'.$id.'.jpg')) - { - $offsetX = $offsetY = 0; - - switch ($size) - { - case 'tiny': - $offsetX += $s['small']; - case 'small': - $offsetY += $s['medium']; - case 'medium': - $offsetX += $s['large']; - } - - $src = imageCreateFromJpeg('uploads/avatars/'.$id.'.jpg'); - $dest = imageCreateTruecolor($s[$size], $s[$size]); - - imagecopymerge($dest, $src, 0, 0, $offsetX, $offsetY, $s[$size], $s[$size], 100); - - if ($matches[2] == 'gif') - imageGif($dest); - else - imageJpeg($dest); - } -} - -function handlePinToggle($id, $mode) // (un)favorite -{ - /* params - id: - user: [optional] - return: null - */ -} - -function handleLinkToggle($id, $mode) // links char with account -{ - /* params - id: - user: [optional] - return: null - */ -} - -function handlePrivacyToggle($id, $mode) // ... -{ - /* params - id: - user: [optional] - return: null - */ -} - -function handleResync($initNew = true) // ... -{ - /* params - id: - user: [optional] - return - null [onOK] - int or str [onError] - */ - - if ($initNew) - return '1'; - else - { - /* - 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 - - [ - processId, - [StatusCode, timeToRefresh, iCount, errorCode, iNResyncs], - []... - ] - */ - return '[0, [4, 10000, 1, 2]]'; - } -} - -function handleSave() // unKill a profile -{ - /* params GET - id: - params POST - name, level, class, race, gender, nomodel, talenttree1, talenttree2, talenttree3, activespec, talentbuild1, glyphs1, talentbuild2, glyphs2, gearscore, icon, public [always] - description, source, copy, inv { inventory: array containing itemLinks } [optional] - } - return - int > 0 [profileId, if we came from an armoryProfile create a new one] - int < 0 [onError] - str [onError] - */ - - return 'NYI'; -} - -function handleDelete() // kill a profile -{ - /* params - id: - return - null - */ - - return 'NYI'; -} - -function handlePurge() // removes certain saved information but not the entire character -{ - /* params - id: - data: [string, tabName?] - return - null - */ - - return 'NYI'; -} - -function handleLoad() -{ - /* params - id: profileId - items: string [itemIds joined by :] - unnamed: unixtime [only to force the browser to reload instead of cache] - return - lots... - */ - - // titles, achievements, characterData, talents (, pets) - // and some onLoad-hook to .. load it registerProfile($data) - // everything else goes through data.php .. strangely enough - - - $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 - ), + protected $type = 0; + protected $typeId = 0; + protected $path = [1, 5, 1]; + protected $tabId = 1; + protected $tpl = 'profile'; + protected $reqDataKey = true; + protected $js = ['filters.js', 'TalentCalc.js', 'swfobject.js', 'profile_all.js', 'profile.js', 'Profiler.js']; + protected $css = array( + ['path' => 'TalentCalc.css'], + ['path' => 'Profiler.css'] ); + protected $profileId = 0; -@include('datasets/ProfilerExampleChar'); // tmp char data + private $isCustom = false; + private $profile = null; - $buff = ''; - $itemz = new ItemList(array(['id', array_column($character ['inventory'], 0)])); - $data = $itemz->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS); - - $auraz = new SpellList(array(['id', $character['auras']])); - $dataz = $auraz->getListviewData(); - $modz = $auraz->getProfilerMods(); - - // get and apply inventory - foreach ($itemz->iterate() as $iId => $__) - $buff .= 'g_items.add('.$iId.', {name_'.User::$localeString.":'".Util::jsEscape($itemz->getField('name', true))."', quality:".$itemz->getField('quality').", icon:'".$itemz->getField('iconString')."', jsonequip:".json_encode($data[$iId], JSON_NUMERIC_CHECK)."});\n"; - - $buff .= "\n"; - - // get and apply aura-mods - foreach ($dataz as $id => $data) + public function __construct($pageCall, $pageParam) { - $mods = []; - if (!empty($modz[$id])) + $_ = strlen($pageParam) ? explode('.', $pageParam) : null; + $this->getCategoryFromUrl($pageParam); + + $this->typeId &= $this->profileId; + + parent::__construct($pageCall, $pageParam); + + // temp locale + if ($this->mode == CACHETYPE_TOOLTIP && isset($_GET['domain'])) + Util::powerUseLocale($_GET['domain']); + + if (count($_) == 1 && intVal($_[0])) { - foreach ($modz[$id] as $k => $v) - { - if (is_array($v)) - $mods[] = $v; - else if ($str = @Util::$itemMods[$k]) - $mods[$str] = $v; - } - } + if ($_ = DB::Aowow()->selectCell('SELECT 2161862')) // some query to validate existence of char + $this->profileId = $_; + else + $this->notFound(Util::ucFirst(Lang::$game['profile'])); - $buff .= 'g_spells.add('.$id.", {id:".$id.", name:'".Util::jsEscape($data['name'])."', icon:'".$data['icon']."', modifier:".json_encode($mods, JSON_NUMERIC_CHECK)."});\n"; - } - $buff .= "\n"; - - // load available titles - Util::loadStaticFile('p-titles-'.$character['gender'], $buff, true); - - // load available achievements - if (!Util::loadStaticFile('p-achievements', $buff, true)) - { - $buff .= "\n\ng_achievement_catorder = [];"; - $buff .= "\n\ng_achievement_points = [0];"; - } - - // excludes; structure UNK type => [maskBit => [typeIds]] ? - /* - g_user.excludes = [type:[typeIds]] - g_user.includes = [type:[typeIds]] - g_user.excludegroups = groupMask // requires g_user.settings != null - - maskBit are matched against fieldId from excludeGroups - id: 1, label: LANG.dialog_notavail - id: 2, label: LANG.dialog_tcg - id: 4, label: LANG.dialog_collector - id: 8, label: LANG.dialog_promo - id: 16, label: LANG.dialog_nonus - id: 96, label: LANG.dialog_faction - id: 896, label: LANG.dialog_profession - id: 1024, label: LANG.dialog_noexalted - */ - // $buff .= "\n\ng_excludes = {};"; - - // add profile to buffer - $buff .= "\n\n\$WowheadProfiler.registerProfile(".json_encode($character).");"; // can't use JSON_NUMERIC_CHECK or the talent-string becomes a float - - return $buff."\n"; -} - - -/**********/ -/* HALPer */ -/**********/ - -function getModelForForm($form, $char) -{ - switch ($form) - { - case 1: // FORM_CAT - if ($char['race'] == 4) // RACE_NIGHTELF - { - if ($char['hairColor'] >= 0 && $char['hairColor'] <= 2) - return 29407; - else if ($char['hairColor'] == 3) - return 29406; - else if ($char['hairColor'] == 4) - return 29408; - else if ($char['hairColor'] == 7 || $char['hairColor'] == 8) - return 29405; - else - return 892; - } - - if ($char['race'] == 6) // RACE_TAUREN - { - if ($char['gender'] == GENDER_MALE) - { - if ($char['skinColor'] >= 0 && $char['skinColor'] <= 5) - return 29412; - else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 8) - return 29411; - else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 11) - return 29410; - else if (in_array($char['skinColor'], [12, 13, 14, 18])) - return 29410; - else - return 8571; - } - else // if gender == GENDER_FEMALE - { - if ($char['skinColor'] >= 0 && $char['skinColor'] <= 3) - return 29412; - else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 5) - return 29411; - else if ($char['skinColor'] >= 0 && $char['skinColor'] <= 7) - return 29410; - else if ($char['skinColor'] == 10) - return 29410; - else - return 8571; - } - } - case 5: // FORM_DIREBEAR - case 8: // FORM_BEAR - if ($char['race'] == 4) // RACE_NIGHTELF - { - if ($char['hairColor'] >= 0 && $char['hairColor'] <= 2) - return 29413; - else if ($char['hairColor'] == 3) - return 29417; - else if ($char['hairColor'] == 4) - return 29416; - else if ($char['hairColor'] == 6) - return 29414; - else - return 2281; - } - - if ($char['race'] == 6) // RACE_TAUREN - { - if ($char['gender'] == GENDER_MALE) - { - if ($char['skinColor'] >= 0 && $char['skinColor'] <= 2) - return 29415; - else if (in_array($char['skinColor'], [3, 4, 5, 12, 13, 14])) - return 29419; - else if (in_array($char['skinColor'], [9, 10, 11, 15, 16, 17])) - return 29420; - else if ($char['skinColor'] == 18) - return 29421; - else - return 2289; - } - else // if gender == GENDER_FEMALE - { - if ($char['skinColor'] == 0 && $char['skinColor'] == 1) - return 29418; - else if ($char['skinColor'] == 2 && $char['skinColor'] == 3) - return 29419; - else if ($char['skinColor'] >= 6 && $char['skinColor'] <= 9) - return 29420; - else if ($char['skinColor'] == 10) - return 29421; - else - return 2289; - } - } - } - - // hey, still here? you're not a Tauren/Nelf as bear or cat, are you? - return DB::Aowow()->selectCell('SELECT IF(?d == 1, IFNULL(displayIdA, displayIdH), IFNULL(displayIdH, displayIdA)) FROM ?_shapeshiftForm WHERE id = ?d AND XXX', Util::sideByRaceMask(1 << ($char['race'] - 1)), $form); -} - - -/******************/ -/* select handler */ -/******************/ - -switch ($pageParam) -{ - case 'link': - case 'unlink': - die(handleLinkToggle()); - case 'pin': - case 'unpin': - die(handlePinToggle()); - case 'public': - case 'private': - die(handlePrivacyToggle()); - case 'resync': - case 'status': - die(handleResync($pageParam == 'resync')); - case 'save': - die(handleSave()); - case 'delete': - die(handleDelete()); - case 'purge': - die(handlePurge()); - case 'summary': // page is generated by jScript - die(); - case 'avatar': - die(handleAvatar()); - case 'load': - die(handleLoad()); - case '': - if (isset($_GET['new'])) - { - $_profileId = 0; - break; - } - - die(); - default: - $_ = explode('.', $pageParam); - if (count($_) == 1 && intVal($_)) - { - $_custom = true; - $_profile = intVal($_); + $this->isCustom = true; + $this->profile = intVal($_[0]); } else if (count($_) == 3) - $_profile = $_; - else - Util::$pageTemplate->error(); + { + if ($_ = DB::Aowow()->selectCell('SELECT 2161862')) // some query to validate existence of char + $this->profileId = $_; + else + $this->notFound(Util::ucFirst(Lang::$game['profile'])); - // AowowPower-request - if (isset($_GET['power'])) - handlePower($_custom, $_profile); - else if ($_custom) // validate existance of profile - $_profileId = 0; - else if ($_ = DB::Aowow()->selectCell('SELECT 2161862')) // some query to validate existence of char - $_profileId = $_; - else - Util::$pageTemplate->notFound(Util::ucFirst(Lang::$game['profile']), $pageParam); + $this->profile = $_; + } + else if ($_ || !isset($_GET['new'])) + $this->notFound(Util::ucFirst(Lang::$game['profile'])); + + $this->subject = new ProfileList(/*stuff*/); + } + + protected function generateContent() + { + $this->addJS('?data=enchants.gems.glyphs.itemsets.pets.pet-talents.quick-excludes.realms.statistics.weight-presets&locale='.User::$localeId.'&t='.$_SESSION['dataKey']); + + $this->region = 'eu'; + $this->realm = 'Realm Name'; + } + + protected function generatePath() + { + + } + + protected function generateTitle() + { + array_unshift($this->title, Util::ucFirst(Lang::$game['profile'])); + } + + protected function generateTooltip($asError = false) + { + $x = '$WowheadPower.registerProfile('.($this->isCustom ? $this->profile : "'".implode('.', $this->profile)."'").', '.User::$localeId.', {'; + if ($asError) + return $x."});"; + + @include('datasets/ProfilerExampleChar'); // tmp char data + + $name = $character['name']; + $guild = $character['guild']; + $gRankName = $character['guildrank']; + $lvl = $character['level']; + $ra = $character['race']; + $cl = $character['classs']; + $gender = $character['gender']; + $desc = $character['description']; + $title = (new TitleList(array(['id', $character['title']])))->getField($gender ? 'female' : 'male', true); + + if ($this->isCustom) + $name .= ' (Custom Profile)'; + else if ($title) + $name = sprintf($title, $name); + + $x .= "\n"; + $x .= "\tname_".User::$localeString.": '".Util::jsEscape($name)."',\n"; + $x .= "\ttooltip_".User::$localeString.": '".$this->subject->renderTooltip()."',\n"; + $x .= "\ticon: \$WH.g_getProfileIcon(".$ra.", ".$cl.", ".$gender.", ".$lvl."),\n"; // (race, class, gender, level, iconOrId, 'medium') + $x .= "});"; + + return $x; + } + + public function display($override = '') + { + if ($this->mode != CACHETYPE_TOOLTIP) + return parent::display($override); + + // do not cache profile tooltips + header('Content-type: application/x-javascript; charset=utf-8'); + die($this->generateTooltip()); + } + + public function notFound($typeStr) + { + if ($this->mode != CACHETYPE_TOOLTIP) + return parent::notFound($typeStr); + + header('Content-type: application/x-javascript; charset=utf-8'); + echo $this->generateTooltip(true); + exit(); + } } - // required by progress in JScript move to handleLoad()? - Util::$pageTemplate->extendGlobalIds(TYPE_NPC, [29120, 31134, 29306, 29311, 23980, 27656, 26861, 26723, 28923, 15991]); - - -$pageData = array( - 'page' => array( - 'profileId' => $_profileId, - 'dataKey' => $_SESSION['dataKey'], - 'path' => json_encode($_path, JSON_NUMERIC_CHECK), - 'title' => Util::ucFirst(Lang::$game['profile']), // actual name is set per jScript - 'tab' => 1, - 'region' => 'eu', - 'realm' => 'realm Name', - 'reqJS' => array( - STATIC_URL.'/js/filters.js', - STATIC_URL.'/js/TalentCalc.js', - STATIC_URL.'/js/swfobject.js', - STATIC_URL.'/js/profile_all.js', - STATIC_URL.'/js/profile.js', - STATIC_URL.'/js/Profiler.js', - '?data=enchants.gems.glyphs.itemsets.pets.pet-talents.quick-excludes.realms.statistics.weight-presets&locale='.User::$localeId.'&t='.$_SESSION['dataKey'] - ), - 'reqCSS' => array( - ['path' => STATIC_URL.'/css/TalentCalc.css'], - ['path' => STATIC_URL.'/css/Profiler.css'] - ) - ) -); - - -$smarty->updatePageVars($pageData['page']); -$smarty->assign('lang', array_merge(Lang::$main, Lang::$game, ['colon' => Lang::$colon])); - -// load the page -$smarty->display('profile.tpl'); - - - ?> diff --git a/pages/profiles.php b/pages/profiles.php index 68872ade..e11acc71 100644 --- a/pages/profiles.php +++ b/pages/profiles.php @@ -21,87 +21,117 @@ new Listview({ }); */ -@include('datasets/ProfilerExampleChar'); // tmp char data - -$finalDis = []; -$tString = $character['talents']['builds'][$character['talents']['active']]['talents']; -$start = 0; -$distrib = 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 << ($character['classs'] - 1)); -foreach ($distrib as $d) -{ - $tSub = substr($tString, $start, $d); - $qty = 0; - for ($i = 0; $i < strlen($tSub); $i++) - $qty += (int)$tSub[$i]; - - $finalDis[] = $qty; - $start += $d; -} - -$lv = array( - array( - 'id' => 0, - 'name' => $character['name'], - 'acvPts' => $character['achievementpoints'], - 'guildName' => $character['guild'], - 'guildRank' => -1, - 'realmInternal' => $character['realm'][0], - 'realmName' => $character['realm'][1], - 'bgInternal' => $character['battlegroup'][0], - 'bgName' => $character['battlegroup'][0], - 'region' => $character['region'][0], - 'level' => $character['level'], - 'race' => $character['race'], - 'gender' => $character['gender'], - 'class' => $character['classs'], - 'faction' => $character['faction'], - 'tree' => $finalDis, - 'spec' => $character['talents']['active'] - ) -); - -// dont send ID for real chars unless they have some kind of custom avatar -// on second thought .. ids are required for resync, but the function that generates the icon is faulty - -$pageData = array( - 'file' => 'class', - 'data' => $lv, - 'params' => [ - 'id' => 'characters', - 'name' => '$LANG.tab_characters', - 'hideCount' => 1, - '_truncated' => 1, - 'roster' => 3, - 'visibleCols' => "$['race','classs','level','talents','achievementpoints']", - 'note' => '$$WH.sprintf(LANG.lvnote_charactersfound, \'20,592,390\', 200) + LANG.dash + LANG.lvnote_tryfiltering.replace(\'\', \'\')', - 'onBeforeCreate' => '$pr_initRosterListview' // $_GET['roster'] = 1|2|3|4 .. 2,3,4 arenateam-size (4 => 5-man), 1 guild .. it puts a resync button on the lv... - ] -); - - // menuId 5: Profiler g_initPath() // tabId 1: Tools g_initHeader() -$smarty->updatePageVars(array( - 'tab' => 1, - 'title' => Util::ucFirst(Lang::$game['profiles']), - 'path' => "[1, 5, 0, '".$character['region'][0]."', '".$character['battlegroup'][0]."', '".$character['realm'][0]."']", - 'realm' => '', // not sure about the use - 'region' => '', // seconded.. - 'reqJS' => array( - STATIC_URL.'/js/filters.js', - STATIC_URL.'/js/profile_all.js', - STATIC_URL.'/js/profile.js', - '?data=weight-presets.realms&locale='.User::$localeId.'&t='.$_SESSION['dataKey'] - ), - 'reqCSS' => array( - ['path' => STATIC_URL.'/css/profiler.css'] - ) -)); -$smarty->assign('lang', array_merge(Lang::$main, Lang::$game, ['colon' => Lang::$colon])); -$smarty->assign('lvData', $pageData); -$smarty->assign('filter', ['query' => 1]); +class ProfilesPage extends GenericPage +{ + protected $tpl = 'profiles'; + protected $js = ['filters.js', 'profile_all.js', 'profile.js']; + protected $css = [['path' => 'profiler.css']]; + protected $tabId = 1; + protected $path = [1, 5, 0]; + protected $realm = ''; // not sure about the use + protected $region = ''; // seconded.. -// load the page -$smarty->display('profiles.tpl'); + public function __construct($pageCall, $pageParam) + { + @include('datasets/ProfilerExampleChar'); // tmp char data + $this->character = $character; + + // soo .. + // we require a list and filter-handler for profiles + + parent::__construct($pageCall, $pageParam); + } + + protected function generateTitle() + { + $this->title[] = Util::ucFirst(Lang::$game['profiles']); + } + + protected function generatePath() + { + $this->path[] = $this->character['region'][0]; + $this->path[] = $this->character['battlegroup'][0]; + $this->path[] = $this->character['realm'][0]; + } + + protected function generateContent() + { + $this->addJS('?data=weight-presets.realms&locale='.User::$localeId.'&t='.$_SESSION['dataKey']); + + + $tDistrib = $this->getTalentDistribution($this->character['talents']['builds'][$this->character['talents']['active']]['talents']); + $exampleRow = array( + 'id' => 0, + 'name' => $this->character['name'], + 'achievementpoints' => $this->character['achievementpoints'], + 'guild' => $this->character['guild'], // 0 if none + 'guildRank' => -1, + 'realm' => $this->character['realm'][0], + 'realmname' => $this->character['realm'][1], + 'battlegroup' => $this->character['battlegroup'][0], + 'battlegroupname' => $this->character['battlegroup'][0], + 'region' => $this->character['region'][0], + 'level' => $this->character['level'], + 'race' => $this->character['race'], + 'gender' => $this->character['gender'], + 'classs' => $this->character['classs'], + 'faction' => $this->character['faction'], + 'talenttree1' => $tDistrib[0], + 'talenttree2' => $tDistrib[1], + 'talenttree3' => $tDistrib[2], + 'talentspec' => $this->character['talents']['active'] + ); + + // description:'{$curr.description|escape:"javascript"}', + // icon:'{$curr.icon|escape:"javascript"}', + // published:1, + // pinned:1, + // deleted:1, + + // dont send ID for real chars unless they have some kind of custom avatar + // on second thought .. ids are required for resync, but the function that generates the icon is faulty + + $this->lvData = array( + 'file' => 'profile', + 'data' => [$exampleRow], + 'params' => [ + 'id' => 'characters', + 'name' => '$LANG.tab_characters', + 'hideCount' => 1, + '_truncated' => 1, + 'roster' => 3, + 'visibleCols' => "$['race','classs','level','talents','achievementpoints']", + 'note' => '$$WH.sprintf(LANG.lvnote_charactersfound, \'20,592,390\', 200) + LANG.dash + LANG.lvnote_tryfiltering.replace(\'\', \'\')', + 'onBeforeCreate' => '$pr_initRosterListview' // $_GET['roster'] = 1|2|3|4 .. 2,3,4 arenateam-size (4 => 5-man), 1 guild .. it puts a resync button on the lv... + ] + ); + + + + $this->filter = ['query' => 1]; + + + asort(Lang::$game['cl']); + asort(Lang::$game['ra']); + } + + private function getTalentDistribution($tString) + { + $classMask = 1 << ($this->character['classs'] - 1); + $distrib = 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', $classMask); + $result = []; + + $start = 0; + foreach ($distrib as $len) + { + $result[] = array_sum(str_split(substr($tString, $start, $len))); + $start += $len; + } + + return $result; + } +} ?> diff --git a/pages/talent.php b/pages/talent.php index 49a676b5..19aaabf4 100644 --- a/pages/talent.php +++ b/pages/talent.php @@ -10,6 +10,7 @@ class TalentPage extends GenericPage protected $tpl = 'talent'; protected $tabId = 1; protected $mode = CACHETYPE_NONE; + protected $gDataKey = true; protected $js = ['TalentCalc.js']; protected $css = array( ['path' => 'TalentCalc.css'], @@ -39,7 +40,6 @@ class TalentPage extends GenericPage $this->addCSS($this->isPetCalc ? ['path' => 'petcalc.css'] : null); $this->tcType = $this->isPetCalc ? 'pc' : 'tc'; - $this->dataKey = $_SESSION['dataKey']; } protected function generateTitle() diff --git a/template/bricks/head.tpl.php b/template/bricks/head.tpl.php index adc3503f..2a953425 100644 --- a/template/bricks/head.tpl.php +++ b/template/bricks/head.tpl.php @@ -25,8 +25,8 @@ endforeach; var g_staticUrl = ""; var g_host = ""; dataKey)): - echo "var g_dataKey = '".$this->dataKey."'\n"; +if ($this->gDataKey): + echo " var g_dataKey = '".$_SESSION['dataKey']."'\n"; endif; ?> diff --git a/template/pages/acc-signUp.tpl.php b/template/pages/acc-signUp.tpl.php index 18e41eee..8d52a6e4 100644 --- a/template/pages/acc-signUp.tpl.php +++ b/template/pages/acc-signUp.tpl.php @@ -101,7 +101,7 @@
- + diff --git a/template/pages/items.tpl.php b/template/pages/items.tpl.php index c59677b2..0b304c6b 100644 --- a/template/pages/items.tpl.php +++ b/template/pages/items.tpl.php @@ -27,7 +27,7 @@ endif;
$str): + foreach ($f['slot'] as $k => $str): echo ' \n"; endforeach; ?> @@ -60,7 +60,7 @@ if (!empty($f['type'])):
$str): +foreach (Lang::$game['si'] as $k => $str): echo ' \n"; endforeach; ?> @@ -99,7 +99,7 @@ endforeach;   -{foreach from=$lang.cl key=i item=str}{if $str} - -{/if}{/foreach} - - - -
-
{$lang.race|ucfirst}{$lang.colon}
-
{$lang.clear} -
- -
- - - - - - - - - - - - - - - - - - - -
Name{$lang.colon} - - - - -
  
-
Region{$lang.colon}   -    Realm{$lang.colon} 
Side{$lang.colon}  -    {$lang.level}{$lang.colon}  -
- -
- - -
- {$lang.match}{$lang.colon} -
- -
- -
- - - -
- - - - -
- - -
- - - -{include file='footer.tpl'} diff --git a/template/pages/profiles.tpl.php b/template/pages/profiles.tpl.php new file mode 100644 index 00000000..3b6ba896 --- /dev/null +++ b/template/pages/profiles.tpl.php @@ -0,0 +1,126 @@ +brick('header'); +$f = $this->filter; // shorthand +?> + +
+
+
+ +brick('announcement'); ?> + + + + +
+
+
+ +
+ +
+ +
+
+ +
+ +
+ + + + + + + + + + + + + + + + +
+ + + + +
 />  />
+
      
     /> - />
+ +
+
+ +
+ />/> +
+ +
+ +
+ + +
+ +
+
+
+ + + +
+ + +
+
+
+ +brick('footer'); ?>