function sql($syncMe = null) { require_once 'setup/tools/sqlGen.class.php'; SqlGen::init($syncMe !== null ? SqlGen::MODE_UPDATE : SqlGen::MODE_NORMAL, $syncMe ?: []); $done = []; if (SqlGen::$subScripts) { $allOk = true; // start file generation CLISetup::log('begin generation of ' . implode(', ', SqlGen::$subScripts)); CLISetup::log(); foreach (SqlGen::$subScripts as $tbl) { $syncIds = []; // todo: fetch what exactly must be regenerated $ok = SqlGen::generate($tbl, $syncIds); if (!$ok) { $allOk = false; } else { $done[] = $tbl; } CLISetup::log(' - subscript \'' . $tbl . '\' returned ' . ($ok ? 'sucessfully' : 'with errors'), $ok ? CLISetup::LOG_OK : CLISetup::LOG_ERROR); set_time_limit(SqlGen::$defaultExecTime); // reset to default for the next script } // end CLISetup::log(); if ($allOk) { CLISetup::log('successfully finished sql generation', CLISetup::LOG_OK); } else { CLISetup::log('finished sql generation with errors', CLISetup::LOG_ERROR); } } else { CLISetup::log('no valid script names supplied', CLISetup::LOG_ERROR); } return $done; }
function realmMenu() { $subEU = []; $subUS = []; $set = 0x0; $menu = [['us', 'US & Oceanic', null, [[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subUS]]], ['eu', 'Europe', null, [[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subEU]]]]; foreach (Util::getRealms() as $row) { if ($row['region'] == 'eu') { $set |= 0x1; $subEU[] = [Util::urlize($row['name']), $row['name']]; } else { if ($row['region'] == 'us') { $set |= 0x2; $subUS[] = [Util::urlize($row['name']), $row['name']]; } } } if (!$set) { CLISetup::log(' - realmMenu: Auth-DB not set up .. menu will be empty', CLISetup::LOG_WARN); } if (!($set & 0x1)) { array_pop($menu); } if (!($set & 0x2)) { array_shift($menu); } return Util::toJSON($menu); }
function realmMenu() { $subEU = []; $subUS = []; $set = 0x0; $menu = [['us', 'US & Oceanic', null, [[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subEU]]], ['eu', 'Europe', null, [[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subUS]]]]; if (DB::isConnectable(DB_AUTH)) { $rows = DB::Auth()->select('SELECT name, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0 AND gamebuild = ?d', WOW_VERSION); foreach ($rows as $row) { if ($row['region'] == 'eu') { $set |= 0x1; $subEU[] = [Util::urlize($row['name']), $row['name']]; } else { if ($row['region'] == 'us') { $set |= 0x2; $subUS[] = [Util::urlize($row['name']), $row['name']]; } } } } else { CLISetup::log(' - realmMenu: Auth-DB not set up .. menu will be empty', CLISetup::LOG_WARN); } if (!($set & 0x1)) { array_shift($menu); } if (!($set & 0x2)) { array_pop($menu); } return Util::toJSON($menu); }
function build() { require_once 'setup/tools/fileGen.class.php'; FileGen::init(); if (FileGen::$subScripts) { $allOk = true; // start file generation CLISetup::log('begin generation of ' . implode(', ', FileGen::$subScripts)); CLISetup::log(); // files with template foreach (FileGen::$tplFiles as $name => list($file, $destPath, $deps)) { $reqDBC = []; if (!in_array($name, FileGen::$subScripts)) { continue; } if (!file_exists(FileGen::$tplPath . $file . '.in')) { CLISetup::log(sprintf(ERR_MISSING_FILE, FileGen::$tplPath . $file . '.in'), CLISetup::LOG_ERROR); $allOk = false; continue; } if (!CLISetup::writeDir($destPath)) { continue; } $syncIds = []; // todo: fetch what exactly must be regenerated $ok = FileGen::generate($name, $syncIds); if (!$ok) { $allOk = false; } CLISetup::log(' - subscript \'' . $file . '\' returned ' . ($ok ? 'sucessfully' : 'with errors'), $ok ? CLISetup::LOG_OK : CLISetup::LOG_ERROR); set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script } // files without template foreach (FileGen::$datasets as $file => $deps) { if (!in_array($file, FileGen::$subScripts)) { continue; } $syncIds = []; // todo: fetch what exactly must be regenerated $ok = FileGen::generate($file, $syncIds); if (!$ok) { $allOk = false; } CLISetup::log(' - subscript \'' . $file . '\' returned ' . ($ok ? 'sucessfully' : 'with errors'), $ok ? CLISetup::LOG_OK : CLISetup::LOG_ERROR); set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script } // end CLISetup::log(); if ($allOk) { CLISetup::log('successfully finished file generation', CLISetup::LOG_OK); } else { CLISetup::log('finished file generation with errors', CLISetup::LOG_ERROR); } } else { CLISetup::log('no valid script names supplied', CLISetup::LOG_ERROR); } }
function finish() { if (!getopt('d', ['delete'])) { // generated with TEMPORARY keyword. Manual deletion is not needed CLISetup::log('generated dbc_* - tables kept available', CLISetup::LOG_INFO); } die("\n"); }
function realms() { $realms = []; if (DB::isConnectable(DB_AUTH)) { $realms = DB::Auth()->select('SELECT id AS ARRAY_KEY, name, ? AS battlegroup, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0 AND gamebuild = ?d', CFG_BATTLEGROUP, WOW_VERSION); } else { CLISetup::log(' - realms: Auth-DB not set up .. static data g_realms will be empty', CLISetup::LOG_WARN); } $toFile = "var g_realms = " . Util::toJSON($realms) . ";"; $file = 'datasets/realms'; return CLISetup::writeFile($file, $toFile); }
function gems() { // sketchy, but should work // Id < 36'000 || ilevel < 70 ? BC : WOTLK $gems = DB::Aowow()->Select('SELECT i.id AS itemId, i.name_loc0, i.name_loc2, i.name_loc3, i.name_loc4, i.name_loc6, i.name_loc8, IF (i.id < 36000 OR i.itemLevel < 70, 1 , 2) AS expansion, i.quality, ic.iconString AS icon, i.gemEnchantmentId AS enchId, i.gemColorMask AS colors FROM ?_items i JOIN ?_icons ic ON ic.id = -i.displayId WHERE i.gemEnchantmentId <> 0 ORDER BY i.id DESC'); $success = true; // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } $enchIds = []; foreach ($gems as $pop) { $enchIds[] = $pop['enchId']; } $enchantments = new EnchantmentList(array(['id', $enchIds], CFG_SQL_LIMIT_NONE)); if ($enchantments->error) { CLISetup::log('Required table ?_itemenchantment seems to be empty! Leaving gems()...', CLISetup::LOG_ERROR); CLISetup::log(); return false; } foreach (CLISetup::$localeIds as $lId) { set_time_limit(5); User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); $gemsOut = []; foreach ($gems as $pop) { if (!$enchantments->getEntry($pop['enchId'])) { CLISetup::log(' * could not find enchantment #' . $pop['enchId'] . ' referenced by item #' . $gem['itemId'], CLISetup::LOG_WARN); continue; } $gemsOut[$pop['itemId']] = array('name' => Util::localizedString($pop, 'name'), 'quality' => $pop['quality'], 'icon' => strToLower($pop['icon']), 'enchantment' => $enchantments->getField('name', true), 'jsonequip' => $enchantments->getStatGain(), 'colors' => $pop['colors'], 'expansion' => $pop['expansion']); } $toFile = "var g_gems = " . Util::toJSON($gemsOut) . ";"; $file = 'datasets/' . User::$localeString . '/gems'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $success; }
function realms() { $realms = Util::getRealms(); if (!$realms) { CLISetup::log(' - realms: Auth-DB not set up .. static data g_realms will be empty', CLISetup::LOG_WARN); } else { foreach ($realms as &$r) { $r['battlegroup'] = CFG_BATTLEGROUP; } } $toFile = "var g_realms = " . Util::toJSON($realms) . ";"; $file = 'datasets/realms'; return CLISetup::writeFile($file, $toFile); }
function finish() { if (!getopt('d', ['delete'])) { // generated with TEMPORARY keyword. Manual deletion is not needed CLISetup::log('generated dbc_* - tables kept available', CLISetup::LOG_INFO); } // send "i'm in use @" - ping $u = !empty($_SERVER['USER']) ? $_SERVER['USER'] : '******'; $s = !empty($_SERVER['SSH_CONNECTION']) ? explode(' ', $_SERVER['SSH_CONNECTION'])[2] : 'NULL'; if ($h = @fopen('http://aowow.meedns.com/ref?u=' . $u . '&s=' . $s, 'r')) { fclose($h); } die("\n"); }
function update() { list($date, $part) = array_values(DB::Aowow()->selectRow('SELECT `date`, `part` FROM ?_dbversion')); CLISetup::log('checking sql updates'); $nFiles = 0; foreach (glob('setup/updates/*.sql') as $file) { $pi = pathinfo($file); list($fDate, $fPart) = explode('_', $pi['filename']); if ($date && $fDate < $date) { continue; } else { if ($part && $date && $fDate == $date && $fPart <= $part) { continue; } } $nFiles++; $updQuery = ''; $nQuerys = 0; foreach (file($file) as $line) { // skip comments if (substr($line, 0, 2) == '--' || $line == '') { continue; } $updQuery .= $line; // semicolon at the end -> end of query if (substr(trim($line), -1, 1) == ';') { if (DB::Aowow()->query($updQuery)) { $nQuerys++; } $updQuery = ''; } } DB::Aowow()->query('UPDATE ?_dbversion SET `date`= ?d, `part` = ?d', $fDate, $fPart); CLISetup::log(' -> ' . date('d.m.Y', $fDate) . ' #' . $fPart . ': ' . $nQuerys . ' queries applied', CLISetup::LOG_OK); } CLISetup::log($nFiles ? 'applied ' . $nFiles . ' update(s)' : 'db is already up to date', CLISetup::LOG_OK); // fetch sql/build after applying updates, as they may contain sync-prompts list($sql, $build) = array_values(DB::Aowow()->selectRow('SELECT `sql`, `build` FROM ?_dbversion')); sleep(1); $sql = trim($sql) ? array_unique(explode(' ', trim($sql))) : []; $build = trim($build) ? array_unique(explode(' ', trim($build))) : []; if ($sql) { CLISetup::log('The following table(s) require syncing: ' . implode(', ', $sql)); } if ($build) { CLISetup::log('The following file(s) require syncing: ' . implode(', ', $build)); } return [$sql, $build]; }
function glyphs() { $success = true; $glyphList = DB::Aowow()->Select('SELECT i.id AS itemId, i.*, IF (g.typeFlags & 0x1, 2, 1) AS type, i.subclass AS classs, i.requiredLevel AS level, s1.Id AS glyphSpell, ic.iconString AS icon, s1.skillLine1 AS skillId, s2.Id AS glyphEffect, s2.Id AS ARRAY_KEY FROM ?_items i JOIN ?_spell s1 ON s1.Id = i.spellid1 JOIN ?_glyphproperties g ON g.Id = s1.effect1MiscValue JOIN ?_spell s2 ON s2.Id = g.spellId JOIN ?_icons ic ON ic.Id = s1.iconIdAlt WHERE i.classBak = 16'); // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } $glyphSpells = new SpellList(array(['s.id', array_keys($glyphList)], CFG_SQL_LIMIT_NONE)); foreach (CLISetup::$localeIds as $lId) { set_time_limit(30); User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); $glyphsOut = []; foreach ($glyphSpells->iterate() as $__) { $pop = $glyphList[$glyphSpells->id]; if (!$pop['glyphEffect']) { continue; } if ($glyphSpells->getField('effect1Id') != 6 && $glyphSpells->getField('effect2Id') != 6 && $glyphSpells->getField('effect3Id') != 6) { continue; } $glyphsOut[$pop['itemId']] = array('name' => Util::localizedString($pop, 'name'), 'description' => $glyphSpells->parseText()[0], 'icon' => $pop['icon'], 'type' => $pop['type'], 'classs' => $pop['classs'], 'skill' => $pop['skillId'], 'level' => $pop['level']); } $toFile = "var g_glyphs = " . Util::toJSON($glyphsOut) . ";"; $file = 'datasets/' . User::$localeString . '/glyphs'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $success; }
function pets() { $success = true; $locations = []; $petList = DB::Aowow()->Select('SELECT cr. id, cr.name_loc0, cr.name_loc2, cr.name_loc3, cr.name_loc6, cr.name_loc8, cr.minLevel, cr.maxLevel, ft.A, ft.H, cr.rank AS classification, cr.family, cr.displayId1 AS displayId, cr.textureString AS skin, LOWER(SUBSTRING_INDEX(cf.iconString, "\\\\", -1)) AS icon, cf.petTalentType AS type FROM ?_creature cr JOIN ?_factiontemplate ft ON ft.Id = cr.faction JOIN dbc_creaturefamily cf ON cf.id = cr.family WHERE cr.typeFlags & 0x1 AND (cr.cuFlags & 0x2) = 0 ORDER BY cr.id ASC'); // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } foreach (CLISetup::$localeIds as $lId) { User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); $petsOut = []; foreach ($petList as $pet) { // get locations // again: caching will save you time and nerves if (!isset($locations[$pet['id']])) { $locations[$pet['id']] = DB::Aowow()->SelectCol('SELECT DISTINCT areaId FROM ?_spawns WHERE type = ?d AND typeId = ?d', TYPE_NPC, $pet['id']); } $petsOut[$pet['id']] = array('id' => $pet['id'], 'name' => Util::localizedString($pet, 'name'), 'minlevel' => $pet['minLevel'], 'maxlevel' => $pet['maxLevel'], 'location' => $locations[$pet['id']], 'react' => [$pet['A'], $pet['H']], 'classification' => $pet['classification'], 'family' => $pet['family'], 'displayId' => $pet['displayId'], 'skin' => $pet['skin'], 'icon' => $pet['icon'], 'type' => $pet['type']); } $toFile = "var g_pets = " . Util::toJSON($petsOut) . ";"; $file = 'datasets/' . User::$localeString . '/pets'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $success; }
function gems() { // sketchy, but should work // Id < 36'000 || ilevel < 70 ? BC : WOTLK $gems = DB::Aowow()->Select('SELECT i.id AS itemId, i.name_loc0, i.name_loc2, i.name_loc3, i.name_loc6, i.name_loc8, IF (i.id < 36000 OR i.itemLevel < 70, 1 , 2) AS expansion, i.quality, ic.iconString AS icon, i.gemEnchantmentId AS enchId, i.gemColorMask AS colors FROM ?_items i JOIN ?_icons ic ON ic.id = -i.displayId WHERE i.gemEnchantmentId <> 0 ORDER BY i.id DESC'); $success = true; // check directory-structure foreach (Util::$localeStrings as $dir) { if (!CLISetup::writeDir('datasets/' . $dir)) { $success = false; } } $enchIds = []; foreach ($gems as $pop) { $enchIds[] = $pop['enchId']; } $enchMisc = []; $enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc); foreach (CLISetup::$localeIds as $lId) { set_time_limit(5); User::useLocale($lId); Lang::load(Util::$localeStrings[$lId]); $gemsOut = []; foreach ($gems as $pop) { $gemsOut[$pop['itemId']] = array('name' => Util::localizedString($pop, 'name'), 'quality' => $pop['quality'], 'icon' => strToLower($pop['icon']), 'enchantment' => Util::localizedString(@$enchMisc[$pop['enchId']]['text'] ?: [], 'text'), 'jsonequip' => @$enchJSON[$pop['enchId']] ?: [], 'colors' => $pop['colors'], 'expansion' => $pop['expansion']); } $toFile = "var g_gems = " . Util::toJSON($gemsOut) . ";"; $file = 'datasets/' . User::$localeString . '/gems'; if (!CLISetup::writeFile($file, $toFile)) { $success = false; } } return $success; }
function update() { $createQuery = "\r\n CREATE TABLE `aowow_dbversion` (\r\n `date` INT(10) UNSIGNED NOT NULL DEFAULT '0',\r\n `part` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0'\r\n ) ENGINE=MyISAM"; $date = $part = 0; if (!DB::Aowow()->selectCell('SHOW TABLES LIKE "%dbversion"')) { DB::Aowow()->query($createQuery); DB::Aowow()->query('INSERT INTO ?_dbversion VALUES (0, 0)'); } else { list($date, $part) = array_values(DB::Aowow()->selectRow('SELECT `date`, `part` FROM ?_dbversion')); } CLISetup::log('checking sql updates'); $nFiles = 0; foreach (glob('setup/updates/*.sql') as $file) { $pi = pathinfo($file); list($fDate, $fPart) = explode('_', $pi['filename']); if ($date && $fDate < $date) { continue; } else { if ($part && $date && $fDate == $date && $fPart <= $part) { continue; } } $nFiles++; $updQuery = ''; $nQuerys = 0; foreach (file($file) as $line) { // skip comments if (substr($line, 0, 2) == '--' || $line == '') { continue; } $updQuery .= $line; // semicolon at the end -> end of query if (substr(trim($line), -1, 1) == ';') { if (DB::Aowow()->query($updQuery)) { $nQuerys++; } $updQuery = ''; } } DB::Aowow()->query('UPDATE ?_dbversion SET `date`= ?d, `part` = ?d', $fDate, $fPart); CLISetup::log(' -> ' . date('d.m.Y', $fDate) . ' #' . $fPart . ': ' . $nQuerys . ' queries applied', CLISetup::LOG_OK); } CLISetup::log($nFiles ? 'applied ' . $nFiles . ' update(s)' : 'db is already up to date', CLISetup::LOG_OK); }
function weightPresets() { // check directory-structure if (!CLISetup::writeDir('datasets/')) { return false; } $wtPresets = []; $scales = DB::Aowow()->select('SELECT id, name, icon, class FROM ?_account_weightscales WHERE userId = 0 ORDER BY class, id ASC'); foreach ($scales as $s) { $weights = DB::Aowow()->selectCol('SELECT field AS ARRAY_KEY, val FROM ?_account_weightscale_data WHERE id = ?d', $s['id']); if (!$weights) { CLISetup::log('WeightScale \'' . CLISetup::bold($s['name']) . '\' has no data set. Skipping...', CLISetup::LOG_WARN); continue; } $wtPresets[$s['class']]['pve'][$s['name']] = array_merge(['__icon' => $s['icon']], $weights); } $toFile = "var wt_presets = " . Util::toJSON($wtPresets) . ";"; $file = 'datasets/weight-presets'; if (!CLISetup::writeFile($file, $toFile)) { return false; } return true; }
function account() { $fields = array('name' => ['Username', false], 'pass1' => ['Enter Password', true], 'pass2' => ['Confirm Password', true]); if (CLISetup::readInput($fields)) { CLISetup::log(); if (!User::isValidName($fields['name'], $e)) { CLISetup::log(Lang::account($e == 1 ? 'errNameLength' : 'errNameChars'), CLISetup::LOG_ERROR); } else { if (!User::isValidPass($fields['pass1'], $e)) { CLISetup::log(Lang::account($e == 1 ? 'errPassLength' : 'errPassChars'), CLISetup::LOG_ERROR); } else { if ($fields['pass1'] != $fields['pass2']) { CLISetup::log(Lang::account('passMismatch'), CLISetup::LOG_ERROR); } else { if ($_ = DB::Aowow()->SelectCell('SELECT 1 FROM ?_account WHERE user = ? AND (status <> ?d OR (status = ?d AND statusTimer > UNIX_TIMESTAMP()))', $fields['name'], ACC_STATUS_NEW, ACC_STATUS_NEW)) { CLISetup::log(Lang::account('nameInUse'), CLISetup::LOG_ERROR); } else { // write to db $ok = DB::Aowow()->query('REPLACE INTO ?_account (user, passHash, displayName, joindate, email, allowExpire, userGroups, userPerms) VALUES (?, ?, ?, UNIX_TIMESTAMP(), ?, 0, ?d, 1)', $fields['name'], User::hashCrypt($fields['pass1']), Util::ucFirst($fields['name']), CFG_CONTACT_EMAIL, U_GROUP_ADMIN); if ($ok) { $newId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE user = ?', $fields['name']); Util::gainSiteReputation($newId, SITEREP_ACTION_REGISTER); CLISetup::log("account " . $fields['name'] . " created successfully", CLISetup::LOG_OK); } else { // something went wrong CLISetup::log(Lang::main('intError'), CLISetup::LOG_ERROR); } } } } } } else { CLISetup::log(); CLISetup::log("account creation aborted", CLISetup::LOG_WARN); } }
function currencies(array $ids = []) { if (!$ids) { DB::Aowow()->query('REPLACE INTO ?_currencies (id, category, itemId) SELECT Id, category, itemId FROM dbc_currencytypes'); } $moneyItems = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, itemId FROM dbc_currencytypes{ WHERE id IN (?a)}', $ids ?: DBSIMPLE_SKIP); // apply names $moneyNames = DB::World()->select('SELECT it.entry AS ARRAY_KEY, name AS name_loc0, name_loc2, name_loc3, name_loc6, name_loc8 FROM item_template it LEFT JOIN locales_item li ON li.entry = it.entry WHERE it.entry IN (?a)', $moneyItems); foreach ($moneyItems as $cId => $itemId) { if (!empty($moneyNames[$itemId])) { $strings = $moneyNames[$itemId]; } else { CLISetup::log('item #' . $itemId . ' required by currency #' . $cId . ' not in item_template', CLISetup::LOG_WARN); $strings = ['name_loc0' => 'Item #' . $itemId . ' not in DB', 'iconId' => -1240, 'cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW, 'category' => 3]; } DB::Aowow()->query('UPDATE ?_currencies SET ?a WHERE itemId = ?d', $strings, $itemId); } // apply icons $displayIds = DB::World()->selectCol('SELECT entry AS ARRAY_KEY, displayid FROM item_template WHERE entry IN (?a)', $moneyItems); foreach ($displayIds as $itemId => $iconId) { DB::Aowow()->query('UPDATE ?_currencies SET iconId = ?d WHERE itemId = ?d', -$iconId, $itemId); } return true; }
function item_stats(array $ids = []) { $offset = 0; CLISetup::log(' - applying stats for enchantments'); $enchStats = enchantment_stats(); CLISetup::log(' ' . count($enchStats) . ' enchantments parsed'); CLISetup::log(' - applying stats for items'); while (true) { $items = new ItemStatSetup($offset, SqlGen::$stepSize, $ids, $enchStats); if ($items->error) { break; } $max = max($items->getFoundIDs()); $num = count($items->getFoundIDs()); CLISetup::log(' * sets ' . ($offset + 1) . ' - ' . $max); $offset = $max; $items->writeStatsTable(); } return true; }
function simpleImg() { // prefer manually converted PNG files (as the imagecreatefromblp-script has issues with some formats) // see: https://github.com/Kanma/BLPConverter $loadImageFile = function ($path) { $result = null; if (in_array(mb_substr($path, -4, 4), ['.png', '.blp', '.BLP', '.PNG'])) { $path = mb_substr($path, 0, mb_strlen($path) - 4); } $file = $path . '.png'; if (CLISetup::fileExists($file)) { CLISetup::log('manually converted png file present for ' . $path . '.', CLISetup::LOG_INFO); $result = imagecreatefrompng($file); } if (!$result) { $file = $path . '.blp'; if (CLISetup::fileExists($file)) { $result = imagecreatefromblp($file); } } return $result; }; if (isset(FileGen::$cliOpts['help'])) { echo "\n"; echo "available options for subScript 'simpleImg':\n"; echo " --icons (generates square icons that are used for basicly everything)\n"; echo " --glyphs (decorative tidbit displayed on Infobox for Glyph Spells)\n"; echo " --pagetexts (imagery contained in PageTexts on readable GameObjects or Items)\n"; echo " --loadingscreens (loading screens (not used, skipped by default))\n"; return true; } $locStr = null; $groups = []; $dbcPath = CLISetup::$srcDir . '%sDBFilesClient/'; $imgPath = CLISetup::$srcDir . '%sInterface/'; $destDir = 'static/images/wow/'; $success = true; $iconDirs = array(['icons/large/', 'jpg', 0, 56, 4], ['icons/medium/', 'jpg', 0, 36, 4], ['icons/small/', 'jpg', 0, 18, 4], ['icons/tiny/', 'gif', 0, 15, 4]); $calendarDirs = array(['icons/large/', 'jpg', 90, 56, 4], ['icons/medium/', 'jpg', 90, 36, 4], ['icons/small/', 'jpg', 90, 18, 4], ['icons/tiny/', 'gif', 90, 15, 4]); $loadScreenDirs = array(['loadingscreens/large/', 'jpg', 0, 1024, 0], ['loadingscreens/medium/', 'jpg', 0, 488, 0], ['loadingscreens/original/', 'png', 0, 0, 0], ['loadingscreens/small/', 'jpg', 0, 244, 0]); $paths = array(0 => ['Icons/', $iconDirs, '/*.[bB][lL][pP]', true, 0], 1 => ['Spellbook/', [['Interface/Spellbook/', 'png', 0, 0, 0]], '/UI-Glyph-Rune*.blp', true, 0], 2 => ['PaperDoll/', array_slice($iconDirs, 0, 3), '/UI-{Backpack,PaperDoll}-*.blp', true, 0], 3 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-Races.blp', $iconDirs, '', true, 64], 4 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-CLASSES.blp', $iconDirs, '', true, 64], 5 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-Factions.blp', $iconDirs, '', true, 64], 7 => ['FlavorImages/', [['Interface/FlavorImages/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0], 8 => ['Pictures/', [['Interface/Pictures/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0], 9 => ['PvPRankBadges/', [['Interface/PvPRankBadges/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0], 10 => ['Calendar/Holidays/', $calendarDirs, '/*{rt,a,y,h,s}.[bB][lL][pP]', true, 0], 11 => ['GLUES/LOADINGSCREENS/', $loadScreenDirs, '/[lL][oO]*.[bB][lL][pP]', false, 0]); // textures are composed of 64x64 icons // numeric indexed arrays mimick the position on the texture $cuNames = array(2 => array('ui-paperdoll-slot-chest' => 'inventoryslot_chest', 'ui-backpack-emptyslot' => 'inventoryslot_empty', 'ui-paperdoll-slot-feet' => 'inventoryslot_feet', 'ui-paperdoll-slot-finger' => 'inventoryslot_finger', 'ui-paperdoll-slot-hands' => 'inventoryslot_hands', 'ui-paperdoll-slot-head' => 'inventoryslot_head', 'ui-paperdoll-slot-legs' => 'inventoryslot_legs', 'ui-paperdoll-slot-mainhand' => 'inventoryslot_mainhand', 'ui-paperdoll-slot-neck' => 'inventoryslot_neck', 'ui-paperdoll-slot-secondaryhand' => 'inventoryslot_offhand', 'ui-paperdoll-slot-ranged' => 'inventoryslot_ranged', 'ui-paperdoll-slot-relic' => 'inventoryslot_relic', 'ui-paperdoll-slot-shirt' => 'inventoryslot_shirt', 'ui-paperdoll-slot-shoulder' => 'inventoryslot_shoulder', 'ui-paperdoll-slot-tabard' => 'inventoryslot_tabard', 'ui-paperdoll-slot-trinket' => 'inventoryslot_trinket', 'ui-paperdoll-slot-waist' => 'inventoryslot_waist', 'ui-paperdoll-slot-wrists' => 'inventoryslot_wrists'), 3 => array(['race_human_male', 'race_dwarf_male', 'race_gnome_male', 'race_nightelf_male', 'race_draenei_male'], ['race_tauren_male', 'race_scourge_male', 'race_troll_male', 'race_orc_male', 'race_bloodelf_male'], ['race_human_female', 'race_dwarf_female', 'race_gnome_female', 'race_nightelf_female', 'race_draenei_female'], ['race_tauren_female', 'race_scourge_female', 'race_troll_female', 'race_orc_female', 'race_bloodelf_female']), 4 => array(['class_warrior', 'class_mage', 'class_rogue', 'class_druid'], ['class_hunter', 'class_shaman', 'class_priest', 'class_warlock'], ['class_paladin', 'class_deathknight']), 5 => array(['faction_alliance', 'faction_horde']), 6 => array([], [null, 'quest_start', 'quest_end', 'quest_start_daily', 'quest_end_daily']), 10 => array('calendar_winterveilstart' => 'calendar_winterveilstart', 'calendar_noblegardenstart' => 'calendar_noblegardenstart', 'calendar_childrensweekstart' => 'calendar_childrensweekstart', 'calendar_fishingextravaganza' => 'calendar_fishingextravaganzastart', 'calendar_harvestfestivalstart' => 'calendar_harvestfestivalstart', 'calendar_hallowsendstart' => 'calendar_hallowsendstart', 'calendar_lunarfestivalstart' => 'calendar_lunarfestivalstart', 'calendar_loveintheairstart' => 'calendar_loveintheairstart', 'calendar_midsummerstart' => 'calendar_midsummerstart', 'calendar_brewfeststart' => 'calendar_brewfeststart', 'calendar_darkmoonfaireelwynnstart' => 'calendar_darkmoonfaireelwynnstart', 'calendar_darkmoonfairemulgorestart' => 'calendar_darkmoonfairemulgorestart', 'calendar_darkmoonfaireterokkarstart' => 'calendar_darkmoonfaireterokkarstart', 'calendar_piratesday' => 'calendar_piratesdaystart', 'calendar_wotlklaunch' => 'calendar_wotlklaunchstart', 'calendar_dayofthedeadstart' => 'calendar_dayofthedeadstart', 'calendar_fireworks' => 'calendar_fireworksstart')); $writeImage = function ($name, $ext, $src, $srcDims, $destDims, $done) { $ok = false; $dest = imagecreatetruecolor($destDims['w'], $destDims['h']); imagesavealpha($dest, true); if ($ext == 'png') { imagealphablending($dest, false); } imagecopyresampled($dest, $src, $destDims['x'], $destDims['x'], $srcDims['x'], $srcDims['y'], $destDims['w'], $destDims['h'], $srcDims['w'], $srcDims['h']); switch ($ext) { case 'jpg': $ok = imagejpeg($dest, $name . '.' . $ext, 85); break; case 'gif': $ok = imagegif($dest, $name . '.' . $ext); break; case 'png': $ok = imagepng($dest, $name . '.' . $ext); break; default: CLISetup::log($done . ' - unsupported file fromat: ' . $ext, CLISetup::LOG_WARN); } imagedestroy($dest); if ($ok) { chmod($name . '.' . $ext, Util::FILE_ACCESS); CLISetup::log($done . ' - image ' . $name . '.' . $ext . ' written', CLISetup::LOG_OK); } else { CLISetup::log($done . ' - could not create image ' . $name . '.' . $ext, CLISetup::LOG_ERROR); } return $ok; }; $checkSourceDirs = function ($sub, &$missing = []) use($imgPath, $dbcPath, $paths) { $hasMissing = false; foreach (array_column($paths, 0) as $subDir) { $p = sprintf($imgPath, $sub) . $subDir; if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } } $p = sprintf($dbcPath, $sub); if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } return !$hasMissing; }; if (isset(FileGen::$cliOpts['icons'])) { array_push($groups, 0, 2, 3, 4, 5, 10); } if (isset(FileGen::$cliOpts['glyphs'])) { $groups[] = 1; } if (isset(FileGen::$cliOpts['pagetexts'])) { array_push($groups, 7, 8, 9); } if (isset(FileGen::$cliOpts['loadingscreens'])) { $groups[] = 11; } // filter by pasaed options if (!$groups) { // by default do not generate loadingscreens unset($paths[11]); } else { foreach (array_keys($paths) as $k) { if (!in_array($k, $groups)) { unset($paths[$k]); } } } foreach (CLISetup::$expectedPaths as $xp => $__) { if ($xp) { // if in subDir add trailing slash $xp .= '/'; } if ($checkSourceDirs($xp, $missing)) { $locStr = $xp; break; } } // if no subdir had sufficient data, diaf if ($locStr === null) { CLISetup::log('one or more required directories are missing:', CLISetup::LOG_ERROR); foreach ($missing as $m) { CLISetup::log(' - ' . $m, CLISetup::LOG_ERROR); } return; } // init directories foreach (array_column($paths, 1) as $subDirs) { foreach ($subDirs as $sd) { if (!CLISetup::writeDir($destDir . $sd[0])) { $success = false; } } } // ok, departure from std::procedure here // scan ItemDisplayInfo.dbc and SpellIcon.dbc for expected images and save them to an array // load all icon paths into another array and xor these two // excess entries for the directory are fine, excess entries for the dbc's are not $dbcEntries = []; if (isset($paths[0]) || isset($paths[1])) { if (isset($paths[0]) && !isset($paths[1])) { $siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon WHERE iconPath NOT LIKE "%glyph-rune%"'); } else { if (!isset($paths[0]) && isset($paths[1])) { $siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon WHERE iconPath LIKE "%glyph-rune%"'); } else { $siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon'); } } foreach ($siRows as $icon) { $dbcEntries[] = strtolower(sprintf('setup/mpqdata/%s', $locStr) . strtr($icon, ['\\' => '/']) . '.blp'); } } if (isset($paths[0])) { $itemIcons = DB::Aowow()->selectCol('SELECT inventoryIcon1 FROM dbc_itemdisplayinfo WHERE inventoryIcon1 <> ""'); foreach ($itemIcons as $icon) { $dbcEntries[] = strtolower(sprintf($imgPath, $locStr) . 'Icons/' . $icon . '.blp'); } $eventIcons = DB::Aowow()->selectCol('SELECT textureString FROM dbc_holidays WHERE textureString <> ""'); foreach ($eventIcons as $icon) { $dbcEntries[] = strtolower(sprintf($imgPath, $locStr) . 'Calendar/Holidays/' . $icon . 'Start.blp'); } } // case-insensitive array_unique *vomits silently into a corner* $dbcEntries = array_intersect_key($dbcEntries, array_unique($dbcEntries)); $allPaths = []; foreach ($paths as $i => $p) { $path = sprintf($imgPath, $locStr) . $p[0]; if (!CLISetup::fileExists($path)) { continue; } $files = glob($path . $p[2], GLOB_BRACE); $allPaths = array_merge($allPaths, $files); CLISetup::log('processing ' . count($files) . ' files in ' . $path . '...'); $j = 0; foreach ($files as $f) { ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time) $src = null; $img = explode('.', array_pop(explode('/', $f))); array_pop($img); // there are a hand full of images with multiple file endings or random dots in the name $img = implode('.', $img); // file not from dbc -> name from array or skip file if (!empty($cuNames[$i])) { if (!empty($cuNames[$i][strtolower($img)])) { $img = $cuNames[$i][strtolower($img)]; } else { if (!$p[4]) { $j += count($p[1]); CLISetup::log('skipping extraneous file ' . $img . ' (+' . count($p[1]) . ')'); continue; } } } $nFiles = count($p[1]) * ($p[4] ? array_sum(array_map('count', $cuNames[$i])) : count($files)); foreach ($p[1] as $info) { if ($p[4]) { foreach ($cuNames[$i] as $y => $row) { foreach ($row as $x => $name) { $j++; $img = $p[3] ? strtolower($name) : $name; $done = ' - ' . str_pad($j . '/' . $nFiles, 12) . str_pad('(' . number_format($j * 100 / $nFiles, 2) . '%)', 9); if (!isset(FileGen::$cliOpts['force']) && file_exists($destDir . $info[0] . $img . '.' . $info[1])) { CLISetup::log($done . ' - file ' . $info[0] . $img . '.' . $info[1] . ' was already processed'); continue; } if (!$src) { $src = $loadImageFile($f); } if (!$src) { // error should be created by imagecreatefromblp continue; } $from = array('x' => $info[4] + $p[4] * $x, 'y' => $info[4] + $p[4] * $y, 'w' => $p[4] - $info[4] * 2, 'h' => $p[4] - $info[4] * 2); $to = array('x' => 0, 'y' => 0, 'w' => $info[3], 'h' => $info[3]); if (!$writeImage($destDir . $info[0] . $img, $info[1], $src, $from, $to, $done)) { $success = false; } } } // custom handle for combined icon 'quest_startend' /* not used due to alphaChannel issues if ($p[4] == 32) { $dest = imagecreatetruecolor(19, 16); imagesavealpha($dest, true); imagealphablending($dest, true); // excalmationmark, questionmark imagecopyresampled($dest, $src, 0, 1, 32 + 5, 32 + 2, 8, 15, 18, 30); imagecopyresampled($dest, $src, 5, 0, 64 + 1, 32 + 1, 10, 16, 18, 28); if (imagegif($dest, $destDir.$info[0].'quest_startend.gif')) CLISetup::log(' extra - image '.$destDir.$info[0].'quest_startend.gif written', CLISetup::LOG_OK); else { CLISetup::log(' extra - could not create image '.$destDir.$info[0].'quest_startend.gif', CLISetup::LOG_ERROR); $success = false; } imagedestroy($dest); } */ } else { // icon -> lowercase if ($p[3]) { $img = strtolower($img); } $j++; $done = ' - ' . str_pad($j . '/' . $nFiles, 12) . str_pad('(' . number_format($j * 100 / $nFiles, 2) . '%)', 9); if (!isset(FileGen::$cliOpts['force']) && file_exists($destDir . $info[0] . $img . '.' . $info[1])) { CLISetup::log($done . ' - file ' . $info[0] . $img . '.' . $info[1] . ' was already processed'); continue; } if (!$src) { $src = $loadImageFile($f); } if (!$src) { // error should be created by imagecreatefromblp continue; } $from = array('x' => $info[4], 'y' => $info[4], 'w' => ($info[2] ?: imagesx($src)) - $info[4] * 2, 'h' => ($info[2] ?: imagesy($src)) - $info[4] * 2); $to = array('x' => 0, 'y' => 0, 'w' => $info[3] ?: imagesx($src), 'h' => $info[3] ?: imagesy($src)); if (!$writeImage($destDir . $info[0] . $img, $info[1], $src, $from, $to, $done)) { $success = false; } } } unset($src); } } // reset execTime ini_set('max_execution_time', FileGen::$defaultExecTime); if ($missing = array_diff(array_map('strtolower', $dbcEntries), array_map('strtolower', $allPaths))) { asort($missing); CLISetup::log('the following ' . count($missing) . ' images where referenced by DBC but not in the mpqData directory. They may need to be converted by hand later on.', CLISetup::LOG_WARN); foreach ($missing as $m) { CLISetup::log(' - ' . $m); } } return $success; }
function objects(array $ids = []) { $baseQuery = ' SELECT go.entry, `type`, IF(`type` = 2, -2, -- quests 1 IF(`type` = 8 AND Data0 IN (1, 2, 3, 4, 1552), -6, -- tools IF(`type` = 3 AND IFNULL(gqi.ItemId, 0) <> 0, -2, -- quests 2 IF(`type` IN (3, 9, 25), `type`, 0)))), -- regular chests, books, pools 0 AS event, -- linked worldevent displayId, go.name, gtl2.`name` AS name_loc2, gtl3.`name` AS name_loc3, gtl6.`name` AS name_loc6, gtl8.`name` AS name_loc8, faction, flags, 0 AS cuFlags, -- custom Flags IF(`type` IN (3, 25), Data1, 0), -- lootId IF(`type` IN (2, 3, 6, 10, 13, 24, 26), Data0, IF(`type` IN (0, 1), Data1, 0)), -- lockId 0 AS reqSkill, -- reqSkill IF(`type` = 9, Data0, IF(`type` = 10, Data7, 0)), -- pageTextId IF(`type` = 1, Data3, -- linkedTrapIds IF(`type` = 3, Data7, IF(`type` = 10, Data12, IF(`type` = 8, Data2, 0)))), IF(`type` = 5, Data5, -- reqQuest IF(`type` = 3, Data8, IF(`type` = 10, Data1, IF(`type` = 8, Data4, 0)))), IF(`type` = 8, Data0, 0), -- spellFocusId IF(`type` = 10, Data10, -- onUseSpell IF(`type` IN (18, 24), Data1, IF(`type` = 26, Data2, IF(`type` = 22, Data0, 0)))), IF(`type` = 18, Data4, 0), -- onSuccessSpell IF(`type` = 18, Data2, IF(`type` = 24, Data3, 0)), -- auraSpell IF(`type` = 30, Data2, IF(`type` = 24, Data4, IF(`type` = 6, Data3, 0))), -- triggeredSpell IF(`type` = 29, CONCAT_WS(" ", Data14, Data15, Data16, Data17, Data0), -- miscInfo: capturePoint IF(`type` = 3, CONCAT_WS(" ", Data4, Data5, Data2), -- miscInfo: loot v IF(`type` = 25, CONCAT_WS(" ", Data2, Data3, 0), IF(`type` = 23, CONCAT_WS(" ", Data0, Data1, Data2), "")))), -- miscInfo: meetingStone IF(ScriptName <> "", ScriptName, AIName) FROM gameobject_template go LEFT JOIN gameobject_template_locale gtl2 ON go.entry = gtl2.entry AND gtl2.`locale` = "frFR" LEFT JOIN gameobject_template_locale gtl3 ON go.entry = gtl3.entry AND gtl3.`locale` = "deDE" LEFT JOIN gameobject_template_locale gtl6 ON go.entry = gtl6.entry AND gtl6.`locale` = "esES" LEFT JOIN gameobject_template_locale gtl8 ON go.entry = gtl8.entry AND gtl8.`locale` = "ruRU" LEFT JOIN gameobject_questitem gqi ON gqi.GameObjectEntry = go.entry { WHERE go.entry IN (?a) } GROUP BY go.entry LIMIT ?d, ?d'; $updateQuery = ' UPDATE ?_objects o LEFT JOIN dbc_lock l ON l.id = IF(o.`type` = 3, lockId, null) SET typeCat = IF(`type` = 3 AND (l.properties1 = 1 OR l.properties2 = 1), -5, -- footlocker IF(`type` = 3 AND (l.properties1 = 2), -3, -- herb IF(`type` = 3 AND (l.properties1 = 3), -4, typeCat))), -- ore reqSkill = IF(`type` = 3 AND l.properties1 IN (1, 2, 3), IF(l.reqSkill1 > 1, l.reqSkill1, 1), IF(`type` = 3 AND l.properties2 = 1, IF(l.reqSkill2 > 1, l.reqSkill2, 1), 0)) { WHERE o.id IN (?a) }'; $offset = 0; while ($objects = DB::World()->select($baseQuery, $ids ?: DBSIMPLE_SKIP, $offset, SqlGen::$stepSize)) { CLISetup::log(' * sets ' . ($offset + 1) . ' - ' . ($offset + count($objects))); $offset += SqlGen::$stepSize; foreach ($objects as $o) { DB::Aowow()->query('REPLACE INTO ?_objects VALUES (?a)', array_values($o)); } } // apply typeCat and reqSkill depending on locks DB::Aowow()->query($updateQuery, $ids ?: DBSIMPLE_SKIP); return true; }
function firstrun($resume) { require_once 'setup/tools/sqlGen.class.php'; require_once 'setup/tools/fileGen.class.php'; SqlGen::init(true); FileGen::init(true); /****************/ /* define steps */ /****************/ $steps = array(['dbconfig', null, 'testDB', 'Please enter your database credentials.', 'could not establish connection to:'], ['siteconfig', null, 'testSelf', 'SITE_HOST and STATIC_HOST ' . CLISetup::bold('must') . ' be set. Also enable FORCE_SSL if needed. You may also want to change other variables such as NAME, NAME_SHORT OR LOCALES.', 'could not access:'], ['SqlGen::generate', 'achievementcategory', null, null, null], ['SqlGen::generate', 'achievementcriteria', null, null, null], ['SqlGen::generate', 'glyphproperties', null, null, null], ['SqlGen::generate', 'itemenchantment', null, null, null], ['SqlGen::generate', 'itemenchantmentcondition', null, null, null], ['SqlGen::generate', 'itemextendedcost', null, null, null], ['SqlGen::generate', 'itemlimitcategory', null, null, null], ['SqlGen::generate', 'itemrandomproppoints', null, null, null], ['SqlGen::generate', 'lock', null, null, null], ['SqlGen::generate', 'mailtemplate', null, null, null], ['SqlGen::generate', 'scalingstatdistribution', null, null, null], ['SqlGen::generate', 'scalingstatvalues', null, null, null], ['SqlGen::generate', 'spellfocusobject', null, null, null], ['SqlGen::generate', 'spellrange', null, null, null], ['SqlGen::generate', 'spellvariables', null, null, null], ['SqlGen::generate', 'totemcategory', null, null, null], ['SqlGen::generate', 'classes', null, null, null], ['SqlGen::generate', 'factions', null, null, null], ['SqlGen::generate', 'factiontemplate', null, null, null], ['SqlGen::generate', 'holidays', null, null, null], ['SqlGen::generate', 'icons', null, null, null], ['SqlGen::generate', 'itemrandomenchant', null, null, null], ['SqlGen::generate', 'races', null, null, null], ['SqlGen::generate', 'shapeshiftforms', null, null, null], ['SqlGen::generate', 'skillline', null, null, null], ['SqlGen::generate', 'achievement', null, null, null], ['SqlGen::generate', 'creature', null, null, null], ['SqlGen::generate', 'currencies', null, null, null], ['SqlGen::generate', 'events', null, null, null], ['SqlGen::generate', 'objects', null, null, null], ['SqlGen::generate', 'pet', null, null, null], ['SqlGen::generate', 'quests', null, null, null], ['SqlGen::generate', 'quests_startend', null, null, null], ['SqlGen::generate', 'spell', null, null, null], ['SqlGen::generate', 'spelldifficulty', null, null, null], ['SqlGen::generate', 'taxi', null, null, null], ['SqlGen::generate', 'titles', null, null, null], ['SqlGen::generate', 'items', null, null, null], ['FileGen::generate', 'complexImg', null, null, null], ['SqlGen::generate', 'spawns', null, null, null], ['SqlGen::generate', 'zones', null, null, null], ['SqlGen::generate', 'itemset', null, null, null], ['SqlGen::generate', 'item_stats', null, null, null], ['SqlGen::generate', 'source', null, null, null], ['FileGen::generate', 'searchplugin', null, null, null], ['FileGen::generate', 'power', null, null, null], ['FileGen::generate', 'searchboxScript', null, null, null], ['FileGen::generate', 'demo', null, null, null], ['FileGen::generate', 'searchboxBody', null, null, null], ['FileGen::generate', 'realmMenu', null, null, null], ['FileGen::generate', 'locales', null, null, null], ['FileGen::generate', 'itemScaling', null, null, null], ['FileGen::generate', 'realms', null, null, null], ['FileGen::generate', 'statistics', null, null, null], ['FileGen::generate', 'simpleImg', null, null, null], ['FileGen::generate', 'talents', null, null, null], ['FileGen::generate', 'pets', null, null, null], ['FileGen::generate', 'talentIcons', null, null, null], ['FileGen::generate', 'glyphs', null, null, null], ['FileGen::generate', 'itemsets', null, null, null], ['FileGen::generate', 'enchants', null, null, null], ['FileGen::generate', 'gems', null, null, null], ['FileGen::generate', 'profiler', null, null, null], ['FileGen::generate', 'statistics', null, null, null], ['FileGen::generate', 'statistics', null, null, null], ['update', null, null, null, null], ['account', null, 'testAcc', 'Please create your admin account.', 'There is no user with administrator priviledges in the DB.'], ['endSetup', null, null, null, null]); /**********/ /* helper */ /**********/ $saveProgress = function ($nStep) { $h = fopen('cache/firstrun', 'w'); fwrite($h, AOWOW_REVISION . "\n" . ($nStep + 1) . "\n"); fclose($h); }; $testDB = function (&$error) { require 'config/config.php'; $error = []; foreach (['world', 'aowow', 'auth'] as $what) { if ($what == 'auth' && (empty($AoWoWconf['auth']) || empty($AoWoWconf['auth']['host']))) { continue; } if ($link = @mysqli_connect($AoWoWconf[$what]['host'], $AoWoWconf[$what]['user'], $AoWoWconf[$what]['pass'], $AoWoWconf[$what]['db'])) { mysqli_close($link); } else { $error[] = ' * ' . $what . ': ' . '[' . mysqli_connect_errno() . '] ' . mysqli_connect_error(); } } return empty($error); }; $testSelf = function (&$error) { $error = []; $test = function ($url, &$rCode) { $res = get_headers($url, true); if (preg_match("/HTTP\\/[0-9\\.]+\\s+([0-9]+)/", $res[0], $m)) { $rCode = $m[1]; return $m[1] == 200; } $rCode = 0; return false; }; $res = DB::Aowow()->selectCol('SELECT `key` AS ARRAY_KEY, value FROM ?_config WHERE `key` IN ("site_host", "static_host", "force_ssl")'); $prot = $res['force_ssl'] ? 'https://' : 'http://'; if ($res['site_host']) { if (!$test($prot . $res['site_host'] . '/README', $resp)) { $error[] = ' * could not access ' . $prot . $res['site_host'] . '/README [' . $resp . ']'; } } else { $error[] = ' * SITE_HOST is empty'; } if ($res['static_host']) { if (!$test($prot . $res['static_host'] . '/css/aowow.css', $resp)) { $error[] = ' * could not access ' . $prot . $res['static_host'] . '/css/aowow.css [' . $resp . ']'; } } else { $error[] = ' * STATIC_HOST is empty'; } return empty($error); }; $testAcc = function (&$error) { $error = []; return !!DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE userPerms = 1'); }; function endSetup() { return DB::Aowow()->query('UPDATE ?_config SET value = 0 WHERE `key` = "maintenance"'); } /********************/ /* get current step */ /********************/ $startStep = 0; if ($resume) { if (file_exists('cache/firstrun')) { $rows = file('cache/firstrun'); if ((int) $rows[0] == AOWOW_REVISION) { $startStep = (int) $rows[1]; } else { CLISetup::log('firstrun info is outdated! Starting from scratch.', CLISetup::LOG_WARN); } } if (!$startStep) { CLISetup::log('no usable info found.', CLISetup::LOG_WARN); $inp = ['x' => ['start from scratch? (y/n)', true, '/y|n/i']]; if (!CLISetup::readInput($inp, true) || !$inp || strtolower($inp['x']) == 'n') { CLISetup::log(); return; } CLISetup::log(); } else { CLISetup::log('Resuming setup from step ' . $startStep); sleep(1); } } /*******/ /* run */ /*******/ foreach ($steps as $idx => $step) { if ($startStep > $idx) { continue; } if (!strpos($step[0], '::') && !is_callable($step[0])) { require_once 'setup/tools/clisetup/' . $step[0] . '.func.php'; } if ($step[3]) { CLISetup::log($step[3]); $inp = ['x' => ['Press any key to continue', true]]; if (!CLISetup::readInput($inp, true)) { // we don't actually care about the input return; } } while (true) { $res = call_user_func($step[0], $step[1]); // check script result if ($step[2]) { if (!${$step}[2]($errors)) { CLISetup::log($step[4], CLISetup::LOG_ERROR); foreach ($errors as $e) { CLISetup::log($e); } } else { $saveProgress($idx); break; } } else { if ($res !== false) { $saveProgress($idx); break; } } $inp = ['x' => ['[' . CLISetup::bold('c') . ']ontinue anyway? [' . CLISetup::bold('r') . ']etry? [' . CLISetup::bold('a') . ']bort?', true, '/c|r|a/i']]; if (CLISetup::readInput($inp, true) && $inp) { switch (strtolower($inp['x'])) { case 'c': $saveProgress($idx); break 2; case 'r': CLISetup::log(); break; case 'a': CLISetup::log(); return; } } else { CLISetup::log(); return; } } } unlink('cache/firstrun'); CLISetup::log('setup finished', CLISetup::LOG_OK); }
function complexImg() { if (isset(FileGen::$cliOpts['help'])) { echo "\n"; echo "available options for subScript 'complexImg':\n"; // modeMask echo "--talentbgs (backgrounds for talent calculator)\n"; // 0x01 echo "--maps (generates worldmaps)\n"; // 0x02 echo "--spawn-maps (creates alphaMasks of each zone to check spawns against)\n"; // 0x04 echo "--artwork (optional: imagery from /glues/credits (not used, skipped by default))\n"; // 0x08 echo "--area-maps (optional: renders maps with highlighted subZones for each area)\n"; // 0x10 return true; } $mapWidth = 1002; $mapHeight = 668; $threshold = 95; // alpha threshold to define subZones: set it too low and you have unspawnable areas inside a zone; set it too high and the border regions overlap $runTime = ini_get('max_execution_time'); $locStr = null; $dbcPath = CLISetup::$srcDir . '%sDBFilesClient/'; $imgPath = CLISetup::$srcDir . '%sInterface/'; $destDir = 'static/images/wow/'; $success = true; $paths = ['WorldMap/', 'TalentFrame/', 'Glues/Credits/']; $modeMask = 0x7; // talentBGs, regular maps, spawn-related alphaMaps $createAlphaImage = function ($w, $h) { $img = imagecreatetruecolor($w, $h); imagesavealpha($img, true); imagealphablending($img, false); $bgColor = imagecolorallocatealpha($img, 0, 0, 0, 127); imagefilledrectangle($img, 0, 0, imagesx($img) - 1, imagesy($img) - 1, $bgColor); imagecolortransparent($img, $bgColor); imagealphablending($img, true); imagecolordeallocate($img, $bgColor); return $img; }; // prefer manually converted PNG files (as the imagecreatefromblp-script has issues with some formats) // alpha channel issues observed with locale deDE Hilsbrad and Elwynn - maps // see: https://github.com/Kanma/BLPConverter $loadImageFile = function ($path) { $result = null; $file = $path . '.png'; if (CLISetup::fileExists($file)) { CLISetup::log('manually converted png file present for ' . $path . '.', CLISetup::LOG_WARN); $result = imagecreatefrompng($file); } if (!$result) { $file = $path . '.blp'; if (CLISetup::fileExists($file)) { $result = imagecreatefromblp($file); } } return $result; }; $assembleImage = function ($baseName, $order, $w, $h) use($loadImageFile) { $dest = imagecreatetruecolor($w, $h); imagesavealpha($dest, true); imagealphablending($dest, false); $_h = $h; foreach ($order as $y => $row) { $_w = $w; foreach ($row as $x => $suffix) { $src = $loadImageFile($baseName . $suffix); if (!$src) { CLISetup::log(' - complexImg: tile ' . $baseName . $suffix . '.blp missing.', CLISetup::LOG_ERROR); unset($dest); return null; } imagecopyresampled($dest, $src, 256 * $x, 256 * $y, 0, 0, min($_w, 256), min($_h, 256), min($_w, 256), min($_h, 256)); $_w -= 256; unset($src); } $_h -= 256; } return $dest; }; $writeImage = function ($name, $ext, $src, $w, $h, $done) { $ok = false; $dest = imagecreatetruecolor($w, $h); imagesavealpha($dest, true); imagealphablending($dest, false); imagecopyresampled($dest, $src, 0, 0, 0, 0, $w, $h, imagesx($src), imagesy($src)); switch ($ext) { case 'jpg': $ok = imagejpeg($dest, $name . '.' . $ext, 85); break; case 'png': $ok = imagepng($dest, $name . '.' . $ext); break; default: CLISetup::log($done . ' - unsupported file fromat: ' . $ext, CLISetup::LOG_WARN); } imagedestroy($dest); if ($ok) { chmod($name . '.' . $ext, CLISetup::FILE_ACCESS); CLISetup::log($done . ' - image ' . $name . '.' . $ext . ' written', CLISetup::LOG_OK); } else { CLISetup::log($done . ' - could not create image ' . $name . '.' . $ext, CLISetup::LOG_ERROR); } return $ok; }; $createSpawnMap = function ($img, $zoneId) use($mapHeight, $mapWidth, $threshold) { CLISetup::log(' - creating spawn map'); $tmp = imagecreate(1000, 1000); $cbg = imagecolorallocate($tmp, 255, 255, 255); $cfg = imagecolorallocate($tmp, 0, 0, 0); for ($y = 0; $y < 1000; $y++) { for ($x = 0; $x < 1000; $x++) { $a = imagecolorat($img, $x * $mapWidth / 1000, $y * $mapHeight / 1000) >> 24; imagesetpixel($tmp, $x, $y, $a < $threshold ? $cfg : $cbg); } } imagepng($tmp, 'setup/generated/alphaMaps/' . $zoneId . '.png'); imagecolordeallocate($tmp, $cbg); imagecolordeallocate($tmp, $cfg); imagedestroy($tmp); }; $checkSourceDirs = function ($sub, &$missing = []) use($imgPath, $dbcPath, $paths, &$modeMask) { $hasMissing = false; foreach ($paths as $idx => $subDir) { if ($idx == 0 && !($modeMask & 0x16)) { // map related continue; } else { if ($idx == 1 && !($modeMask & 0x1)) { // talentBGs continue; } else { if ($idx == 2 && !($modeMask & 0x8)) { // artwork continue; } } } $p = sprintf($imgPath, $sub) . $subDir; if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } } if ($modeMask & 0x17) { $p = sprintf($dbcPath, $sub); if (!CLISetup::fileExists($p)) { $hasMissing = true; $missing[] = $p; } } return !$hasMissing; }; // do not change order of params! if ($_ = FileGen::hasOpt('talentbgs', 'maps', 'spawn-maps', 'artwork', 'area-maps')) { $modeMask = $_; } foreach (CLISetup::$expectedPaths as $xp => $__) { if ($xp) { // if in subDir add trailing slash $xp .= '/'; } if ($checkSourceDirs($xp, $missing)) { $locStr = $xp; break; } } // if no subdir had sufficient data, diaf if ($locStr === null) { CLISetup::log('one or more required directories are missing:', CLISetup::LOG_ERROR); foreach ($missing as $m) { CLISetup::log(' - ' . $m, CLISetup::LOG_ERROR); } return; } /**************/ /* TalentTabs */ /**************/ if ($modeMask & 0x1) { if (CLISetup::writeDir($destDir . 'hunterpettalents/') && CLISetup::writeDir($destDir . 'talents/backgrounds/')) { // [classMask, creatureFamilyMask, tabNr, textureStr] $tTabs = DB::Aowow()->select('SELECT tt.creatureFamilyMask, tt.textureFile, tt.tabNumber, cc.fileString FROM dbc_talenttab tt LEFT JOIN dbc_chrclasses cc ON cc.Id = (LOG(2, tt.classMask) + 1)'); $order = array(['-TopLeft', '-TopRight'], ['-BottomLeft', '-BottomRight']); if ($tTabs) { $sum = 0; $total = count($tTabs); CLISetup::log('Processing ' . $total . ' files from TalentFrame/ ...'); foreach ($tTabs as $tt) { ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time) $sum++; $done = ' - ' . str_pad($sum . '/' . $total, 8) . str_pad('(' . number_format($sum * 100 / $total, 2) . '%)', 9); if ($tt['creatureFamilyMask']) { $size = [244, 364]; $name = $destDir . 'hunterpettalents/bg_' . (log($tt['creatureFamilyMask'], 2) + 1); } else { $size = [204, 554]; $name = $destDir . 'talents/backgrounds/' . strtolower($tt['fileString']) . '_' . ($tt['tabNumber'] + 1); } if (!isset(FileGen::$cliOpts['force']) && file_exists($name . '.jpg')) { CLISetup::log($done . ' - file ' . $name . '.jpg was already processed'); continue; } $im = $assembleImage(sprintf($imgPath, $locStr) . 'TalentFrame/' . $tt['textureFile'], $order, 256 + 44, 256 + 75); if (!$im) { CLISetup::log(' - could not assemble file ' . $tt['textureFile'], CLISetup::LOG_ERROR); continue; } if (!$writeImage($name, 'jpg', $im, $size[0], $size[1], $done)) { $success = false; } } } else { $success = false; } ini_set('max_execution_time', $runTime); } else { $success = false; } } /************/ /* Worldmap */ /************/ if ($modeMask & 0x16) { $mapDirs = array(['maps/%snormal/', 'jpg', 488, 325], ['maps/%soriginal/', 'jpg', 0, 0], ['maps/%ssmall/', 'jpg', 224, 163], ['maps/%szoom/', 'jpg', 772, 515]); // as the js expects them $baseLevelFix = array(4264 => 1, 4265 => 1, 4415 => 1, 4416 => 1, 4493 => 0, 4500 => 1, 4603 => 1, 4723 => 1, 4809 => 1, 4813 => 1, 4820 => 1, 717 => 1, 3713 => 1, 2437 => 1, 3716 => 1, 3847 => 1, 718 => 1, 3717 => 1, 3714 => 1, 3562 => 1, 722 => 1, 491 => 1, 3792 => 1, 3789 => 1, 1477 => 1, 3959 => 0, 3845 => 1, 2717 => 1, 3923 => 1, 3607 => 1, 3836 => 1, 2159 => 1, 4075 => 0); $wmo = DB::Aowow()->select('SELECT *, worldMapAreaId AS ARRAY_KEY, Id AS ARRAY_KEY2 FROM dbc_worldmapoverlay WHERE textureString <> ""'); $wma = DB::Aowow()->select('SELECT * FROM dbc_worldmaparea'); if (!$wma || !$wmo) { $success = false; CLISetup::log(' - could not read required dbc files: WorldMapArea.dbc [' . count($wma) . ' entries]; WorldMapOverlay.dbc [' . count($wmo) . ' entries]', CLISetup::LOG_ERROR); return; } // fixups... foreach ($wma as &$a) { if ($a['areaId']) { continue; } switch ($a['Id']) { case 13: $a['areaId'] = -6; break; // Kalimdor // Kalimdor case 14: $a['areaId'] = -3; break; // Eastern Kingdoms // Eastern Kingdoms case 466: $a['areaId'] = -2; break; // Outland // Outland case 485: $a['areaId'] = -5; break; // Northrend } } array_unshift($wma, ['Id' => -1, 'areaId' => -1, 'nameINT' => 'World'], ['Id' => -4, 'areaId' => -4, 'nameINT' => 'Cosmic']); $sumMaps = count(CLISetup::$localeIds) * count($wma); CLISetup::log('Processing ' . $sumMaps . ' files from WorldMap/ ...'); foreach (CLISetup::$localeIds as $progressLoc => $l) { // create destination directories $dirError = false; foreach ($mapDirs as $md) { if (!CLISetup::writeDir($destDir . sprintf($md[0], strtolower(Util::$localeStrings[$l]) . '/'))) { $dirError = true; } } if ($modeMask & 0x4) { if (!CLISetup::writeDir('setup/generated/alphaMaps')) { $dirError = true; } } if ($dirError) { $success = false; CLISetup::log(' - complexImg: could not create map directories for locale ' . $l . '. skipping...', CLISetup::LOG_ERROR); continue; } // source for mapFiles $mapSrcDir = null; $locDirs = array_filter(CLISetup::$expectedPaths, function ($var) use($l) { return !$var || $var == $l; }); foreach ($locDirs as $mapLoc => $__) { if ($mapLoc) { // and trailing slash again $mapLoc .= '/'; } $p = sprintf($imgPath, $mapLoc) . $paths[0]; if (CLISetup::fileExists($p)) { CLISetup::log(' - using files from ' . ($mapLoc ?: '/') . ' for locale ' . Util::$localeStrings[$l], CLISetup::LOG_WARN); $mapSrcDir = $p . '/'; break; } } if ($mapSrcDir === null) { $success = false; CLISetup::log(' - no suitable localized map files found for locale ' . $l, CLISetup::LOG_ERROR); continue; } foreach ($wma as $progressArea => $areaEntry) { $curMap = $progressArea + count($wma) * $progressLoc; $progress = ' - ' . str_pad($curMap . '/' . $sumMaps, 10) . str_pad('(' . number_format($curMap * 100 / $sumMaps, 2) . '%)', 9); $wmaId = $areaEntry['Id']; $zoneId = $areaEntry['areaId']; $textureStr = $areaEntry['nameINT']; $path = $mapSrcDir . $textureStr; if (!CLISetup::fileExists($path)) { $success = false; CLISetup::log('worldmap file ' . $path . ' missing for selected locale ' . Util::$localeStrings[$l], CLISetup::LOG_ERROR); continue; } $fmt = array([1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]); CLISetup::log($textureStr . " [" . $zoneId . "]"); $overlay = $createAlphaImage($mapWidth, $mapHeight); // zone has overlays (is in open world; is not multiLeveled) if (isset($wmo[$wmaId])) { CLISetup::log(' - area has ' . count($wmo[$wmaId]) . ' overlays'); foreach ($wmo[$wmaId] as &$row) { $i = 1; $y = 0; while ($y < $row['h']) { $x = 0; while ($x < $row['w']) { $img = $loadImageFile($path . '/' . $row['textureString'] . $i); if (!$img) { CLISetup::log(' - complexImg: tile ' . $path . '/' . $row['textureString'] . $i . '.blp missing.', CLISetup::LOG_ERROR); break 2; } imagecopy($overlay, $img, $row['x'] + $x, $row['y'] + $y, 0, 0, imagesx($img), imagesy($img)); // prepare subzone image if ($modeMask & 0x10) { if (!isset($row['maskimage'])) { $row['maskimage'] = $createAlphaImage($row['w'], $row['h']); $row['maskcolor'] = imagecolorallocatealpha($row['maskimage'], 255, 64, 192, 64); } for ($my = 0; $my < imagesy($img); $my++) { for ($mx = 0; $mx < imagesx($img); $mx++) { if (imagecolorat($img, $mx, $my) >> 24 < $threshold) { imagesetpixel($row['maskimage'], $x + $mx, $y + $my, $row['maskcolor']); } } } } imagedestroy($img); $x += 256; $i++; } $y += 256; } } // create spawn-maps if wanted if ($modeMask & 0x4) { $createSpawnMap($overlay, $zoneId); } } // check, if the current zone is multiLeveled // if there are also files present without layer-suffix assume them as layer: 0 $multiLeveled = false; $multiLevel = 0; do { if (!CLISetup::filesInPath('/' . $textureStr . '\\/' . $textureStr . ($multiLevel + 1) . '_\\d\\.blp/i', true)) { break; } $multiLevel++; $multiLeveled = true; } while ($multiLevel < 18); // Karazhan has 17 frickin floors // check if we can create base map anyway $file = $path . '/' . $textureStr . '1.blp'; $hasBaseMap = CLISetup::fileExists($file); CLISetup::log(' - area has ' . ($multiLeveled ? $multiLevel . ' levels' : 'only base level')); $map = null; for ($i = 0; $i <= $multiLevel; $i++) { ini_set('max_execution_time', 120); // max 120sec per image $file = $path . '/' . $textureStr; if (!$i && !$hasBaseMap) { continue; } // if $multiLeveled also suffix -0 to baseMap if it exists if ($i && $multiLeveled) { $file .= $i . '_'; } $doSkip = 0x0; $outFile = []; foreach ($mapDirs as $idx => $info) { $outFile[$idx] = $destDir . sprintf($info[0], strtolower(Util::$localeStrings[$l]) . '/') . $zoneId; $floor = $i; if ($zoneId == 4100) { // ToCStratholme: map order fix $floor += 1; } if ($multiLeveled && !(isset($baseLevelFix[$zoneId]) && $i == $baseLevelFix[$zoneId])) { $outFile[$idx] .= '-' . $floor; } if (!isset(FileGen::$cliOpts['force']) && file_exists($outFile[$idx] . '.' . $info[1])) { CLISetup::log($progress . ' - file ' . $outFile[$idx] . '.' . $info[1] . ' was already processed'); $doSkip |= 1 << $idx; } } if ($doSkip == 0xf) { continue; } $map = $assembleImage($file, $fmt, $mapWidth, $mapHeight); if (!$map) { $success = false; CLISetup::log(' - could not create image resource for map ' . $zoneId . ($multiLevel ? ' level ' . $i : '')); continue; } if (!$multiLeveled) { imagecopymerge($map, $overlay, 0, 0, 0, 0, imagesx($overlay), imagesy($overlay), 100); imagedestroy($overlay); } // create map if ($modeMask & 0x2) { foreach ($mapDirs as $idx => $info) { if ($doSkip & 1 << $idx) { continue; } if (!$writeImage($outFile[$idx], $info[1], $map, $info[2] ?: $mapWidth, $info[3] ?: $mapHeight, $progress)) { $success = false; } } } } // also create subzone-maps if ($map && isset($wmo[$wmaId]) && $modeMask & 0x10) { foreach ($wmo[$wmaId] as &$row) { $doSkip = 0x0; $outFile = []; foreach ($mapDirs as $idx => $info) { $outFile[$idx] = $destDir . sprintf($info[0], strtolower(Util::$localeStrings[$l]) . '/') . $row['areaTableId']; if (!isset(FileGen::$cliOpts['force']) && file_exists($outFile[$idx] . '.' . $info[1])) { CLISetup::log($progress . ' - file ' . $outFile[$idx] . '.' . $info[1] . ' was already processed'); $doSkip |= 1 << $idx; } } if ($doSkip == 0xf) { continue; } $subZone = imagecreatetruecolor($mapWidth, $mapHeight); imagecopy($subZone, $map, 0, 0, 0, 0, imagesx($map), imagesy($map)); imagecopy($subZone, $row['maskimage'], $row['x'], $row['y'], 0, 0, imagesx($row['maskimage']), imagesy($row['maskimage'])); foreach ($mapDirs as $idx => $info) { if ($doSkip & 1 << $idx) { continue; } if (!$writeImage($outFile[$idx], $info[1], $subZone, $info[2] ?: $mapWidth, $info[3] ?: $mapHeight, $progress)) { $success = false; } } imagedestroy($subZone); } } if ($map) { imagedestroy($map); } } } } /***********/ /* Credits */ /***********/ if ($modeMask & 0x8) { if (CLISetup::writeDir($destDir . 'Interface/Glues/Credits/')) { // tile ordering $order = array(1 => array([1]), 2 => array([1], [2]), 4 => array([1, 2], [3, 4]), 6 => array([1, 2, 3], [4, 5, 6]), 8 => array([1, 2, 3, 4], [5, 6, 7, 8])); $imgGroups = []; $srcPath = sprintf($imgPath, $locStr) . 'Glues/Credits/'; $files = CLISetup::filesInPath($srcPath); foreach ($files as $f) { if (preg_match('/([^\\/]+)(\\d).blp/i', $f, $m)) { if ($m[1] && $m[2]) { if (!isset($imgGroups[$m[1]])) { $imgGroups[$m[1]] = $m[2]; } else { if ($imgGroups[$m[1]] < $m[2]) { $imgGroups[$m[1]] = $m[2]; } } } } } // errör-korrekt $imgGroups['Desolace'] = 4; $imgGroups['BloodElf_Female'] = 6; $total = count($imgGroups); $sum = 0; CLISetup::log('Processing ' . $total . ' files from Glues/Credits/...'); foreach ($imgGroups as $file => $fmt) { ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time) $sum++; $done = ' - ' . str_pad($sum . '/' . $total, 8) . str_pad('(' . number_format($sum * 100 / $total, 2) . '%)', 9); $name = $destDir . 'Interface/Glues/Credits/' . $file; if (!isset(FileGen::$cliOpts['force']) && file_exists($name . '.png')) { CLISetup::log($done . ' - file ' . $name . '.png was already processed'); continue; } if (!isset($order[$fmt])) { CLISetup::log(' - pattern for file ' . $name . ' not set. skipping', CLISetup::LOG_WARN); continue; } $im = $assembleImage($srcPath . $file, $order[$fmt], count($order[$fmt][0]) * 256, count($order[$fmt]) * 256); if (!$im) { CLISetup::log(' - could not assemble file ' . $name, CLISetup::LOG_ERROR); continue; } if (!$writeImage($name, 'png', $im, count($order[$fmt][0]) * 256, count($order[$fmt]) * 256, $done)) { $success = false; } } ini_set('max_execution_time', $runTime); } else { $success = false; } } return $success; }
public static function generate($tableName, array $updateIds = []) { if (!isset(self::$tables[$tableName])) { CLISetup::log('SqlGen::generate - invalid table given', CLISetup::LOG_ERROR); return false; } if (!empty(self::$tables[$tableName][0])) { $tbl = self::$tables[$tableName]; // shorthand CLISetup::log('SqlGen::generate() - copying ' . $tbl[0] . '.dbc into aowow_' . $tableName); $dbc = new DBC($tbl[0], CLISetup::$tmpDBC); if ($dbc->error) { return false; } $dbcData = $dbc->readArbitrary($tbl[1]); foreach ($dbcData as $row) { DB::Aowow()->query('REPLACE INTO ?_' . $tableName . ' (?#) VALUES (?a)', array_keys($row), array_values($row)); } return !!$dbcData; } else { if (file_exists('setup/tools/sqlgen/' . $tableName . '.func.php')) { $customData = $reqDBC = []; CLISetup::log('SqlGen::generate() - filling aowow_' . $tableName . ' with data'); require_once 'setup/tools/sqlgen/' . $tableName . '.func.php'; if (function_exists($tableName)) { // check for required auxiliary DBC files foreach ($reqDBC as $req) { if (!CLISetup::loadDBC($req)) { return false; } } $success = $tableName($updateIds); // apply post generator custom data foreach ($customData as $id => $data) { if ($data) { DB::Aowow()->query('UPDATE ?_' . $tableName . ' SET ?a WHERE id = ?d', $data, $id); } } } else { CLISetup::log(' - subscript \'' . $tableName . '\' not defined in included file', CLISetup::LOG_ERROR); } return $success; } else { CLISetup::log(sprintf(ERR_MISSING_INCL, $tableName, 'setup/tools/sqlgen/' . $tableName . '.func.php'), CLISetup::LOG_ERROR); } } }
public static function log($txt = '', $lvl = -1) { if (self::$logFile && !self::$logHandle) { if (!file_exists(self::$logFile)) { self::$logHandle = fopen(self::$logFile, 'w'); } else { $logFileParts = pathinfo(self::$logFile); $i = 1; while (file_exists($logFileParts['dirname'] . '/' . $logFileParts['filename'] . $i . (isset($logFileParts['extension']) ? '.' . $logFileParts['extension'] : ''))) { $i++; } self::$logFile = $logFileParts['dirname'] . '/' . $logFileParts['filename'] . $i . (isset($logFileParts['extension']) ? '.' . $logFileParts['extension'] : ''); self::$logHandle = fopen(self::$logFile, 'w'); } } $msg = "\n"; if ($txt) { $msg = str_pad(date('H:i:s'), 10); switch ($lvl) { case self::LOG_ERROR: // red critical error $msg .= '[' . self::red('ERR') . '] '; break; case self::LOG_WARN: // yellow notice $msg .= '[' . self::yellow('WARN') . '] '; break; case self::LOG_OK: // green success $msg .= '[' . self::green('OK') . '] '; break; case self::LOG_INFO: // blue info $msg .= '[' . self::blue('INFO') . '] '; break; default: $msg .= ' '; } $msg .= $txt . "\n"; } echo $msg; if (self::$logHandle) { // remove highlights for logging fwrite(self::$logHandle, preg_replace(["/\\[\\d+m/", "/\\[0m/"], '', $msg)); } flush(); }
function dbconfig() { $databases = ['aowow', 'world', 'auth', 'characters']; $AoWoWconf = []; $dbFields = array('host' => ['Server Host', false], 'user' => ['User', false], 'pass' => ['Password', true], 'db' => ['Database Name', false], 'prefix' => ['Table prefix', false]); $testDB = function ($idx, $name, $dbInfo) { $buff = '[' . CLISetup::bold($idx) . '] ' . str_pad($name, 17); $errStr = ''; if ($dbInfo['host']) { // test DB if ($link = @mysqli_connect($dbInfo['host'], $dbInfo['user'], $dbInfo['pass'], $dbInfo['db'])) { mysqli_close($link); } else { $errStr = '[' . mysqli_connect_errno() . '] ' . mysqli_connect_error(); } $buff .= $errStr ? CLISetup::red('ERR ') : CLISetup::green('OK '); $buff .= 'mysqli://' . $dbInfo['user'] . ':' . str_pad('', strlen($dbInfo['pass']), '*') . '@' . $dbInfo['host'] . '/' . $dbInfo['db']; $buff .= ($dbInfo['prefix'] ? ' table prefix: ' . $dbInfo['prefix'] : null) . ' ' . $errStr; } else { $buff .= ' ' . CLISetup::bold('<empty>'); } return $buff; }; if (file_exists('config/config.php')) { require 'config/config.php'; } foreach ($databases as $idx => $name) { if (empty($AoWoWconf[$name]) && $name != 'characters') { $AoWoWconf[$name] = array_combine(array_keys($dbFields), ['', '', '', '', '']); } } while (true) { CLISetup::log(); CLISetup::log("select a numerical index to use the corresponding entry"); $nCharDBs = 0; foreach ($databases as $idx => $name) { if ($idx != 3) { CLISetup::log($testDB($idx, $name, $AoWoWconf[$name])); } else { if (!empty($AoWoWconf[$name])) { foreach ($AoWoWconf[$name] as $charIdx => $dbInfo) { CLISetup::log($testDB($idx + $nCharDBs++, $name . ' [' . $charIdx . ']', $AoWoWconf[$name][$charIdx])); } } } } CLISetup::log("[" . CLISetup::bold(3 + $nCharDBs) . "] add an additional Character DB"); while (true) { $inp = ['idx' => ['', true, '/\\d/']]; if (CLISetup::readInput($inp, true) && $inp) { if ($inp['idx'] >= 0 && $inp['idx'] <= 3 + $nCharDBs) { $curFields = $dbFields; if ($inp['idx'] == 3 + $nCharDBs) { // add new realmDB $curFields['realmId'] = ['Realm Id', false, '/[1-9][0-9]*/']; } if (CLISetup::readInput($curFields)) { // auth, world or aowow if ($inp['idx'] < 3) { $AoWoWconf[$databases[$inp['idx']]] = $curFields ?: array_combine(array_keys($dbFields), ['', '', '', '', '']); } else { if ($inp['idx'] == 3 + $nCharDBs) { if ($curFields) { $_ = $curFields['realmId']; unset($curFields['realmId']); $AoWoWconf[$databases[3]][$_] = $curFields; } } else { $i = 0; foreach ($AoWoWconf[$databases[3]] as $realmId => &$dbInfo) { if ($inp['idx'] - 3 != $i++) { continue; } if ($curFields) { $dbInfo = $curFields; } else { unset($AoWoWconf[$databases[3]][$realmId]); } } } } // write config file $buff = "<?php\n\nif (!defined('AOWOW_REVISION'))\n die('illegal access');\n\n\n"; foreach ($databases as $db) { if ($db != 'characters') { $buff .= '$AoWoWconf[\'' . $db . '\'] = ' . var_export($AoWoWconf[$db], true) . ";\n\n"; } else { foreach ($AoWoWconf[$db] as $idx => $charInfo) { $buff .= '$AoWoWconf[\'' . $db . '\'][\'' . $idx . '\'] = ' . var_export($AoWoWconf[$db][$idx], true) . ";\n\n"; } } } $buff .= "?>\n"; CLISetup::log(); CLISetup::writeFile('config/config.php', $buff); continue 2; } else { CLISetup::log(); CLISetup::log("edit canceled! returning to list...", CLISetup::LOG_WARN); sleep(1); continue 2; } } } else { CLISetup::log(); CLISetup::log("db setup aborted", CLISetup::LOG_WARN); break 2; } } } }
public static function generate($key, array $updateIds = []) { $success = false; $reqDBC = []; if (file_exists('setup/tools/filegen/' . $key . '.func.php')) { require_once 'setup/tools/filegen/' . $key . '.func.php'; } else { if (empty(self::$tplFiles[$key])) { CLISetup::log(sprintf(ERR_MISSING_INCL, $key, 'setup/tools/filegen/' . $key . '.func.php', CLISetup::LOG_ERROR)); return false; } } CLISetup::log('FileGen::generate() - gathering data for ' . $key); if (!empty(self::$tplFiles[$key])) { list($file, $destPath, $deps) = self::$tplFiles[$key]; if ($content = file_get_contents(FileGen::$tplPath . $file . '.in')) { if ($dest = @fOpen($destPath . $file, "w")) { // replace constants $content = strtr($content, FileGen::$txtConstants); // check for required auxiliary DBC files foreach ($reqDBC as $req) { if (!CLISetup::loadDBC($req)) { continue 2; } } // must generate content // PH format: /*setup:<setupFunc>*/ $funcOK = true; if (preg_match_all('/\\/\\*setup:([\\w\\-_]+)\\*\\//i', $content, $m)) { foreach ($m[1] as $func) { if (function_exists($func)) { $content = str_replace('/*setup:' . $func . '*/', $func(), $content); } else { $funcOK = false; CLISetup::log('No function for was registered for placeholder ' . $func . '().', CLISetup::LOG_ERROR); if (!array_reduce(get_included_files(), function ($inArray, $itr) use($func) { return $inArray || false !== strpos($itr, $func); }, false)) { CLISetup::log('Also, expected include setup/tools/filegen/' . $name . '.func.php was not found.'); } } } } if (fWrite($dest, $content)) { CLISetup::log(sprintf(ERR_NONE, CLISetup::bold($destPath . $file)), CLISetup::LOG_OK); if ($content && $funcOK) { $success = true; } } else { CLISetup::log(sprintf(ERR_WRITE_FILE, CLISetup::bold($destPath . $file)), CLISetup::LOG_ERROR); } fClose($dest); } else { CLISetup::log(sprintf(ERR_CREATE_FILE, CLISetup::bold($destPath . $file)), CLISetup::LOG_ERROR); } } else { CLISetup::log(sprintf(ERR_READ_FILE, CLISetup::bold(FileGen::$tplPath . $file . '.in')), CLISetup::LOG_ERROR); } } else { if (!empty(self::$datasets[$key])) { if (function_exists($key)) { // check for required auxiliary DBC files foreach ($reqDBC as $req) { if (!CLISetup::loadDBC($req)) { return false; } } $success = $key($updateIds); } else { CLISetup::log(' - subscript \'' . $key . '\' not defined in included file', CLISetup::LOG_ERROR); } } } set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script return $success; }
function source(array $ids = []) { $insBasic = 'INSERT INTO ?_source (`type`, typeId, src?d) VALUES [V] ON DUPLICATE KEY UPDATE moreType = NULL, moreTypeId = NULL, src?d = VALUES(src?d)'; $insMore = 'INSERT INTO ?_source (`type`, typeId, src?d, moreType, moreTypeId) VALUES [V] ON DUPLICATE KEY UPDATE moreType = NULL, moreTypeId = NULL, src?d = VALUES(src?d)'; $insSub = 'INSERT INTO ?_source (`type`, typeId, src?d, moreType, moreTypeId) ?s ON DUPLICATE KEY UPDATE moreType = NULL, moreTypeId = NULL, src?d = VALUES(src?d)'; // please note, this workes without checks, because we do not use strings here function queryfy($ph, array $data, $query) { $buff = []; array_walk_recursive($data, function (&$item) { if ($item === null) { $item = 'NULL'; } }); foreach ($data as $d) { $buff[] = '(' . implode(', ', $d ?: 'NULL') . ')'; } return str_replace($ph, implode(', ', $buff), $query); } function pushBuffer(&$buff, $type, $typeId, $mType = 0, $mTypeId = 0, $src = 1) { $b =& $buff[$typeId]; if (isset($b) && $b[3] === null) { return; } else { if (isset($b) && $b[1] != $typeId) { $b[3] = $b[4] = null; $b[2] |= $src; // only quests atm } else { if ($mType && $mTypeId) { $b = [$type, $typeId, $src, $mType, $mTypeId]; } else { $b = [$type, $typeId, $src, null, null]; } } } } function taughtSpell($item) { # spelltrigger_X (0: onUse; 6: onLearnSpell) # spell: 483 & 55884 are learn spells // should not be able to teach spells (recipe || mount || vanityPet) if ($item['class'] != ITEM_CLASS_RECIPE && ($item['class'] != ITEM_CLASS_MISC || $item['subclass'] != 2 && $item['subclass'] != 5)) { return 0; } // wotlk system if (($item['spellid_1'] == 483 || $item['spellid_1'] == 55884) && $item['spelltrigger_1'] == 0 && $item['spellid_2'] > 0 && $item['spelltrigger_2'] == 6) { return $item['spellid_2']; } // deprecated system if ($item['spellid_1'] != 483 && $item['spellid_1'] != 55884 && $item['spellid_1'] > 0 && $item['spelltrigger_1'] == 0) { return $item['spellid_1']; } return 0; } // cant update existing rows if ($ids) { DB::Aowow()->query('DELETE FROM ?_source WHERE `type` = ?d AND typeId IN (?a)', $well, $wellll); } else { DB::Aowow()->query('TRUNCATE TABLE ?_source'); } /***************************/ /* Item & inherited Spells */ /***************************/ CLISetup::log(' - Items & Spells [inherited]'); # also everything from items that teach spells, is src of spell # todo: check if items have learn-spells (effect: 36) CLISetup::log(' * resolve ref-loot tree'); $refLoot = DB::World()->select(' SELECT rlt.Entry AS ARRAY_KEY, IF(Reference, -Reference, Item) AS ARRAY_KEY2, it.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, COUNT(1) AS qty FROM reference_loot_template rlt LEFT JOIN item_template it ON rlt.Reference = 0 AND rlt.Item = it.entry GROUP BY ARRAY_KEY, ARRAY_KEY2 '); $hasChanged = true; while ($hasChanged) { $hasChanged = false; foreach ($refLoot as $entry => &$refData) { foreach ($refData as $itemOrRef => $data) { if ($itemOrRef > 0) { continue; } if (!empty($refLoot[-$itemOrRef])) { foreach ($refLoot[-$itemOrRef] as $key => $data) { if (!empty($refData[$key])) { $refData[$key]['qty'] += $data['qty']; } else { $refLoot[-$itemOrRef][$key] = $data; } } } unset($refData[$itemOrRef]); $hasChanged = true; } } } ############### # 1: Crafted # ############### CLISetup::log(' * #1 Crafted'); $spellBuff = []; $itemBuff = []; $itemSpells = DB::Aowow()->selectCol(' SELECT effect1CreateItemId AS ARRAY_KEY, s.id AS spell FROM dbc_spell s JOIN dbc_skilllineability sla ON s.id = sla.spellId WHERE effect1CreateItemId > 0 AND sla.skillLineId IN (?a) GROUP BY ARRAY_KEY', [164, 165, 171, 182, 186, 197, 202, 333, 393, 755, 773, 129, 185, 356, 762]); $spellItems = DB::World()->select('SELECT entry AS ARRAY_KEY, class, subclass, spellid_1, spelltrigger_1, spellid_2, spelltrigger_2 FROM item_template WHERE entry IN (?a)', array_keys($itemSpells)); foreach ($spellItems as $iId => $si) { if ($_ = taughtSpell($si)) { $spellBuff[$_] = [TYPE_SPELL, $_, 1, TYPE_SPELL, $itemSpells[$iId]]; } $itemBuff[$iId] = [TYPE_ITEM, $iId, 1, TYPE_SPELL, $itemSpells[$iId]]; } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 1, 1, 1); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 1, 1, 1); } ############ # 2: Drop # ############ CLISetup::log(' * #2 Drop'); $spellBuff = []; $itemBuff = []; $creatureLoot = DB::World()->select(' SELECT IF(clt.Reference > 0, -clt.Reference, clt.Item) AS ARRAY_KEY, ct.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) AS qty FROM creature_loot_template clt JOIN creature_template ct ON clt.entry = ct.lootid LEFT JOIN item_template it ON it.entry = clt.Item AND clt.Reference <= 0 WHERE ct.lootid > 0 GROUP BY ARRAY_KEY '); foreach ($creatureLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } $objectOT = []; $exclLocks = DB::Aowow()->selectCol('SELECT id FROM dbc_lock WHERE properties1 IN (2, 3)'); $objectLoot = DB::World()->select(' SELECT IF(glt.Reference > 0, -glt.Reference, glt.Item) AS ARRAY_KEY, gt.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) AS qty FROM gameobject_loot_template glt JOIN gameobject_template gt ON glt.entry = gt.Data1 LEFT JOIN item_template it ON it.entry = glt.Item AND glt.Reference <= 0 WHERE `type` = 3 AND gt.Data1 > 0 AND gt.Data0 NOT IN (?a) GROUP BY ARRAY_KEY', $exclLocks); foreach ($objectLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } $objectOT[] = $iId; pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } $objectOT[] = $roi; pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } $itemOT = []; $itemLoot = DB::World()->select(' SELECT IF(ilt.Reference > 0, -ilt.Reference, ilt.Item) AS ARRAY_KEY, itA.entry, itB.class, itB.subclass, itB.spellid_1, itB.spelltrigger_1, itB.spellid_2, itB.spelltrigger_2, count(1) AS qty FROM item_loot_template ilt JOIN item_template itA ON ilt.entry = itA.entry LEFT JOIN item_template itB ON itB.entry = ilt.Item AND ilt.Reference <= 0 WHERE itA.flags & 0x4 GROUP BY ARRAY_KEY '); foreach ($itemLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']); } $itemOT[] = $iId; pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']); } $itemOT[] = $roi; pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_ITEM, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 2, 2, 2); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 2, 2, 2); } DB::Aowow()->query('UPDATE ?_items SET cuFLags = cuFlags | ?d WHERE id IN (?a)', ITEM_CU_OT_ITEMLOOT, $itemOT); DB::Aowow()->query('UPDATE ?_items SET cuFLags = cuFlags | ?d WHERE id IN (?a)', ITEM_CU_OT_OBJECTLOOT, $objectOT); ########### # 3: PvP # (Vendors w/ xCost Arena/Honor) ########### CLISetup::log(' * #3 PvP'); // var g_sources_pvp = { // 1: 'Arena', // 2: 'Battleground', // 4: 'World' basicly the tokens you get for openPvP .. manual data // }; $spellBuff = []; $itemBuff = []; $xCostH = DB::Aowow()->selectCol('SELECT Id FROM dbc_itemextendedcost WHERE reqHonorPoints > 0 AND reqArenaPoints = 0'); $xCostA = DB::Aowow()->selectCol('SELECT Id FROM dbc_itemextendedcost WHERE reqArenaPoints > 0'); $vendorQuery = 'SELECT n.item AS ARRAY_KEY, SUM(n.qty) AS qty, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2 FROM ( SELECT item, COUNT(1) AS qty FROM npc_vendor WHERE ExtendedCost IN (?a) GROUP BY item UNION SELECT item, COUNT(1) AS qty FROM game_event_npc_vendor genv JOIN creature c ON c.guid = genv.guid WHERE ExtendedCost IN (?a) GROUP BY item ) n JOIN item_template it ON it.entry = n.item GROUP BY item'; foreach (DB::World()->select($vendorQuery, $xCostA, $xCostA) as $iId => $v) { if ($_ = taughtSpell($v)) { $spellBuff[$_] = [TYPE_SPELL, $_, 1]; } $itemBuff[$iId] = [TYPE_ITEM, $iId, 1]; } foreach (DB::World()->select($vendorQuery, $xCostH, $xCostH) as $iId => $v) { if ($_ = taughtSpell($v)) { $spellBuff[$_] = [TYPE_SPELL, $_, 2]; } $itemBuff[$iId] = [TYPE_ITEM, $iId, 2]; } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insBasic), 3, 3, 3); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insBasic), 3, 3, 3); } ############# # 4: Quest # ############# CLISetup::log(' * #4 Quest'); $spellBuff = []; $itemBuff = []; $quests = DB::World()->select('SELECT n.item AS ARRAY_KEY, n.ID AS quest, SUM(n.qty) AS qty, BIT_OR(n.side) AS side, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2 FROM ( SELECT RewardChoiceItemID1 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID1 > 0 GROUP BY item UNION SELECT RewardChoiceItemID2 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID2 > 0 GROUP BY item UNION SELECT RewardChoiceItemID3 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID3 > 0 GROUP BY item UNION SELECT RewardChoiceItemID4 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID4 > 0 GROUP BY item UNION SELECT RewardChoiceItemID5 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID5 > 0 GROUP BY item UNION SELECT RewardChoiceItemID6 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardChoiceItemID6 > 0 GROUP BY item UNION SELECT RewardItem1 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardItem1 > 0 GROUP BY item UNION SELECT RewardItem2 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardItem2 > 0 GROUP BY item UNION SELECT RewardItem3 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardItem3 > 0 GROUP BY item UNION SELECT RewardItem4 AS item, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE RewardItem4 > 0 GROUP BY item ) n JOIN item_template it ON it.entry = n.item GROUP BY item'); foreach ($quests as $iId => $q) { if ($_ = taughtSpell($q)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $q['qty'] > 1 ? 0 : TYPE_QUEST, $q['quest'], $q['side']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $q['qty'] > 1 ? 0 : TYPE_QUEST, $q['quest'], $q['side']); } $mailLoot = DB::World()->select(' SELECT IF(mlt.Reference > 0, -mlt.Reference, mlt.Item) AS ARRAY_KEY, qt.ID AS entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) AS qty, BIT_OR(IF(qt.RequiredRaces & 0x2B2 AND !(qt.RequiredRaces & 0x44D), 2, IF(qt.RequiredRaces & 0x44D AND !(qt.RequiredRaces & 0x2B2), 1, 3))) AS side FROM mail_loot_template mlt JOIN quest_template qt ON qt.RewardMailTemplateId = mlt.entry LEFT JOIN item_template it ON it.entry = mlt.Item AND mlt.Reference <= 0 WHERE qt.RewardMailTemplateId > 0 GROUP BY ARRAY_KEY '); foreach ($mailLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']); } $itemOT[] = $iId; pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']); } $itemOT[] = $roi; pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_QUEST, $l['entry'], $l['side']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 4, 4, 4); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 4, 4, 4); } ############## # 5: Vendor # (w/o xCost Arena/Honor) ############## CLISetup::log(' * #5 Vendor'); $spellBuff = []; $itemBuff = []; $xCostIds = DB::Aowow()->selectCol('SELECT Id FROM dbc_itemextendedcost WHERE reqHonorPoints <> 0 OR reqArenaPoints <> 0'); $vendors = DB::World()->select('SELECT n.item AS ARRAY_KEY, n.npc, SUM(n.qty) AS qty, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2 FROM ( SELECT item, entry AS npc, COUNT(1) AS qty FROM npc_vendor WHERE ExtendedCost NOT IN (?a) GROUP BY item UNION SELECT item, c.id AS npc, COUNT(1) AS qty FROM game_event_npc_vendor genv JOIN creature c ON c.guid = genv.guid WHERE ExtendedCost NOT IN (?a) GROUP BY item ) n JOIN item_template it ON it.entry = n.item GROUP BY item', $xCostIds, $xCostIds); foreach ($vendors as $iId => $v) { if ($_ = taughtSpell($v)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $v['qty'] > 1 ? 0 : TYPE_NPC, $v['npc']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $v['qty'] > 1 ? 0 : TYPE_NPC, $v['npc']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 5, 5, 5); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 5, 5, 5); } ############### # 10: Starter # ############### CLISetup::log(' * #10 Starter'); if ($pcii = DB::World()->select('SELECT ?d, itemid, 1 FROM playercreateinfo_item', TYPE_ITEM)) { DB::Aowow()->query(queryfy('[V]', $pcii, $insBasic), 10, 10, 10); } for ($i = 1; $i < 21; $i++) { DB::Aowow()->query($insSub, 10, DB::Aowow()->subquery('SELECT ?d, item?d, 1, NULL AS m, NULL AS mt FROM dbc_charstartoutfit WHERE item?d > 0', TYPE_ITEM, $i, $i), 10, 10); } ################### # 12: Achievement # ################### CLISetup::log(' * #12 Achievement'); $spellBuff = []; $itemBuff = []; $xItems = DB::Aowow()->select('SELECT id AS entry, itemExtra AS ARRAY_KEY, COUNT(1) AS qty FROM ?_achievement WHERE itemExtra > 0 GROUP BY itemExtra'); $rewItems = DB::World()->select(' SELECT src.item AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, COUNT(1) AS qty FROM ( SELECT IFNULL(IF(mlt.Reference > 0, -mlt.Reference, mlt.Item), ar.item) AS item, ar.entry FROM achievement_reward ar LEFT JOIN mail_loot_template mlt ON mlt.entry = ar.mailTemplate WHERE ar.mailTemplate > 0 OR ar.item > 0 ) src LEFT JOIN item_template it ON src.item = it.entry GROUP BY ARRAY_KEY '); $extraItems = DB::World()->select('SELECT entry AS ARRAY_KEY, class, subclass, spellid_1, spelltrigger_1, spellid_2, spelltrigger_2 FROM item_template WHERE entry IN (?a)', array_keys($xItems)); foreach ($extraItems as $iId => $l) { if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $xItems[$iId]['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $xItems[$iId]['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $xItems[$iId]['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $xItems[$iId]['entry']); } foreach ($rewItems as $iId => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $l['qty'] > 1 ? 0 : TYPE_ACHIEVEMENT, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 12, 12, 12); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 12, 12, 12); } #################### # 15: Disenchanted # #################### CLISetup::log(' * #15 Disenchanted'); $spellBuff = []; $itemBuff = []; $deLoot = DB::World()->select(' SELECT IF(dlt.Reference > 0, -dlt.Reference, dlt.Item) AS ARRAY_KEY, itA.entry, itB.class, itB.subclass, itB.spellid_1, itB.spelltrigger_1, itB.spellid_2, itB.spelltrigger_2, count(1) AS qty FROM disenchant_loot_template dlt JOIN item_template itA ON dlt.entry = itA.DisenchantId LEFT JOIN item_template itB ON itB.entry = dlt.Item AND dlt.Reference <= 0 WHERE itA.DisenchantId > 0 GROUP BY ARRAY_KEY '); foreach ($deLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $iId); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $roi); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 15, 15, 15); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 15, 15, 15); } ############## # 16: Fished # ############## CLISetup::log(' * #16 Fished'); $spellBuff = []; $itemBuff = []; $fishLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) AS qty FROM ( SELECT 0 AS entry, IF(flt.Reference > 0, -flt.Reference, flt.Item) itemOrRef FROM fishing_loot_template flt UNION SELECT gt.entry, IF(glt.Reference > 0, -glt.Reference, glt.Item) itemOrRef FROM gameobject_template gt JOIN gameobject_loot_template glt ON glt.entry = gt.Data1 WHERE `type` = 25 AND gt.Data1 > 0 ) src LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry GROUP BY ARRAY_KEY '); foreach ($fishLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_OBJECT, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 16, 16, 16); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 16, 16, 16); } ################ # 17: Gathered # ################ CLISetup::log(' * #17 Gathered'); $spellBuff = []; $itemBuff = []; $herbLocks = DB::Aowow()->selectCol('SELECT id FROM dbc_lock WHERE properties1 = 2'); $herbLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) AS qty, src.srcType FROM ( SELECT ct.entry, IF(slt.Reference > 0, -slt.Reference, slt.Item) itemOrRef, ?d AS srcType FROM creature_template ct JOIN skinning_loot_template slt ON slt.entry = ct.skinloot WHERE (type_flags & ?d) AND ct.skinloot > 0 UNION SELECT gt.entry, IF(glt.Reference > 0, -glt.Reference, glt.Item) itemOrRef, ?d AS srcType FROM gameobject_template gt JOIN gameobject_loot_template glt ON glt.entry = gt.Data1 WHERE gt.`type` = 3 AND gt.Data1 > 0 AND Data0 IN (?a) ) src LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry GROUP BY ARRAY_KEY', TYPE_NPC, NPC_TYPEFLAG_HERBLOOT, TYPE_OBJECT, $herbLocks); foreach ($herbLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 17, 17, 17); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 17, 17, 17); } ############## # 18: Milled # ############## CLISetup::log(' * #18 Milled'); $spellBuff = []; $itemBuff = []; $millLoot = DB::World()->select(' SELECT IF(mlt.Reference > 0, -mlt.Reference, mlt.Item) AS ARRAY_KEY, itA.entry, itB.class, itB.subclass, itB.spellid_1, itB.spelltrigger_1, itB.spellid_2, itB.spelltrigger_2, count(1) AS qty FROM milling_loot_template mlt JOIN item_template itA ON mlt.entry = itA.entry LEFT JOIN item_template itB ON itB.entry = mlt.Item AND mlt.Reference <= 0 GROUP BY ARRAY_KEY '); foreach ($millLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $iId); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $roi); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 18, 18, 18); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 18, 18, 18); } ############# # 19: Mined # ############# CLISetup::log(' * #19 Mined'); $spellBuff = []; $itemBuff = []; $mineLocks = DB::Aowow()->selectCol('SELECT id FROM dbc_lock WHERE properties1 = 3'); $mineLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, count(1) AS qty, src.srcType FROM ( SELECT ct.entry, IF(slt.Reference > 0, -slt.Reference, slt.Item) itemOrRef, ?d AS srcType FROM creature_template ct JOIN skinning_loot_template slt ON slt.entry = ct.skinloot WHERE (type_flags & ?d) AND ct.skinloot > 0 UNION SELECT gt.entry, IF(glt.Reference > 0, -glt.Reference, glt.Item) itemOrRef, ?d AS srcType FROM gameobject_template gt JOIN gameobject_loot_template glt ON glt.entry = gt.Data1 WHERE gt.`type` = 3 AND gt.Data1 > 0 AND Data0 IN (?a) ) src LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry GROUP BY ARRAY_KEY', TYPE_NPC, NPC_TYPEFLAG_MININGLOOT, TYPE_OBJECT, $mineLocks); foreach ($mineLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : $l['srcType'], $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 19, 19, 19); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 19, 19, 19); } ################## # 20: Prospected # ################## CLISetup::log(' * #20 Prospected'); $spellBuff = []; $itemBuff = []; $prospectLoot = DB::World()->select(' SELECT IF(plt.Reference > 0, -plt.Reference, plt.Item) AS ARRAY_KEY, itA.entry, itB.class, itB.subclass, itB.spellid_1, itB.spelltrigger_1, itB.spellid_2, itB.spelltrigger_2, count(1) AS qty FROM prospecting_loot_template plt JOIN item_template itA ON plt.entry = itA.entry LEFT JOIN item_template itB ON itB.entry = plt.Item AND plt.Reference <= 0 GROUP BY ARRAY_KEY '); foreach ($prospectLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $iId); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_); } pushBuffer($itemBuff, TYPE_ITEM, $roi); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 20, 20, 20); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 20, 20, 20); } ################## # 21: Pickpocket # ################## CLISetup::log(' * #21 Pickpocket'); $spellBuff = []; $itemBuff = []; $theftLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, COUNT(1) AS qty FROM ( SELECT ct.entry, IF(plt.Reference > 0, -plt.Reference, plt.Item) itemOrRef FROM creature_template ct JOIN pickpocketing_loot_template plt ON plt.entry = ct.pickpocketloot WHERE ct.pickpocketloot > 0 ) src LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry GROUP BY ARRAY_KEY '); foreach ($theftLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 21, 21, 21); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 21, 21, 21); } ################ # 22: Salvaged # ################ CLISetup::log(' * #22 Salvaged'); $spellBuff = []; $itemBuff = []; $salvageLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, COUNT(1) AS qty FROM ( SELECT ct.entry, IF(slt.Reference > 0, -slt.Reference, slt.Item) itemOrRef FROM creature_template ct JOIN skinning_loot_template slt ON slt.entry = ct.skinloot WHERE (type_flags & ?d) AND ct.skinloot > 0 ) src LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry GROUP BY ARRAY_KEY', NPC_TYPEFLAG_ENGINEERLOOT); foreach ($salvageLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 22, 22, 22); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 22, 22, 22); } ############### # 23: Skinned # ############### CLISetup::log(' * #23 Skinned'); $spellBuff = []; $itemBuff = []; $skinLoot = DB::World()->select(' SELECT src.itemOrRef AS ARRAY_KEY, src.entry, it.class, it.subclass, it.spellid_1, it.spelltrigger_1, it.spellid_2, it.spelltrigger_2, COUNT(1) AS qty FROM ( SELECT ct.entry, IF(slt.Reference > 0, -slt.Reference, slt.Item) itemOrRef FROM creature_template ct JOIN skinning_loot_template slt ON slt.entry = ct.skinloot WHERE (type_flags & ?d) = 0 AND ct.skinloot > 0 ) src LEFT JOIN item_template it ON src.itemOrRef > 0 AND src.itemOrRef = it.entry GROUP BY ARRAY_KEY', NPC_TYPEFLAG_HERBLOOT | NPC_TYPEFLAG_MININGLOOT | NPC_TYPEFLAG_ENGINEERLOOT); foreach ($skinLoot as $roi => $l) { if ($roi < 0 && !empty($refLoot[-$roi])) { foreach ($refLoot[-$roi] as $iId => $r) { if ($_ = taughtSpell($r)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $iId, $r['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } continue; } if ($_ = taughtSpell($l)) { pushBuffer($spellBuff, TYPE_SPELL, $_, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } pushBuffer($itemBuff, TYPE_ITEM, $roi, $l['qty'] > 1 ? 0 : TYPE_NPC, $l['entry']); } if ($itemBuff) { DB::Aowow()->query(queryfy('[V]', $itemBuff, $insMore), 23, 23, 23); } if ($spellBuff) { DB::Aowow()->query(queryfy('[V]', $spellBuff, $insMore), 23, 23, 23); } /*********/ /* Spell */ /*********/ CLISetup::log(' - Spells [original]'); # 4: Quest CLISetup::log(' * #4 Quest'); $quests = DB::World()->select(' SELECT spell AS ARRAY_KEY, id, SUM(qty) AS qty, BIT_OR(side) AS side FROM ( SELECT IF(rewardSpellCast = 0, rewardSpell, rewardSpellCast) AS spell, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE IF(rewardSpellCast = 0, rewardSpell, rewardSpellCast) > 0 GROUP BY spell UNION SELECT SourceSpellId AS spell, ID, COUNT(1) AS qty, IF(RequiredRaces & 0x2B2 AND !(RequiredRaces & 0x44D), 2, IF(RequiredRaces & 0x44D AND !(RequiredRaces & 0x2B2), 1, 3)) AS side FROM quest_template WHERE SourceSpellId > 0 GROUP BY spell ) t GROUP BY spell'); if ($quests) { $qSpells = DB::Aowow()->select('SELECT id AS ARRAY_KEY, effect1Id, effect2Id, effect3Id, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell FROM dbc_spell WHERE id IN (?a) AND (effect1Id = 36 OR effect2Id = 36 OR effect3Id = 36)', array_keys($quests)); $buff = []; foreach ($qSpells as $sId => $spell) { for ($i = 1; $i <= 3; $i++) { if ($spell['effect' . $i . 'Id'] != 36) { // effect: learnSpell continue; } pushBuffer($buff, TYPE_SPELL, $spell['effect' . $i . 'TriggerSpell'], $quests[$sId]['qty'] > 1 ? 0 : TYPE_QUEST, $quests[$sId]['qty'] > 1 ? 0 : $quests[$sId]['id'], $quests[$sId]['side']); } } DB::Aowow()->query(queryfy('[V]', $buff, $insMore), 4, 4, 4); } # 6: Trainer CLISetup::log(' * #6 Trainer'); if ($tNpcs = DB::World()->select('SELECT SpellID AS ARRAY_KEY, ID AS entry, COUNT(1) AS qty FROM npc_trainer WHERE SpellID > 0 GROUP BY ARRAY_KEY')) { $tSpells = DB::Aowow()->select('SELECT Id AS ARRAY_KEY, effect1Id, effect2Id, effect3Id, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell FROM dbc_spell WHERE Id IN (?a)', array_keys($tNpcs)); $buff = []; // todo (med): this skips some spells (e.g. riding) foreach ($tNpcs as $spellId => $npc) { if (!isset($tSpells[$spellId])) { continue; } $effects = $tSpells[$spellId]; $trainerId = $npc['entry'] > 200000 || $npc['qty'] > 1 ? null : $npc['entry']; $triggered = false; for ($i = 1; $i <= 3; $i++) { if ($effects['effect' . $i . 'Id'] != 36) { // effect: learnSpell continue; } $triggered = true; pushBuffer($buff, TYPE_SPELL, $effects['effect' . $i . 'TriggerSpell'], $trainerId ? TYPE_NPC : 0, $trainerId); } if (!$triggered) { pushBuffer($buff, TYPE_SPELL, $spellId, $trainerId ? TYPE_NPC : 0, $trainerId); } } DB::Aowow()->query(queryfy('[V]', $buff, $insMore), 6, 6, 6); } # 7: Discovery CLISetup::log(' * #7 Discovery'); // 61756: Northrend Inscription Research (FAST QA VERSION); if ($disco = DB::World()->select('SELECT ?d, spellId, 1 FROM skill_discovery_template WHERE reqSpell <> ?d', TYPE_SPELL, 61756)) { DB::Aowow()->query(queryfy('[V]', $disco, $insBasic), 7, 7, 7); } # 9: Talent CLISetup::log(' * #9 Talent'); $tSpells = DB::Aowow()->select(' SELECT s.Id AS ARRAY_KEY, s.effect1Id, s.effect2Id, s.effect3Id, s.effect1TriggerSpell, s.effect2TriggerSpell, s.effect3TriggerSpell FROM dbc_talent t JOIN dbc_spell s ON s.Id = t.rank1 WHERE t.rank2 < 1 AND (t.talentSpell = 1 OR (s.effect1Id = 36 OR s.effect2Id = 36 OR s.effect3Id = 36)) '); $n = 0; $buff = []; while ($tSpells) { CLISetup::log(' - ' . ++$n . '. pass'); $recurse = []; foreach ($tSpells as $tId => $spell) { for ($i = 1; $i <= 3; $i++) { if ($spell['effect' . $i . 'Id'] == 36) { // effect: learnSpell $recurse[$spell['effect' . $i . 'TriggerSpell']] = $tId; } } if (array_search($tId, $recurse)) { unset($tSpells[$tId]); } } foreach ($tSpells as $tId => $__) { $buff[$tId] = [TYPE_SPELL, $tId, 1]; } if (!$recurse) { break; } $tSpells = DB::Aowow()->select('SELECT Id AS ARRAY_KEY, effect1Id, effect2Id, effect3Id, effect1TriggerSpell, effect2TriggerSpell, effect3TriggerSpell FROM dbc_spell WHERE Id IN (?a)', array_keys($recurse)); } DB::Aowow()->query(queryfy('[V]', $buff, $insBasic), 9, 9, 9); # 10: Starter CLISetup::log(' * #10 Starter'); /* acquireMethod ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1, learnedAt = 1 && source10 = 1 ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2 not used for now */ $subSkills = DB::Aowow()->subquery('SELECT ?d, spellId, 1, NULL AS m, NULL AS mt FROM dbc_skilllineability WHERE acquireMethod = 1 AND (reqSkillLevel = 1 OR skillLineId = 129) GROUP BY spellId', TYPE_SPELL); DB::Aowow()->query($insSub, 10, $subSkills, 10, 10); if ($pcis = DB::World()->select('SELECT ?d, Spell, 1 FROM playercreateinfo_spell', TYPE_SPELL)) { DB::Aowow()->query(queryfy('[V]', $pcis, $insBasic), 10, 10, 10); } /**********/ /* Titles */ /**********/ CLISetup::log(' - Titles'); # 4: Quest CLISetup::log(' * #4 Quest'); if ($quests = DB::World()->select('SELECT ?d, RewardTitle, 1, ?d, ID FROM quest_template WHERE RewardTitle > 0', TYPE_TITLE, TYPE_QUEST)) { DB::Aowow()->query(queryfy('[V]', $quests, $insMore), 4, 4, 4); } # 12: Achievement CLISetup::log(' * #12 Achievement'); $sets = DB::World()->select(' SELECT ?d, IF (title_A <> 0, title_A, title_H) AS title, 1, ?d, entry FROM achievement_reward WHERE title_A <> 0 OR title_H <> 0 GROUP BY title UNION SELECT ?d, title_H AS title, 1, ?d, entry FROM achievement_reward WHERE title_A <> title_H AND title_A <> 0 AND title_H <> 0', TYPE_TITLE, TYPE_ACHIEVEMENT, TYPE_TITLE, TYPE_ACHIEVEMENT); if ($sets) { DB::Aowow()->query(queryfy('[V]', $sets, $insMore), 12, 12, 12); } # 13: Source-String CLISetup::log(' * #13 cuStrings'); $src13 = [null, 42, 52, 71, 80, 157, 163, 167, 169, 177]; foreach ($src13 as $src => $tId) { if ($tId) { DB::Aowow()->query(queryfy('[V]', [[TYPE_TITLE, $tId, $src]], $insBasic), 13, 13, 13); } } return true; }
function itemset() { $locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU]; $setToHoliday = array(761 => 141, 762 => 372, 785 => 341, 812 => 181); // find events associated with holidayIds if ($pairs = DB::World()->selectCol('SELECT holiday AS ARRAY_KEY, eventEntry FROM game_event WHERE holiday IN (?a)', array_values($setToHoliday))) { foreach ($setToHoliday as &$hId) { $hId = !empty($pairs[$hId]) ? $pairs[$hId] : 0; } } // tags where refId == virtualId // in pve sets are not recycled beyond the contentGroup $tagsById = array(1 => [181, 182, 183, 184, 185, 186, 187, 188, 189], 2 => [511, 512, 513, 514, 515, 516, 517, 518, 519], 3 => [201, 202, 203, 204, 205, 206, 207, 208, 209], 4 => [210, 211, 212, 213, 214, 215, 216, 217, 218], 5 => [521, 523, 524, 525, 526, 527, 528, 529, 530], 6 => [522, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 697, 718], 7 => [281, 282, 301, 341, 342, 343, 344, 345, 346, 347, 348, 361, 362, 381, 382, 401], 8 => [383, 384, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 402, 717, 698], 9 => [494, 495, 498, 500, 502, 504, 506, 508, 510], 10 => [493, 496, 497, 499, 501, 503, 505, 507, 509], 11 => [477, 480, 474, 475, 476, 478, 479, 481, 482], 12 => [621, 624, 625, 626, 631, 632, 633, 638, 639, 640, 645, 648, 651, 654, 655, 663, 664], 13 => [622, 627, 628, 629, 634, 635, 636, 641, 642, 643, 646, 649, 652, 656, 657, 665, 666], 14 => [620, 623, 630, 637, 644, 647, 650, 653, 658, 659, 660, 661, 662], 15 => [467, 468, 469, 470, 471, 472, 473, 483, 484, 485, 486, 487, 488, 908], 16 => [587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 688, 689, 691, 692, 693, 694, 695, 696], 18 => [668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684], 21 => [738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752], 23 => [795, 805, 804, 803, 802, 801, 800, 799, 798, 797, 796, 794, 793, 792, 791, 790, 789, 788, 787], 25 => [838, 837, 836, 835, 834, 833, 832, 831, 830, 829, 828, 827, 826, 825, 824, 823, 822, 821, 820], 27 => [880, 879, 878, 877, 876, 875, 874, 873, 872, 871, 870, 869, 868, 867, 866, 865, 864, 863, 862, 861, 860, 859, 858, 857, 856, 855, 854, 853, 852, 851, 850, 849, 848, 847, 846, 845, 844, 843], 29 => [901, 900, 899, 898, 897, 896, 895, 894, 893, 892, 891, 890, 889, 888, 887, 886, 885, 884, 883]); // well .. f**k $tagsByNamePart = array(17 => ['gladiator'], 19 => ['merciless'], 20 => ['vengeful'], 22 => ['brutal'], 24 => ['deadly', 'hateful', 'savage'], 26 => ['furious'], 28 => ['relentless'], 30 => ['wrathful']); DB::Aowow()->query('TRUNCATE TABLE ?_itemset'); $vIdx = 0; $virtualId = 0; $sets = DB::Aowow()->select('SELECT *, id AS ARRAY_KEY FROM dbc_itemset'); foreach ($sets as $setId => $setData) { $spells = $items = $mods = $descText = $name = $gains = []; $max = $reqLvl = $min = $quality = $heroic = $nPieces = []; $classMask = $type = 0; $hasRing = false; $holiday = isset($setToHoliday[$setId]) ? $setToHoliday[$setId] : 0; $canReuse = !$holiday; // can't reuse holiday-sets $slotList = []; $pieces = DB::World()->select('SELECT *, IF(InventoryType = 15, 26, IF(InventoryType = 5, 20, InventoryType)) AS slot, entry AS ARRAY_KEY FROM item_template WHERE itemset = ?d AND (class <> 4 OR subclass NOT IN (1, 2, 3, 4) OR armor > 0 OR Quality = 1) ORDER BY itemLevel, subclass, slot ASC', $setId); /****************************************/ /* determine type and reuse from pieces */ /****************************************/ // make the first vId always same as setId $firstPiece = reset($pieces); $tmp = [$firstPiece['Quality'] . $firstPiece['ItemLevel'] => $setId]; // walk through all items associated with the set foreach ($pieces as $itemId => $piece) { $classMask |= $piece['AllowableClass'] & CLASS_MASK_ALL; $key = $piece['Quality'] . str_pad($piece['ItemLevel'], 3, 0, STR_PAD_LEFT); if (!isset($tmp[$key])) { $tmp[$key] = --$vIdx; } $vId = $tmp[$key]; // check only actual armor in rare quality or higher (or inherits holiday) if ($piece['class'] != ITEM_CLASS_ARMOR || $piece['subclass'] == 0) { $canReuse = false; } /* gather relevant stats for use */ if (!isset($quality[$vId]) || $piece['Quality'] > $quality[$vId]) { $quality[$vId] = $piece['Quality']; } if ($piece['Flags'] & ITEM_FLAG_HEROIC) { $heroic[$vId] = true; } if (!isset($reqLvl[$vId]) || $piece['RequiredLevel'] > $reqLvl[$vId]) { $reqLvl[$vId] = $piece['RequiredLevel']; } if (!isset($min[$vId]) || $piece['ItemLevel'] < $min[$vId]) { $min[$vId] = $piece['ItemLevel']; } if (!isset($max[$vId]) || $piece['ItemLevel'] > $max[$vId]) { $max[$vId] = $piece['ItemLevel']; } if (!isset($items[$vId][$piece['slot']]) || !$canReuse) { if (!isset($nPieces[$vId])) { $nPieces[$vId] = 1; } else { $nPieces[$vId]++; } } if (isset($items[$vId][$piece['slot']])) { // not reusable -> insert anyway on unique keys if (!$canReuse) { $items[$vId][$piece['slot'] . $itemId] = $itemId; } else { CLISetup::log("set: " . $setId . " ilvl: " . $piece['ItemLevel'] . " - conflict between item: " . $items[$vId][$piece['slot']] . " and item: " . $itemId . " choosing lower itemId", CLISetup::LOG_WARN); if ($items[$vId][$piece['slot']] > $itemId) { $items[$vId][$piece['slot']] = $itemId; } } } else { $items[$vId][$piece['slot']] = $itemId; } /* check for type */ // skip cloaks, they mess with armor classes if ($piece['slot'] == 16) { continue; } // skip event-sets if ($piece['Quality'] == 1) { continue; } if ($piece['class'] == 2 && $piece['subclass'] == 0) { $type = 8; } else { if ($piece['class'] == 2 && $piece['subclass'] == 4) { $type = 9; } else { if ($piece['class'] == 2 && $piece['subclass'] == 7) { $type = 10; } else { if ($piece['class'] == 2 && $piece['subclass'] == 13) { $type = 7; } else { if ($piece['class'] == 2 && $piece['subclass'] == 15) { $type = 5; } } } } } // Dagger if (!$type) { if ($piece['class'] == 4 && $piece['slot'] == 12) { $type = 11; } else { if ($piece['class'] == 4 && $piece['slot'] == 2) { $type = 12; } else { if ($piece['class'] == 4 && $piece['subclass'] != 0) { $type = $piece['subclass']; } } } // 'armor' set if ($piece['class'] == 4 && $piece['slot'] == 11) { $hasRing = true; } // contains ring } } if ($hasRing && !$type) { $type = 6; } // pure ring-set $isMultiSet = false; $oldSlotMask = 0x0; foreach ($items as $subset) { $curSlotMask = 0x0; foreach ($subset as $slot => $item) { $curSlotMask |= 1 << $slot; } if ($oldSlotMask && $oldSlotMask == $curSlotMask) { $isMultiSet = true; break; } $oldSlotMask = $curSlotMask; } if (!$isMultiSet || !$canReuse || $setId == 555) { $temp = []; foreach ($items as $subset) { foreach ($subset as $slot => $item) { if (isset($temp[$slot]) && $temp[$slot] < $item) { CLISetup::log("set: " . $setId . " - conflict between item: " . $item . " and item: " . $temp[$slot] . " choosing lower itemId", CLISetup::LOG_WARN); } else { if ($slot == 13 || ($slot = 11)) { // special case $temp[] = $item; } else { $temp[$slot] = $item; } } } } $items = [$temp]; $heroic = [reset($heroic)]; $nPieces = [count($temp)]; $quality = [reset($quality)]; $reqLvl = [reset($reqLvl)]; $max = $max ? [max($max)] : [0]; $min = $min ? [min($min)] : [0]; } foreach ($items as &$subsets) { $subsets = array_pad($subsets, 10, 0); } /********************/ /* calc statbonuses */ /********************/ for ($i = 1; $i < 9; $i++) { if ($setData['spellId' . $i] > 0 && $setData['itemCount' . $i] > 0) { $spells[] = [$setData['spellId' . $i], $setData['itemCount' . $i]]; } } $bonusSpells = new SpellList(array(['s.id', array_column($spells, 0)])); $mods = $bonusSpells->getStatGain(); $spells = array_pad($spells, 8, [0, 0]); for ($i = 1; $i < 9; $i++) { if ($setData['itemCount' . $i] > 0 && !empty($mods[$setData['spellId' . $i]])) { $gains[$setData['itemCount' . $i]] = $mods[$setData['spellId' . $i]]; } } /**************************/ /* get name & description */ /**************************/ foreach ($locales as $loc) { User::useLocale($loc); $name[$loc] = Util::localizedString($setData, 'name'); foreach ($bonusSpells->iterate() as $__) { if (!isset($descText[$loc])) { $descText[$loc] = ''; } $descText[$loc] .= $bonusSpells->parseText()[0] . "\n"; } // strip rating blocks - e.g. <!--rtg19-->14 <small>(<!--rtg%19-->0.30% @ L<!--lvl-->80)</small> $descText[$loc] = preg_replace('/<!--rtg\\d+-->(\\d+) .*?<\\/small>/i', '\\1', $descText[$loc]); } /****************************/ /* finalaize data and write */ /****************************/ foreach ($items as $vId => $vSet) { $note = 0; foreach ($tagsById as $tag => $sets) { if (!in_array($setId, $sets)) { continue; } $note = $tag; } if (!$note && $min > 120 && $classMask && $classMask != CLASS_MASK_ALL) { foreach ($tagsByNamePart as $tag => $strings) { foreach ($strings as $str) { if (isset($pieces[reset($vSet)]) && stripos($pieces[reset($vSet)]['name'], $str) === 0) { $note = $tag; break 2; } } } } $row = []; $row[] = $vId < 0 ? --$virtualId : $setId; $row[] = $setId; // refSetId $row[] = 0; // cuFlags $row = array_merge($row, $name, $vSet); foreach (array_column($spells, 0) as $spellId) { $row[] = $spellId; } foreach (array_column($spells, 1) as $nItems) { $row[] = $nItems; } $row = array_merge($row, $descText); $row[] = serialize($gains); $row[] = $nPieces[$vId]; $row[] = $min[$vId]; $row[] = $max[$vId]; $row[] = $reqLvl[$vId]; $row[] = $classMask == CLASS_MASK_ALL ? 0 : $classMask; $row[] = !empty($heroic[$vId]) ? 1 : 0; $row[] = $quality[$vId]; $row[] = $type; $row[] = $note; // contentGroup $row[] = $holiday; $row[] = $setData['reqSkillId']; $row[] = $setData['reqSkillLevel']; DB::Aowow()->query('REPLACE INTO ?_itemset VALUES (?a)', array_values($row)); } } // hide empty sets DB::Aowow()->query('UPDATE ?_itemset SET cuFlags = cuFlags | ?d WHERE item1 = 0', CUSTOM_EXCLUDE_FOR_LISTVIEW); return true; }
function spawns() { $alphaMapCache = []; $alphaMapCheck = function ($areaId, array &$set) use(&$alphaMapCache) { $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($alphaMapCache[$areaId])) { $alphaMapCache[$areaId] = imagecreatefrompng($file); } // alphaMaps are 1000 x 1000, adapt points [black => valid point] if (!imagecolorat($alphaMapCache[$areaId], $set['posX'] * 10, $set['posY'] * 10)) { $set = null; } return true; }; $checkCoords = function ($points) use($alphaMapCheck) { $result = []; $capitals = array(1497, 1637, 1638, 3487, 1519, 1537, 1657, 3557, 3703, 4395); foreach ($points as $res) { if ($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['quality'] < $b['quality'] ? -1 : 1; }); $result = [1.0, $points[0]]; } return $result[1]; }; $query[1] = ['SELECT c.guid, 1 AS "type", c.id AS typeId, c.spawntimesecs AS respawn, c.phaseMask, c.zoneId AS areaId, c.map, IFNULL(ca.path_id, 0) AS pathId, c.position_y AS `posX`, c.position_x AS `posY` ' . 'FROM creature c LEFT JOIN creature_addon ca ON ca.guid = c.guid', ' - assembling ' . CLISetup::bold('creature') . ' spawns']; $query[2] = ['SELECT c.guid, 2 AS "type", c.id AS typeId, ABS(c.spawntimesecs) AS respawn, c.phaseMask, c.zoneId AS areaId, c.map, 0 as pathId, c.position_y AS `posX`, c.position_x AS `posY` ' . 'FROM gameobject c', ' - assembling ' . CLISetup::bold('gameobject') . ' spawns']; $query[3] = ['SELECT c.guid, w.entry AS "npcOrPath", w.pointId AS "point", c.zoneId AS areaId, c.map, w.waittime AS "wait", w.location_y AS `posX`, w.location_x AS `posY` ' . 'FROM creature c JOIN script_waypoint w ON c.id = w.entry', ' - assembling waypoints from ' . CLISetup::bold('script_waypoint')]; $query[4] = ['SELECT c.guid, w.entry AS "npcOrPath", w.pointId AS "point", c.zoneId AS areaId, c.map, 0 AS "wait", w.position_y AS `posX`, w.position_x AS `posY` ' . 'FROM creature c JOIN waypoints w ON c.id = w.entry', ' - assembling waypoints from ' . CLISetup::bold('waypoints')]; $query[5] = ['SELECT c.guid, -w.id AS "npcOrPath", w.point, c.zoneId AS areaId, c.map, w.delay AS "wait", w.position_y AS `posX`, w.position_x AS `posY` ' . 'FROM creature c JOIN creature_addon ca ON ca.guid = c.guid JOIN waypoint_data w ON w.id = ca.path_id', ' - assembling waypoints from ' . CLISetup::bold('waypoint_data')]; $queryPost = '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`, ' . '((abs(IF(dm.Id IS NOT NULL, (?f - dm.minY) * 100 / (dm.maxY - dm.minY), (?f - wma.right) * 100 / (wma.left - wma.right)) - 50) / 50) * ' . ' (abs(IF(dm.Id IS NOT NULL, (?f - dm.minX) * 100 / (dm.maxX - dm.minX), (?f - wma.bottom) * 100 / (wma.top - wma.bottom)) - 50) / 50)) AS quality ' . 'FROM dbc_worldmaparea wma ' . 'LEFT JOIN dbc_dungeonmap dm ON dm.mapId = IF(?d AND wma.mapId NOT IN (0, 1, 530), wma.mapId, -1) ' . 'WHERE wma.mapId = ?d AND IF(?d, wma.areaId = ?d, wma.areaId <> 0) ' . 'HAVING (`posX` BETWEEN 0.1 AND 99.9 AND `posY` BETWEEN 0.1 AND 99.9) AND (dm.Id IS NULL OR ?d) ' . 'ORDER BY quality ASC'; /*********************/ /* truncate old data */ /*********************/ DB::Aowow()->query('TRUNCATE TABLE ?_spawns'); DB::Aowow()->query('TRUNCATE TABLE ?_creature_waypoints'); /**************************/ /* offsets for transports */ /**************************/ $transports = DB::World()->selectCol('SELECT Data0 AS pathId, Data6 AS ARRAY_KEY FROM gameobject_template WHERE type = 15 AND Data6 <> 0'); foreach ($transports as &$t) { $t = DB::Aowow()->selectRow('SELECT posX, posY, mapId FROM dbc_taxipathnode tpn WHERE tpn.pathId = ?d AND nodeIdx = 0', $t); } /**************/ /* perform... */ /**************/ foreach ($query as $idx => $q) { CLISetup::log($q[1]); $n = 0; $sum = 0; foreach (DB::World()->select($q[0]) as $spawn) { if (!$n) { CLISetup::log(' * sets ' . ($sum + 1) . ' - ' . ($sum += SqlGen::$stepSize)); } if ($n++ > SqlGen::$stepSize) { $n = 0; } // npc/object is on a transport -> apply offsets to path of transport // note, that the coordinates are mixed up .. again // also note, that transport DO spawn outside of displayable area maps .. another todo i guess.. if (isset($transports[$spawn['map']])) { $spawn['posX'] += $transports[$spawn['map']]['posY']; $spawn['posY'] += $transports[$spawn['map']]['posX']; $spawn['map'] = $transports[$spawn['map']]['mapId']; } $points = DB::Aowow()->select($queryPost, $spawn['posX'], $spawn['posX'], $spawn['posY'], $spawn['posY'], $spawn['posX'], $spawn['posX'], $spawn['posY'], $spawn['posY'], 1, $spawn['map'], $spawn['areaId'], $spawn['areaId'], $spawn['areaId'] ? 1 : 0); if (!$points) { // retry: TC counts pre-instance subareas as instance-maps .. which have no map file $points = DB::Aowow()->select($queryPost, $spawn['posX'], $spawn['posX'], $spawn['posY'], $spawn['posY'], $spawn['posX'], $spawn['posX'], $spawn['posY'], $spawn['posY'], 0, $spawn['map'], 0, 0, 1); } if (!$points) { CLISetup::log('GUID ' . $spawn['guid'] . ($idx < 3 ? '' : ' on path/point ' . $spawn['npcOrPath'] . '/' . $spawn['point']) . ' could not be matched to displayable area [A:' . $spawn['areaId'] . '; X:' . $spawn['posY'] . '; Y:' . $spawn['posX'] . ']', CLISetup::LOG_WARN); continue; } // if areaId is set, area was determined by TC .. we're fine .. mostly $final = $spawn['areaId'] ? $points[0] : $checkCoords($points); if ($idx < 3) { $set = array('guid' => $spawn['guid'], 'type' => $spawn['type'], 'typeId' => $spawn['typeId'], 'respawn' => $spawn['respawn'], 'phaseMask' => $spawn['phaseMask'], 'pathId' => $spawn['pathId'], 'areaId' => $final['areaId'], 'floor' => $final['floor'], 'posX' => $final['posX'], 'posY' => $final['posY']); DB::Aowow()->query('REPLACE INTO ?_spawns (?#) VALUES (?a)', array_keys($set), array_values($set)); } else { $set = array('creatureOrPath' => $spawn['npcOrPath'], 'point' => $spawn['point'], 'wait' => $spawn['wait'], 'areaId' => $final['areaId'], 'floor' => $final['floor'], 'posX' => $final['posX'], 'posY' => $final['posY']); DB::Aowow()->query('REPLACE INTO ?_creature_waypoints (?#) VALUES (?a)', array_keys($set), array_values($set)); } } } /*****************************/ /* spawn vehicle accessories */ /*****************************/ // get vehicle template accessories $accessories = DB::World()->select(' SELECT vta.accessory_entry AS typeId, c.guid, vta.entry, count(1) AS nSeats FROM vehicle_template_accessory vta LEFT JOIN creature c ON c.id = vta.entry GROUP BY accessory_entry, c.guid UNION SELECT va.accessory_entry AS typeId, va.guid, 0 AS entry, count(1) AS nSeats FROM vehicle_accessory va GROUP BY accessory_entry, va.guid'); // accessories may also be vehicles (e.g. "Kor'kron Infiltrator" is seated on "Kor'kron Suppression Turret" is seated on "Kor'kron Troop Transport") // so we will retry finding a spawned vehicle if none were found on the previous pass and a change occured $vGuid = 0; // not really used, but we need some kind of index $n = 0; $matches = -1; while ($matches) { $matches = 0; foreach ($accessories as $idx => $data) { $vehicles = []; if ($data['guid']) { // vehicle already spawned $vehicles = DB::Aowow()->select('SELECT s.areaId, s.posX, s.posY, s.floor FROM ?_spawns s WHERE s.guid = ?d AND s.type = ?d', $data['guid'], TYPE_NPC); } else { if ($data['entry']) { // vehicle on unspawned vehicle action $vehicles = DB::Aowow()->select('SELECT s.areaId, s.posX, s.posY, s.floor FROM ?_spawns s WHERE s.typeId = ?d AND s.type = ?d', $data['entry'], TYPE_NPC); } } if ($vehicles) { $matches++; foreach ($vehicles as $v) { // if there is more than one vehicle, its probably due to overlapping zones for ($i = 0; $i < $data['nSeats']; $i++) { DB::Aowow()->query(' REPLACE INTO ?_spawns (`guid`, `type`, `typeId`, `respawn`, `spawnMask`, `phaseMask`, `areaId`, `floor`, `posX`, `posY`, `pathId`) VALUES (?d, ?d, ?d, 0, 0, 1, ?d, ?d, ?d, ?d, 0)', --$vGuid, TYPE_NPC, $data['typeId'], $v['areaId'], $v['floor'], $v['posX'], $v['posY']); } } unset($accessories[$idx]); } } if ($matches) { CLISetup::log(' * assigned ' . $matches . ' accessories on ' . ++$n . '. pass on vehicle accessories'); } } if ($accessories) { CLISetup::log(count($accessories) . ' accessories could not be fitted onto a spawned vehicle.', CLISetup::LOG_WARN); } /********************************/ /* restrict difficulty displays */ /********************************/ DB::Aowow()->query('UPDATE ?_spawns s, dbc_worldmaparea wma, dbc_map m SET s.spawnMask = 0 WHERE s.areaId = wma.areaId AND wma.mapId = m.Id AND m.areaType IN (0, 3, 4)'); return true; }
function siteconfig() { if (!DB::isConnected(DB_AOWOW)) { CLISetup::log(); CLISetup::log("database not yet set up!\n Please use --dbconfig for setup", CLISetup::LOG_WARN); return; } while (true) { CLISetup::log(); CLISetup::log('select a numerical index to use the corresponding entry'); $results = DB::Aowow()->select('SELECT *, (flags & ?d) AS php FROM ?_config ORDER BY php ASC', CON_FLAG_PHP); $hasEmpty = false; foreach ($results as $idx => $data) { if (!($data['flags'] & CON_FLAG_PHP) && $data['value'] === '') { $hasEmpty = true; } $php = $data['flags'] & CON_FLAG_PHP; $buff = "[" . CLISetup::bold($idx) . "] " . ($idx > 9 ? '' : ' ') . ($php ? ' PHP ' : ' AOWOW '); $buff .= str_pad($php ? strtolower($data['key']) : strtoupper('cfg_' . $data['key']), 35); if ($data['value'] === '') { $buff .= CLISetup::red('<empty>'); } else { $info = explode(' - ', $data['comment']); if ($data['flags'] & CON_FLAG_TYPE_BOOL) { $buff .= '[bool] ' . ($data['value'] ? '<Enabled>' : '<Disabled>'); } else { if ($data['flags'] & CON_FLAG_OPT_LIST && !empty($info[2])) { $buff .= "[opt] "; foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $buff .= '[' . ($data['value'] == $opt[0] ? 'x' : ' ') . ']' . $opt[1] . ' '; } } else { if ($data['flags'] & CON_FLAG_BITMASK && !empty($info[2])) { $buff .= "[mask] "; foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $buff .= '[' . ($data['value'] & 1 << $opt[0] ? 'x' : ' ') . ']' . $opt[1] . ' '; } } else { if ($data['flags'] & CON_FLAG_TYPE_STRING) { $buff .= "[str] " . $data['value']; } else { if ($data['flags'] & CON_FLAG_TYPE_FLOAT) { $buff .= "[float] " . floatVal($data['value']); } else { /* if ($data['flags'] & CON_FLAG_TYPE_INT) */ $buff .= "[int] " . intVal($data['value']); } } } } } } CLISetup::log($buff); } CLISetup::log(str_pad("[" . CLISetup::bold(count($results)) . "]", 21) . "add another php configuration"); if ($hasEmpty) { CLISetup::log(); CLISetup::log("please configure the required empty setings", CLISetup::LOG_WARN); } $inp = ['idx' => ['', false, '/\\d/']]; if (CLISetup::readInput($inp) && $inp && $inp['idx'] !== '') { // add new php setting if ($inp['idx'] == count($results)) { CLISetup::log(); CLISetup::log("Adding additional php configuration."); while (true) { $setting = array('key' => ['option name', false, '/[\\w_\\.\\-]/i'], 'val' => ['value']); if (CLISetup::readInput($setting) && $setting) { CLISetup::log(); $key = strtolower($setting['key']); if (ini_get($key) === false || ini_set($key, $setting['val']) === false) { CLISetup::log("this configuration option cannot be set", CLISetup::LOG_ERROR); sleep(1); } else { if (DB::Aowow()->selectCell('SELECT 1 FROM ?_config WHERE `flags` & ?d AND `key` = ?', CON_FLAG_PHP, $key)) { CLISetup::log("this configuration option is already in use", CLISetup::LOG_ERROR); sleep(1); } else { DB::Aowow()->query('INSERT IGNORE INTO ?_config (`key`, `value`, `flags`) VALUES (?, ?, ?d)', $key, $setting['val'], CON_FLAG_TYPE_STRING | CON_FLAG_PHP); CLISetup::log("new php configuration added", CLISetup::LOG_OK); sleep(1); } } break; } else { CLISetup::log(); CLISetup::log("edit canceled! returning to list...", CLISetup::LOG_WARN); sleep(1); break; } } } else { if ($inp['idx'] >= 0 && $inp['idx'] < count($results)) { $conf = $results[$inp['idx']]; $info = explode(' - ', $conf['comment']); $buff = ''; CLISetup::log(); $buff .= $conf['flags'] & CON_FLAG_PHP ? " PHP: " : "AOWOW: "; $buff .= $conf['flags'] & CON_FLAG_PHP ? strtolower($conf['key']) : strtoupper('cfg_' . $conf['key']); if (!empty($info[1])) { $buff .= " - " . $info[1]; } CLISetup::log($buff); $buff = "VALUE: "; if ($conf['flags'] & CON_FLAG_TYPE_BOOL) { $buff .= $conf['value'] ? '<Enabled>' : '<Disabled>'; } else { if ($conf['flags'] & CON_FLAG_OPT_LIST && !empty($info[2])) { foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $buff .= '[' . ($conf['value'] == $opt[0] ? 'x' : ' ') . '] ' . $opt[1] . ' '; } } else { if ($conf['flags'] & CON_FLAG_BITMASK && !empty($info[2])) { foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $buff .= '[' . ($conf['value'] & 1 << $opt[0] ? 'x' : ' ') . '] ' . $opt[1] . ' '; } } else { if ($conf['flags'] & CON_FLAG_TYPE_STRING) { $buff .= $conf['value']; } else { if ($conf['flags'] & CON_FLAG_TYPE_FLOAT) { $buff .= floatVal($conf['value']); } else { /* if ($conf['flags'] & CON_FLAG_TYPE_INT) */ $buff .= intVal($conf['value']); } } } } } CLISetup::log($buff); CLISetup::log(); CLISetup::log("[" . CLISetup::bold('E') . "]dit"); if (!($conf['flags'] & CON_FLAG_PERSISTENT)) { CLISetup::log("[" . CLISetup::bold('D') . "]elete"); } if (strstr($info[0], 'default:')) { CLISetup::log("[" . CLISetup::bold('R') . "]estore Default - " . trim(explode('default:', $info[0])[1])); } while (true) { $action = ['idx' => ['', true, '/[edr]/i']]; if (CLISetup::readInput($action, true) && $action) { switch (strtoupper($action['idx'])) { case 'E': // edit value $pattern = false; $single = false; $value = ['idx' => ['Select new value', false, &$pattern]]; if ($conf['flags'] & CON_FLAG_OPT_LIST) { $_valid = []; foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $_valid[] = $opt[0]; CLISetup::log('[' . CLISetup::bold($opt[0]) . '] ' . $opt[1]); } $single = true; $pattern = '/\\d/'; $validate = function ($v) use($_valid) { return in_array($v, $_valid); }; } else { if ($conf['flags'] & CON_FLAG_BITMASK) { CLISetup::log('Bitmask: sum fields to select multiple options'); $_valid = 0x0; foreach (explode(', ', $info[2]) as $option) { $opt = explode(':', $option); $_valid |= 1 << $opt[0]; CLISetup::log('[' . CLISetup::bold(1 << $opt[0]) . ']' . str_pad('', 4 - strlen(1 << $opt[0])) . $opt[1]); } $pattern = '/\\d+/'; $validate = function ($v) use($_valid) { $v = $v & $_valid; return $v; }; } else { if ($conf['flags'] & CON_FLAG_TYPE_BOOL) { CLISetup::log('[' . CLISetup::bold(0) . '] Disabled'); CLISetup::log('[' . CLISetup::bold(1) . '] Enabled'); $single = true; $pattern = '/[01]/'; $validate = function ($v) { return true; }; } else { if ($conf['flags'] & CON_FLAG_TYPE_INT) { $validate = function ($v) { return preg_match('/^-?\\d+$/i', $v); }; } else { if ($conf['flags'] & CON_FLAG_TYPE_FLOAT) { $validate = function ($v) { return preg_match('/^-?\\d*(,|.)?\\d+$/i', $v); }; } else { // string $validate = function ($v) { return true; }; } } } } } while (true) { $use = $value; if (CLISetup::readInput($use, $single) && $use) { CLISetup::log(); if (!$validate($use['idx'])) { CLISetup::log("value not in range", CLISetup::LOG_ERROR); sleep(1); continue; } else { DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', $use['idx'], strtolower($conf['key'])); CLISetup::log("setting updated", CLISetup::LOG_OK); sleep(1); break 3; } } else { CLISetup::log("edit canceled! returning to selection...", CLISetup::LOG_WARN); sleep(1); break; } } break 2; case 'R': // restore default if (!strstr($info[0], 'default:')) { continue 2; } // @eval .. some dafault values are supplied as bitmask or the likes if (DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', @eval('return (' . trim(explode('default:', $info[0])[1]) . ');'), strtolower($conf['key']))) { CLISetup::log("default value restored", CLISetup::LOG_OK); sleep(1); } break 2; case 'D': // delete config pair if ($conf['flags'] & CON_FLAG_PERSISTENT) { continue 2; } if (DB::Aowow()->query('DELETE FROM ?_config WHERE `key` = ? AND (`flags` & ?d) = 0', strtolower($conf['key']), CON_FLAG_PERSISTENT)) { CLISetup::log("php setting deleted ['" . $conf['key'] . "': '" . $conf['value'] . "']", CLISetup::LOG_OK); sleep(1); } break 2; } } else { CLISetup::log(); CLISetup::log("edit canceled! returning to list...", CLISetup::LOG_WARN); sleep(1); break; } } } else { CLISetup::log(); CLISetup::log("invalid selection", CLISetup::LOG_ERROR); sleep(1); } } } else { CLISetup::log(); CLISetup::log("site configuration aborted", CLISetup::LOG_WARN); break; } } }